""" https://stepik.org/lesson/701993/step/10?unit=702094 Вам нужно реализовать в программе игровое поле для игры "Крестики-нолики". Для этого требуется объявить класс TicTacToe (крестики-нолики), объекты которого создаются командой: game = TicTacToe() Каждый объект game должен иметь публичный атрибут: pole - игровое поле: кортеж размером 3х3 с объектами класса Cell. Каждая клетка игрового поля представляется объектом класса Cell и создается командой: cell = Cell() Объекты класса Cell должны иметь следующие публичные локальные атрибуты: is_free - True, если клетка свободна; False в противном случае; value - значение поля: 1 - крестик; 2 - нолик (по умолчанию 0). Также с каждым объектом класса Cell должна работать функция: bool(cell) которая возвращает True, если клетка свободна (cell.is_free=True) и False в противном случае. Класс TicTacToe должен иметь следующий метод: clear() - очистка игрового поля (все клетки заполняются нулями и переводятся в закрытое состояние); А объекты этого класса должны иметь следующую функциональность (обращение по индексам): game[0, 0] = 1 # установка нового значения, если поле закрыто res = game[1, 1] # получение значения центральной ячейки поля (возвращается число) Если указываются некорректные индексы, то должно генерироваться исключение командой: raise IndexError('неверный индекс клетки') Если идет попытка присвоить новое значение в открытую клетку поля, то генерировать исключение: raise ValueError('клетка уже занята') Также должны быть реализованы следующие полные срезы при обращении к клеткам игрового поля: slice_1 = game[:, indx] # выбираются все элементы (кортеж) столбца с индексом indx slice_2 = game[indx, :] # выбираются все элементы (кортеж) строки с индексом indx Пример использования классов (эти строчки в программе не писать): game = TicTacToe() game.clear() game[0, 0] = 1 game[1, 0] = 2 # формируется поле: # 1 0 0 # 2 0 0 # 0 0 0 game[3, 2] = 2 # генерируется исключение IndexError if game[0, 0] == 0: game[0, 0] = 2 v1 = game[0, :] # 1, 0, 0 v2 = game[:, 0] # 1, 2, 0 P.S. В программе нужно объявить только классы. Выводить на экран ничего не нужно. P.P.S. При передаче среза в магических методах __setitem__() и __getitem__() параметр индекса становится объектом класса slice. Его можно указывать непосредственно в квадратных скобках упорядоченных коллекций (списков, кортежей и т.п.). """ class Cell: CHARS = " OX" def __init__(self, value=0, is_free=True): self.value, self.is_free = value, is_free def __bool__(self): return self.is_free def __repr__(self): return f"{self.__class__.__name__}{(self.value, self.is_free)!r}" def __str__(self): return self.CHARS[not self and self.value] class TicTacToe: def __init__(self, pole=None): if pole is None: pole = tuple(tuple(Cell() for _ in range(3)) for _ in range(3)) self.pole = pole def clear(self): for row in self.pole: for cell in row: cell.is_free = True cell.value = 0 def _get_key(self, key): if not isinstance(key, tuple) or len(key) != 2: raise IndexError("неверный индекс клетки") return tuple(x if isinstance(x, int) else None for x in key) def __getitem__(self, key): key = self._get_key(key) row, col = key if row is None and col is None: return tuple(tuple(c.value for c in r) for r in self.pole) if row is not None and col is not None: return self.pole[row][col].value if row is not None and col is None: return tuple(x.value for x in self.pole[row]) return tuple(self.pole[row][col].value for row in range(len(self.pole))) def __setitem__(self, key, value): key = self._get_key(key) row, col = key if row is None and col is None: for i, row in enumerate(value): for j, v in enumerate(row): self[i, j] = v return if row is not None and col is not None: cell = self.pole[row][col] if not cell.is_free: raise ValueError("клетка уже занята") cell.value = value cell.is_free = False return if row is not None and col is None: for j, v in enumerate(value): self[row, j] = v return for i, v in enumerate(value): self[i, col] = v def __repr__(self): return f"{self.__class__.__name__}({self.pole!r})" def __str__(self): return "\n".join(map(lambda r: " ".join(map(str, r)), self.pole)) def tests(): code = ( b"XCOTwRB2;WVPjNpWhf~MXD(xGWnpqCDGFh8b7gXLAZJ@JEFdslAU!=GFd$)WWFTi-GAtl6T_8O" + b"@ATTT-BGA3iu+fLmu+Y2FjL^N&i_o5TQV#lFhHAR^Gc(6!LA(6!Nk(7n*UAkeove2;5xX`lDu+Y8GxY3Uw(7n" + b"*U(6Z5s(S;z;x6r-Nu+fLmwa~rLxX`&E(7MpO(6!Nm(7MpD(7YhfxX`oFfY83sve3TJv(UaE(7({" + b"W(7Vx(ASlqd(7VvMEFjRm(6!LI(7w@t(SXpk(7Mrr(7n*UAkl!(u+Xv4zR`lvu+X*9f*{d>(TC8u" + b"(Sp&7(6Z35(7n*O(6u1Yx6r-Nu+fLmwa~rLxX`&NA_@w0a(OxmARr(ha%FQMJs@XWGb|u5T?%D*V" + b"`Xr3AW3dyWq3t$a&K}v3LqdLAYpTJWpZ>NRC0A?3T13_WjYEVARr)Nb8}^KbRb4yY;$ESAR^Gc(6" + b"u1ZfzY$iwa~rLwb6jkxY2;nzRWpH#LNp56ictvt@" + b"Z*n>cARr(hVRLh3a&#b6a&=`2Wo&b0Itm~lARu9Lb7gXLAVy(qb7d?bBGA3iwII=f(6i9B(7n*L(" + b"SXpn(SXpt(6Z35(7VvS(Sgy7AketcfzZ0pyU~u(htRdqz0kPOwIE4uWMz0oa&m8SAke?jfY7)g(6" + b"`XA(7({Q(SgvoAkeZP(7n*L(Sgx}(TUKt(Sgx|(6Z5k(T>rH(Sy;BAkmM}htRdqxzM`NgCYtF3TG" + b"~3Y-M3`C@BhOTQDpjFkK)$ATbJOTQMvkFkK)$ATkPPTQV#lFkK)$ATtUIVRLh3a&#bPTQDpjI$a<" + b"=Js>DCEFdr}ATTK)VQyp~XIn8WAUa(jJv|^OGAtl4EFdr`AYpD~AZJ@TEFdslAU!=GC^0M`GAtl7" + b"DJ&o&(7n*L(7MpR(SXr_(6!LI(Sp#u(7qthzR`lwfY7kevCzKJg3z$gyU@5G(Sgx`(6!LF(TgC^z" + b"tFzXfzZ3qwII;4(TmWx(7w>J(6AuTywJ7Lg3!Luw9v31V{Bz%awsVv(6}JbztMouxY2>ove2;5xX" + b"`lDu+Y8GxY3Uw(7n*U(6Z5s(S;z;x6r-Nu+fLmwa~rLxX`&G3JPOoY-}JsAVXzrY$z!TVRLh3a&#" + b"bLWo&FNc42IFWgtC0ATTT-BGA3iu+fLmu+Y2FjL^N%zRS(6-RM(7qthvC)gsg3*j1(SXpf" + b"(6Z3I(7qrrA_{V4b09q+V`Xe?E@^XLW^!d^3S(t#Y%XbYUuJS;WgtBuRC0A?3So0|WpZ>NVsCG3C" + b"}U-8Y$+@tBGH7=gV4Ruy3vNvxY3UwVsCG3AkebVwb6jkz0rfvyU?&8MqzAoWgyVB(7Vx(Akl%)ve" + b"3TJvCzKIw9viKzR