井字棋 AI-Python

1. 介绍程序中的算法

MinMax算法,也称为极小化极大算法,是一种在博弈论中广泛应用的算法,用于在两个竞争者之间进行零和博弈时,找出最优策略。

该算法适用于井字棋、象棋等游戏,旨在为玩家提供最佳决策。其基本思想是假设对手不会犯错误,从而在最坏情况下保证自己的最大利益。

Minimax算法的核心在于构建一个博弈树,这个树展示了所有可能的游戏状态和双方的决策路径。每个节点代表一种游戏状态,边代表从一种状态到另一种状态的转换。在这个树中,一方努力最大化自己的收益(MAX节点),而另一方努力最小化对方的收益(MIN节点)。

具体来说,如果当前是MAX节点(即玩家希望最大化收益的节点),它会评估所有可能的走法,并选择能带来最大价值的走法。相反,如果当前是MIN节点(即对手试图最小化玩家收益的节点),则选择对玩家最不利的走法。通过这种递归方式,Minimax算法能够找到一条最优路径,使得在对方采取最佳反应的情况下,自己的损失最小。

然而,这种方法存在明显的效率问题,尤其是当博弈树非常庞大时。为了优化这一过程,引入了Alpha-Beta剪枝技术。这种技术通过维护两个值——Alpha(当前找到的最大下界)和Beta(当前找到的最小上界),在搜索过程中剪枝那些不可能优于已有选择的子树,从而显著减少搜索量。

总的来说,Minimax算法通过构建博弈树并递归评估每个可能的游戏状态,寻找在对手采取最优反应的情况下能够保证的最佳结果。结合Alpha-Beta剪枝,可以有效提高搜索效率,使得该算法在复杂的游戏中依然实用。

2.应用 Minimax 算法:

def minimax(board, depth, is_maximizing, alpha=float('-inf'), beta=float('inf'), depth_limit=None):
    winner = check_winner(board)
    if winner == 'X':
        return 1 / depth
    elif winner == 'O':
        return -1 / depth
    elif is_draw(board):
        return 0

3.源代码:

import time
def check_winner(board):
    # 检查行是否有获胜者
    for row in board:
        if row.count(row[0]) == len(row) and row[0] != ' ':
            return row[0]
    
    # 检查列是否有获胜者
    for col in range(len(board)):
        if all(row[col] == board[0][col] for row in board) and board[0][col] != ' ':
            return board[0][col]
    
    # 检查对角线是否有获胜者
    if all(board[i][i] == board[0][0] for i in range(len(board))) and board[0][0] != ' ':
        return board[0][0]
    if all(board[i][len(board)-1-i] == board[0][len(board)-1] for i in range(len(board))) and board[0][len(board)-1] != ' ':
        return board[0][len(board)-1]
    
    # 检查是否平局
    if all(all(cell != ' ' for cell in row) for row in board):
        return 'draw'
    
    # 没有获胜者且游戏未结束
    return None

def is_draw(board):
    return check_winner(board) == 'draw'
def make_move(board, move, player):
    row, col = move
    new_board = [row[:] for row in board]  # 创建棋盘的深拷贝以避免修改原始棋盘
    new_board[row][col] = player
    return new_board

def get_valid_moves(board):
    valid_moves = []
    for i in range(len(board)):
        for j in range(len(board[i])):
            if board[i][j] == ' ':
                valid_moves.append((i, j))
    return valid_moves

def minimax(board, depth, is_maximizing, alpha=float('-inf'), beta=float('inf'), depth_limit=None):
    winner = check_winner(board)
    if winner == 'X':
        return 1 / depth
    elif winner == 'O':
        return -1 / depth
    elif is_draw(board):
        return 0

    if depth_limit is not None and depth >= depth_limit:
        return 10000  # 返回一个默认评估值,例如 0,表示在这个深度上不进行进一步搜索

    if is_maximizing:
        best_score = float('-inf')
        for move in get_valid_moves(board):
            new_board = make_move(board, move, 'X')
            score = minimax(new_board, depth + 1, False, alpha, beta, depth_limit)
            best_score = max(best_score, score)
            alpha = max(alpha, best_score)
            if beta <= alpha:
                break
        return best_score
    else:
        best_score = float('inf')
        for move in get_valid_moves(board):
            new_board = make_move(board, move, 'O')
            score = minimax(new_board, depth + 1, True, alpha, beta, depth_limit)
            best_score = min(best_score, score)
            beta = min(beta, best_score)
            if beta <= alpha:
                break
        return best_score

def ai_move(board, depth_limit=None):
    best_score = float('-inf')
    best_move = None
    for move in get_valid_moves(board):
        new_board = make_move(board, move, 'X')
        score = minimax(new_board, 1, False, depth_limit=depth_limit)
        if score > best_score:
            best_score = score
            best_move = move
    return best_move

 

def print_board(board):
    for row in board:
        print(" | ".join(row))
        print("-" * (4 * len(board) - 3))

def main():
    board = [[' ' for _ in range(3)] for _ in range(3)]
    current_player = 'X'
    
    while True:
        print_board(board)
        if current_player == 'X':
            # 玩家输入
            row, col = map(int, input("请输入行和列(用空格分隔):").split())
            if board[row][col] != ' ':
                print("无效的移动,请重新输入。")
                continue
            board = make_move(board, (row, col), current_player)
        else:
            # AI输入
            print("AI正在思考...")
            time.sleep(1)
            move = ai_move(board, depth_limit=1000)
            board = make_move(board, move, current_player)
        
        winner = check_winner(board)
        if winner is not None:
            print_board(board)
            if winner == 'draw':
                print("平局!")
            else:
                print(f"{winner} 赢了!")
            break
        
        current_player = 'O' if current_player == 'X' else 'X'

if __name__ == "__main__":
    main()

相关推荐

  1. AI-Python

    2024-07-11 14:02:02       25 阅读
  2. 使用Python创建游戏

    2024-07-11 14:02:02       36 阅读
  3. 使用python写一个窗口小游戏

    2024-07-11 14:02:02       32 阅读
  4. (免费版)

    2024-07-11 14:02:02       25 阅读
  5. 三子/(C语言)

    2024-07-11 14:02:02       39 阅读
  6. C++EasyX之

    2024-07-11 14:02:02       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 14:02:02       66 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 14:02:02       70 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 14:02:02       57 阅读
  4. Python语言-面向对象

    2024-07-11 14:02:02       68 阅读

热门阅读

  1. android解锁remount

    2024-07-11 14:02:02       27 阅读
  2. 洛谷 P3008 [USACO11JAN] Roads and Planes G

    2024-07-11 14:02:02       22 阅读
  3. 2.Spring的IOC容器里面加入对象的常见方式

    2024-07-11 14:02:02       24 阅读
  4. React基础学习-Day02

    2024-07-11 14:02:02       19 阅读
  5. MyClass.static_method() 加不加括号有什么区别

    2024-07-11 14:02:02       23 阅读
  6. AcWing 1633:外观数列

    2024-07-11 14:02:02       25 阅读
  7. nginx的重定向

    2024-07-11 14:02:02       24 阅读
  8. SpringBoot整合Easy-Es最佳实践

    2024-07-11 14:02:02       21 阅读