【创新】教你用python做五子棋AI(含代码)

【创新】教你用python做五子棋AI(含代码)

老样子先讲思路:

观点由作者老程想出,只供参考

  1. FiveChessGame 类的初始化:
  • 创建主窗口,设置标题和背景颜色。

  • 创建画布并绑定鼠标点击事件。

  1. draw_board 方法:
  • 在画布上绘制棋盘的横竖线条。
  1. place_piece 方法:
  • 根据鼠标点击位置确定棋子放置的行列。

  • 如果位置为空,放置棋子并更新棋盘状态。

  • 检查是否获胜或平局,如果是则显示相应的消息框并更新游戏状态。

  • 切换当前玩家,如果是 AI 回合则调用 ai_move 方法。

  1. draw_piece 方法:
  • 在指定位置绘制棋子。
  1. check_win 方法:
  • 遍历整个棋盘,对于每个非空棋子,调用 check_win_at_pos 方法检查是否获胜。
  1. check_win_at_pos 方法:
  • 针对特定位置和棋子类型,在四个方向上检查是否形成五子连珠。
  1. is_draw 方法:
  • 检查棋盘是否已满,以判断是否平局。
  1. ai_move 方法:
  • 进行一定深度的搜索,计算每个可能落子位置的得分。

  • 选择得分最高的位置放置 AI 的棋子。

  • 检查放置后是否获胜或平局,并更新游戏状态和显示相应消息框。

  1. minimax 方法:
  • 实现了极小极大算法,根据当前深度、搜索范围和玩家角色(最大化或最小化)进行递归搜索,计算局面得分。
  1. evaluate_position 方法:
  • 评估当前棋盘局面的得分,考虑棋子的布局情况,如活三、活四等。
  1. check_open_three 和 check_open_four 方法:
  • 分别检查是否存在活三或活四的情况。
  1. handle_click 方法:
  • 处理鼠标点击事件,调用 place_piece 方法放置玩家的棋子。
  1. run 方法:
  • 绘制棋盘并启动主事件循环。

总体思路是通过各种方法实现五子棋的游戏逻辑,包括玩家和 AI 的落子、胜负判断、局面评估等,以实现一个可交互的五子棋游戏,并且 AI 具有一定的智能水平。

理论已明确,以下是实践:

首先是导入模块

import tkinter as tk
from tkinter import messagebox

剩下是修改原五子棋的代码,添加了AI,增强了算法能力。

BOARD_SIZE = 20  
GRID_SIZE = 30  
WHITE = "white"
BLACK = "black"
YELLOW = "yellow"  
PLAYER1_COLOR = BLACK
PLAYER2_COLOR = WHITE
GAME_CONTINUE = 0
PLAYER1_WIN = 1
PLAYER2_WIN = 2
DRAW = 3

class FiveChessGame:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("五子棋游戏")
        self.root.configure(bg=YELLOW)  

        self.canvas = tk.Canvas(self.root, width=BOARD_SIZE * GRID_SIZE, height=BOARD_SIZE * GRID_SIZE)
        self.canvas.pack()

        self.board = [[0 for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
        self.current_player = PLAYER1_COLOR
        self.game_state = GAME_CONTINUE

        self.canvas.bind("<Button-1>", self.handle_click)

    def draw_board(self):
        for i in range(BOARD_SIZE):
            self.canvas.create_line(0, i * GRID_SIZE, BOARD_SIZE * GRID_SIZE, i * GRID_SIZE)
            self.canvas.create_line(i * GRID_SIZE, 0, i * GRID_SIZE, BOARD_SIZE * GRID_SIZE)

    def place_piece(self, x, y):
        row = y // GRID_SIZE
        col = x // GRID_SIZE
        if self.board[row][col] == 0:
            self.board[row][col] = 1 if self.current_player == PLAYER1_COLOR else 2
            self.draw_piece(col * GRID_SIZE, row * GRID_SIZE)
            if self.check_win():  # 不再传递 row 和 col
                if self.current_player == PLAYER1_COLOR:
                    self.game_state = PLAYER1_WIN
                    messagebox.showinfo("游戏结果", "玩家胜利!")
                else:
                    self.game_state = PLAYER2_WIN
                    messagebox.showinfo("游戏结果", "AI 胜利!")
            elif self.is_draw():
                self.game_state = DRAW
                messagebox.showinfo("游戏结果", "平局!")
            else:
                self.current_player = PLAYER2_COLOR if self.current_player == PLAYER1_COLOR else PLAYER1_COLOR
                if self.current_player == PLAYER2_COLOR:  
                    self.ai_move()

    def draw_piece(self, x, y):
        color = self.current_player
        self.canvas.create_oval(x + 5, y + 5, x + GRID_SIZE - 5, y + GRID_SIZE - 5, fill=color)

    def check_win(self):  # 修改为不需要 row 和 col 参数
        for row in range(BOARD_SIZE):
            for col in range(BOARD_SIZE):
                if self.board[row][col]!= 0 and self.check_win_at_pos(row, col):  # 调用新的辅助方法
                    return True
        return False

    def check_win_at_pos(self, row, col):  # 新的辅助方法来检查特定位置是否导致获胜
        directions = [(1, 0), (0, 1), (1, 1), (1, -1)]
        piece_type = self.board[row][col]

        for dr, dc in directions:
            count = 1
            r, c = row + dr, col + dc
            while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == piece_type:
                count += 1
                r += dr
                c += dc
            r, c = row - dr, col - dc
            while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == piece_type:
                count += 1
                r -= dr
                c -= dc
            if count >= 5:
                return True
        return False

    def is_draw(self):
        for row in self.board:
            for col in row:
                if col == 0:
                    return False
        return True

    def ai_move(self):
        max_depth = 2  # 增加搜索深度,可根据性能和需求调整
        best_score = float('-inf')
        best_move = None

        for row in range(BOARD_SIZE):
            for col in range(BOARD_SIZE):
                if self.board[row][col] == 0:
                    self.board[row][col] = 2
                    score = self.minimax(max_depth, float('-inf'), float('inf'), False)
                    self.board[row][col] = 0

                    if score > best_score:
                        best_score = score
                        best_move = (col, row)

        if best_move:
            col, row = best_move
            self.board[row][col] = 2
            self.draw_piece(col * GRID_SIZE, row * GRID_SIZE)
            if self.check_win():  # 不再传递 row 和 col
                self.game_state = PLAYER2_WIN
                messagebox.showinfo("游戏结果", "AI 胜利!")
            elif self.is_draw():
                self.game_state = DRAW
                messagebox.showinfo("游戏结果", "平局!")
            else:
                self.current_player = PLAYER1_COLOR

    def minimax(self, depth, alpha, beta, is_maximizing_player):
        if depth == 0 or self.check_win():  # 不再传递 row 和 col
            return self.evaluate_position()

        if is_maximizing_player:
            max_eval = float('-inf')
            for row in range(BOARD_SIZE):
                for col in range(BOARD_SIZE):
                    if self.board[row][col] == 0:
                        self.board[row][col] = 2
                        eval_score = self.minimax(depth - 1, alpha, beta, False)
                        self.board[row][col] = 0
                        max_eval = max(max_eval, eval_score)
                        alpha = max(alpha, eval_score)
                        if beta <= alpha:
                            break
            return max_eval
        else:
            min_eval = float('inf')
            for row in range(BOARD_SIZE):
                for col in range(BOARD_SIZE):
                    if self.board[row][col] == 0:
                        self.board[row][col] = 1
                        eval_score = self.minimax(depth - 1, alpha, beta, True)
                        self.board[row][col] = 0
                        min_eval = min(min_eval, eval_score)
                        beta = min(beta, eval_score)
                        if beta <= alpha:
                            break
            return min_eval

    def evaluate_position(self):
        score = 0

        # 考虑更多的布局因素,如活三、活四等
        for row in range(BOARD_SIZE):
            for col in range(BOARD_SIZE):
                if self.board[row][col] == 2:  
                    for dr, dc in [(1, 0), (0, 1), (1, 1), (1, -1)]:
                        count = 1
                        r, c = row + dr, col + dc
                        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == 2:
                            count += 1
                            r += dr
                            c += dc
                        r, c = row - dr, col - dc
                        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and self.board[r][c] == 2:
                            count += 1
                            r -= dr
                            c -= dc

                        if count == 2:
                            score += 20
                        elif count == 3:
                            score += 100
                        elif count == 4:
                            score += 1000
                        elif count == 3 and self.check_open_three(row, col, dr, dc):  # 活三
                            score += 500
                        elif count == 4 and self.check_open_four(row, col, dr, dc):  # 活四
                            score += 2000

        return score

    def check_open_three(self, row, col, dr, dc):
        count = 1
        r, c = row + dr, col + dc
        blocked = False
        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
            if self.board[r][c] == 0:
                break
            elif self.board[r][c] == 2:
                count += 1
                r += dr
                c += dc
            else:
                blocked = True
                break
        r, c = row - dr, col - dc
        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
            if self.board[r][c] == 0:
                break
            elif self.board[r][c] == 2:
                count += 1
                r -= dr
                c -= dc
            else:
                blocked = True
                break
        return count == 3 and not blocked

    def check_open_four(self, row, col, dr, dc):
        count = 1
        r, c = row + dr, col + dc
        blocked = False
        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
            if self.board[r][c] == 0:
                break
            elif self.board[r][c] == 2:
                count += 1
                r += dr
                c += dc
            else:
                blocked = True
                break
        r, c = row - dr, col - dc
        while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE:
            if self.board[r][c] == 0:
                break
            elif self.board[r][c] == 2:
                count += 1
                r -= dr
                c -= dc
            else:
                blocked = True
                break
        return count == 4 and not blocked

    def handle_click(self, event):
        x = event.x
        y = event.y
        self.place_piece(x, y)

    def run(self):
        self.draw_board()
        self.root.mainloop()

if __name__ == "__main__":
    game = FiveChessGame()
    game.run()

以上是原代码,运行可能有点慢,这十分考验了高配置的电脑,低配置的需要等待一段时间初始化。

最后,请大家多多支持老程,老程花了两天时间研究,之后老程后更新更多的作品。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值