Tic-tac-toe for AI

MARKS = {0: 'X', 1: 'O'} def update_cells(state): for i, value in enumerate(state): Element(f"pos-{i}-x").add_class("hidden") Element(f"pos-{i}-o").add_class("hidden") if value == 0: Element(f"pos-{i}-x").remove_class("hidden") elif value == 1: Element(f"pos-{i}-o").remove_class("hidden") def display_message(value): Element("message").write(value) class Board: def __init__(self): self.state = [None] * 9 self.counter = 0 def render(self): text = """ 0|1|2 ----- 3|4|5 ----- 6|7|8 """ for idx, x in enumerate(self.state): if x is not None: text = text.replace(str(idx), MARKS[x]) # 4 -> X print(text) def move(self, idx): if self.state[idx] is not None: return False player = self.counter % 2 self.state[idx] = player self.counter += 1 return True def unmove(self, idx): self.counter -= 1 self.state[idx] = None def is_win(self, player): s = self.state if( s[0] == s[1] == s[2] == player or s[3] == s[4] == s[5] == player or s[6] == s[7] == s[8] == player or s[0] == s[3] == s[6] == player or s[1] == s[4] == s[7] == player or s[2] == s[5] == s[8] == player or s[0] == s[4] == s[8] == player or s[2] == s[4] == s[6] == player ): return True return False def is_end(self): if None in self.state: return False return True def valid_moves(self): moves = [] for idx, player in enumerate(self.state): if player is None: moves.append(idx) return moves def minimax(board, player): maximize_player = 0 minimize_player = 1 if board.is_win(maximize_player): return (1, None) elif board.is_win(minimize_player): return (-1, None) elif board.is_end(): return (0, None) opp = 1 if player == 0 else 0 if player == maximize_player: max_score = -float('inf') max_idx = None for idx in board.valid_moves(): board.move(idx) score, next_idx = minimax(board, opp) if max_score < score: max_score = score max_idx = idx board.unmove(idx) return (max_score, max_idx) else: min_score = float('inf') min_idx = None for idx in board.valid_moves(): board.move(idx) score, next_idx = minimax(board, opp) if min_score > score: min_score = score min_idx = idx board.unmove(idx) return (min_score, min_idx) class BestPlayer: def __init__(self, player): self.player = player def play(self, board): score, idx = minimax(board, self.player) board.move(idx) return idx class GameManager: def __init__(self): self.board = None self.best_player = BestPlayer(1) self.game_running = False self.start() def start(self): self.board = Board() self.game_running = True display_message('Your turn') update_cells(self.board.state) Element("reset-button").add_class("hidden") def stop(self): self.game_running = False def resume(self): self.game_running = True def human_play(self, idx): if not self.game_running: return self.board.move(idx) update_cells(self.board.state) if self.board.is_win(0): display_message("You win🎉") self.game_running = False Element("reset-button").remove_class("hidden") return elif self.board.is_end(): display_message("Draw") self.game_running = False Element("reset-button").remove_class("hidden") return # AI Turn display_message("AI Turn") ai_idx = self.best_player.play(self.board) update_cells(self.board.state) if self.board.is_win(1): display_message("You lose😞") self.game_running = False Element("reset-button").remove_class("hidden") return display_message("Your turn") game_manager = GameManager() def reset(): game_manager.start() def cell_click(idx): game_manager.human_play(idx)