def play(self) -> int: board = Board() last_x = None last_y = None while board.round <= MAX_ROUND: current_color = board.next_color (x, y) = self.players[current_color].play(last_x, last_y) if x == -1 and y == -1: self.viewer.player_undoes() board.undo() (last_x, last_y) = (-1, -1) else: if 0 > x > 4 or 0 > y > 4: raise RuleViolation("out of bounds move") if board.field(x, y, 4) != EMPTY: raise RuleViolation("already full at {},{}".format(x, y)) is_winning = board.move(x, y) LOG.debug("player {} plays to {},{}".format( current_color, x, y)) self.viewer.player_plays(x, y) if is_winning: LOG.debug("player {} wins!".format(current_color)) self.viewer.finish(board.winning_coords()) return current_color (last_x, last_y) = (x, y) LOG.debug("game ended in a draw") self.viewer.finish([]) return EMPTY
class BasePlayer(Player): """ Abstract player backed by a simple board """ def __init__(self, viewer): self.viewer = viewer self.board = Board() self.play_both_sides = False def play(self, other_x, other_y) -> tuple: assert self.board.round < 5 * 5 * 5 if not self.play_both_sides: if other_x is not None and other_y is not None: if other_x == -1 and other_y == -1: self.board.undo() else: self.board.move(other_x, other_y) (x, y) = self.do_play() if x == -1 and y == -1: self.board.undo() else: self.board.move(x, y) return x, y def do_select(self, x, y): self.viewer.player_selects(x, y) def do_play(self) -> tuple: raise NotImplementedError def close(self): pass
class BoardViewer: def __init__(self): self.board = Board() def player_plays(self, x, y): self.board.move(x, y) def player_selects(self, x, y): pass def player_undoes(self): self.board.undo() def finish(self, winning_coords): pass def close(self): pass