diff --git a/mod_oop/3.8_10_tictactoe.py b/mod_oop/3.8_10_tictactoe.py new file mode 100644 index 0000000..e761815 --- /dev/null +++ b/mod_oop/3.8_10_tictactoe.py @@ -0,0 +1,169 @@ +""" + 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