+ 3.x tictactoe (done)
This commit is contained in:
parent
5906af0f69
commit
5145c20156
@ -83,6 +83,11 @@ P.S.S. Домашнее задание: завершите создание эт
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
import random
|
||||
|
||||
|
||||
class GameOverException(Exception):
|
||||
...
|
||||
|
||||
|
||||
class Cell:
|
||||
@ -90,8 +95,8 @@ class Cell:
|
||||
|
||||
class State(Enum):
|
||||
FREE = 0
|
||||
HUMAN = 1
|
||||
COMPUTER = 2
|
||||
COMPUTER = 1
|
||||
HUMAN = 2
|
||||
|
||||
@classmethod
|
||||
def wrap(cls, v):
|
||||
@ -124,10 +129,10 @@ class Cell:
|
||||
return self.is_free
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}{(self.value)!r}"
|
||||
return f"{self.__class__.__name__}({self.value!r})"
|
||||
|
||||
def __str__(self):
|
||||
return self.CHARS[not self and self.value]
|
||||
return self.CHARS[self.value]
|
||||
|
||||
|
||||
class TicTacToe:
|
||||
@ -145,10 +150,13 @@ class TicTacToe:
|
||||
def is_ended(self):
|
||||
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
|
||||
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
|
||||
|
||||
def init(self):
|
||||
@ -167,18 +175,18 @@ class TicTacToe:
|
||||
for col in zip(*self.pole):
|
||||
if all(cell.value == value for cell in col):
|
||||
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
|
||||
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
|
||||
|
||||
def _update_state(self):
|
||||
if not any(cell.is_free for row in self.pole for cell in row):
|
||||
self.state = self.State.DRAW
|
||||
elif self._find_line(Cell.State.HUMAN.value):
|
||||
if self._find_line(Cell.State.HUMAN.value):
|
||||
self.state = self.State.HUMAN_WIN
|
||||
elif self._find_line(Cell.State.COMPUTER.value):
|
||||
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
|
||||
def is_human_win(self):
|
||||
@ -193,54 +201,93 @@ class TicTacToe:
|
||||
return self.state is self.State.DRAW
|
||||
|
||||
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("неверный индекс клетки")
|
||||
return tuple(x if isinstance(x, int) else None for x in key)
|
||||
return 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:
|
||||
row, col = self._get_key(key)
|
||||
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:
|
||||
if not self:
|
||||
raise GameOverException("игра закончена")
|
||||
|
||||
row, col = self._get_key(key)
|
||||
cell = self.pole[row][col]
|
||||
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()
|
||||
|
||||
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):
|
||||
...
|
||||
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):
|
||||
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):
|
||||
c = 2
|
||||
c = self.size - 1
|
||||
result = (
|
||||
f"╭─{'─┬─' * c}─╮\n"
|
||||
+ f"├─{'─┼─' * c}─┤\n".join(
|
||||
@ -251,17 +298,22 @@ class TicTacToe:
|
||||
return result
|
||||
|
||||
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()
|
||||
t[1, 1] = 2
|
||||
t[0, 1] = 1
|
||||
t[0, 0] = 2
|
||||
t[2, 1] = 1
|
||||
t[2, 2] = 2
|
||||
t.show()
|
||||
print(t.is_computer_win, t.is_human_win, t.is_draw)
|
||||
import sys
|
||||
|
||||
argc = len(sys.argv)
|
||||
if argc > 1 and sys.argv[1] == "play":
|
||||
game = TicTacToe(argc > 2 and int(sys.argv[2]) or 3)
|
||||
game.play()
|
||||
exit()
|
||||
|
||||
|
||||
def tests():
|
||||
|
Loading…
Reference in New Issue
Block a user