+ 3.x tictactoe (done)
This commit is contained in:
parent
5906af0f69
commit
5145c20156
@ -83,6 +83,11 @@ P.S.S. Домашнее задание: завершите создание эт
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
class GameOverException(Exception):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
class Cell:
|
class Cell:
|
||||||
@ -90,8 +95,8 @@ class Cell:
|
|||||||
|
|
||||||
class State(Enum):
|
class State(Enum):
|
||||||
FREE = 0
|
FREE = 0
|
||||||
HUMAN = 1
|
COMPUTER = 1
|
||||||
COMPUTER = 2
|
HUMAN = 2
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def wrap(cls, v):
|
def wrap(cls, v):
|
||||||
@ -124,10 +129,10 @@ class Cell:
|
|||||||
return self.is_free
|
return self.is_free
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}{(self.value)!r}"
|
return f"{self.__class__.__name__}({self.value!r})"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.CHARS[not self and self.value]
|
return self.CHARS[self.value]
|
||||||
|
|
||||||
|
|
||||||
class TicTacToe:
|
class TicTacToe:
|
||||||
@ -145,10 +150,13 @@ class TicTacToe:
|
|||||||
def is_ended(self):
|
def is_ended(self):
|
||||||
return self is not self.ACTIVE
|
return self is not self.ACTIVE
|
||||||
|
|
||||||
def __init__(self, pole=None):
|
def __init__(self, size=3, pole=None):
|
||||||
|
self.size = size
|
||||||
self.state = self.State.ACTIVE
|
self.state = self.State.ACTIVE
|
||||||
if pole is None:
|
if pole is None:
|
||||||
pole = tuple(tuple(Cell() for _ in range(3)) for _ in range(3))
|
pole = tuple(
|
||||||
|
tuple(Cell() for _ in range(self.size)) for _ in range(self.size)
|
||||||
|
)
|
||||||
self.pole = pole
|
self.pole = pole
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
@ -167,18 +175,18 @@ class TicTacToe:
|
|||||||
for col in zip(*self.pole):
|
for col in zip(*self.pole):
|
||||||
if all(cell.value == value for cell in col):
|
if all(cell.value == value for cell in col):
|
||||||
return True
|
return True
|
||||||
if all(self[i, i] == value for i in range(len(self.pole))):
|
if all(self[i, i] == value for i in range(self.size)):
|
||||||
return True
|
return True
|
||||||
if all(self[i, len(self.pole) - i + 1] == value for i in range(len(self.pole))):
|
if all(self[i, self.size + ~i] == value for i in range(self.size)):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _update_state(self):
|
def _update_state(self):
|
||||||
if not any(cell.is_free for row in self.pole for cell in row):
|
if self._find_line(Cell.State.HUMAN.value):
|
||||||
self.state = self.State.DRAW
|
|
||||||
elif self._find_line(Cell.State.HUMAN.value):
|
|
||||||
self.state = self.State.HUMAN_WIN
|
self.state = self.State.HUMAN_WIN
|
||||||
elif self._find_line(Cell.State.COMPUTER.value):
|
elif self._find_line(Cell.State.COMPUTER.value):
|
||||||
self.state = self.State.COMPUTER_WIN
|
self.state = self.State.COMPUTER_WIN
|
||||||
|
elif not any(cell.is_free for row in self.pole for cell in row):
|
||||||
|
self.state = self.State.DRAW
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_human_win(self):
|
def is_human_win(self):
|
||||||
@ -193,54 +201,93 @@ class TicTacToe:
|
|||||||
return self.state is self.State.DRAW
|
return self.state is self.State.DRAW
|
||||||
|
|
||||||
def _get_key(self, key):
|
def _get_key(self, key):
|
||||||
if not isinstance(key, tuple) or len(key) != 2:
|
if (
|
||||||
|
not isinstance(key, tuple)
|
||||||
|
or len(key) != 2
|
||||||
|
or any(not isinstance(x, int) or x < 0 or x >= len(self.pole) for x in key)
|
||||||
|
):
|
||||||
raise IndexError("неверный индекс клетки")
|
raise IndexError("неверный индекс клетки")
|
||||||
return tuple(x if isinstance(x, int) else None for x in key)
|
return key
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
key = self._get_key(key)
|
row, col = self._get_key(key)
|
||||||
row, col = key
|
return self.pole[row][col].value
|
||||||
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):
|
def __setitem__(self, key, value):
|
||||||
key = self._get_key(key)
|
if not self:
|
||||||
row, col = key
|
raise GameOverException("игра закончена")
|
||||||
if row is None and col is None:
|
|
||||||
for i, row in enumerate(value):
|
row, col = self._get_key(key)
|
||||||
for j, v in enumerate(row):
|
cell = self.pole[row][col]
|
||||||
self[i, j] = v
|
if not cell.is_free:
|
||||||
return
|
raise ValueError("клетка уже занята")
|
||||||
if row is not None and col is not None:
|
|
||||||
cell = self.pole[row][col]
|
cell.value = value
|
||||||
if not cell.is_free:
|
|
||||||
raise ValueError("клетка уже занята")
|
|
||||||
cell.value = value
|
|
||||||
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
|
|
||||||
self._update_state()
|
self._update_state()
|
||||||
|
|
||||||
def human_go(self):
|
def human_go(self):
|
||||||
...
|
pending = True
|
||||||
|
prompt = f"Введите координаты клетки через пробел (0-{self.size - 1}, сначала строка)\nДля выхода введите Q\nВаш ход: "
|
||||||
|
while pending:
|
||||||
|
answer = input(prompt)
|
||||||
|
if answer.lower() == "q":
|
||||||
|
print("Вы сдались!")
|
||||||
|
self.state = self.State.COMPUTER_WIN
|
||||||
|
pending = False
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
row, col = map(int, answer.split())
|
||||||
|
except ValueError:
|
||||||
|
print("Неверный формат ввода")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
self[row, col] = Cell.State.HUMAN
|
||||||
|
pending = False
|
||||||
|
except IndexError:
|
||||||
|
print("Неверные координаты клетки")
|
||||||
|
except ValueError:
|
||||||
|
print("Клетка уже занята")
|
||||||
|
except GameOverException:
|
||||||
|
print("Эй, что происходит?!")
|
||||||
|
pending = False
|
||||||
|
|
||||||
def computer_go(self):
|
def computer_go(self):
|
||||||
...
|
free_cells = [
|
||||||
|
(i, j) for i in range(self.size) for j in range(self.size) if not self[i, j]
|
||||||
|
]
|
||||||
|
row, col = random.choice(free_cells)
|
||||||
|
print("Я выбрал клетку", row, col, end="!\n")
|
||||||
|
self[row, col] = Cell.State.COMPUTER
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
print(self)
|
print(self)
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
human_turn = True
|
||||||
|
turns = self.computer_go, self.human_go
|
||||||
|
while self:
|
||||||
|
if human_turn:
|
||||||
|
self.show()
|
||||||
|
turns[human_turn]()
|
||||||
|
human_turn = not human_turn
|
||||||
|
|
||||||
|
print("Игра окончена!")
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
if self.is_human_win:
|
||||||
|
print("Вы выиграли!")
|
||||||
|
elif self.is_computer_win:
|
||||||
|
print("Ура! Я выиграл!")
|
||||||
|
elif self.is_draw:
|
||||||
|
print("Ничья!")
|
||||||
|
else:
|
||||||
|
print("Что-то пошло не так...")
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return self.size
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
c = 2
|
c = self.size - 1
|
||||||
result = (
|
result = (
|
||||||
f"╭─{'─┬─' * c}─╮\n"
|
f"╭─{'─┬─' * c}─╮\n"
|
||||||
+ f"├─{'─┼─' * c}─┤\n".join(
|
+ f"├─{'─┼─' * c}─┤\n".join(
|
||||||
@ -251,17 +298,22 @@ class TicTacToe:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"{self.__class__.__name__}({self.pole!r})"
|
args = []
|
||||||
|
if self.size != 3:
|
||||||
|
args.append(f"size={self.size!r}")
|
||||||
|
if sum(self[i, j] for i in range(self.size) for j in range(self.size)):
|
||||||
|
args.append(f"pole={self.pole!r}")
|
||||||
|
args = ", ".join(args)
|
||||||
|
return f"{self.__class__.__name__}({args})"
|
||||||
|
|
||||||
|
|
||||||
t = TicTacToe()
|
import sys
|
||||||
t[1, 1] = 2
|
|
||||||
t[0, 1] = 1
|
argc = len(sys.argv)
|
||||||
t[0, 0] = 2
|
if argc > 1 and sys.argv[1] == "play":
|
||||||
t[2, 1] = 1
|
game = TicTacToe(argc > 2 and int(sys.argv[2]) or 3)
|
||||||
t[2, 2] = 2
|
game.play()
|
||||||
t.show()
|
exit()
|
||||||
print(t.is_computer_win, t.is_human_win, t.is_draw)
|
|
||||||
|
|
||||||
|
|
||||||
def tests():
|
def tests():
|
||||||
|
Loading…
Reference in New Issue
Block a user