实验一:基于启发式搜索实现一字棋

一字棋游戏简介

“一字棋"游戏(又叫"三子棋"或"井字棋”),是一款十分经典的益智小游戏。“井字棋"的棋盘很简单,是一个 3×3 的格子,很像中国文字中的"井"字,所以得名"井字棋”。"井字棋"游戏的规则与"五子棋"十分类似,"五子棋"的规则是一方首先五子连成一线就胜利;"井字棋"是一方首先三子连成一线就胜利。 尽可能的朝着可以让计算机获胜的方向走步。需要采用极大极小搜索算法。 “一字棋”游戏(又叫“三子棋”或“井字棋”),是一款十分经典的益智小游戏。“井字棋”的棋盘很简单,是一个 3×3 的格子,很像中国文字中的“井”字,所以得名“井字棋”。“井字棋”游戏的规则与“五子棋”十分类似,“五子棋”的规则是一方首先五子连成一线就胜利;“井字棋”是一方首先三子连成一线就胜利。

启发式搜索简介

启发式搜索(Heuristically Search)又称为有信息搜索(Informed Search),它是利用问题拥有的启发信息来引导搜索,达到减少搜索范围、降低问题复杂度的目的,这种利用启发信息的搜索过程称为启发式搜索。 启发式策略可以通过指导搜索向最有希望的方向前进,降低了复杂性。通过删除某些状态及其延伸,启发式算法可以消除组合爆炸,并得到令人能接受的解(通常并不一定是最佳解)。 然而,启发式策略是极易出错的。在解决问题的过程中启发仅仅是下一步将要采取措施的一个猜想,常常根据经验和直觉来判断。由于启发式搜索只有有限的信息(比如当前状态的描述),要想预测进一步搜索过程中状态空间的具体行为则很难。一个启发式搜索可能得到一个次最佳解,也可能一无所获。这是启发式搜索固有的局限性。这种局限性不可能由所谓更好的启发式策略或更有效的搜索算法来消除。一般说来,启发信息越强,扩展的无用节点就越少。引入强的启发信息,有可能大大降低搜索工作量,但不能保证找到最小耗散值的解路径(最佳路径)。因此,在实际应用中,最好能引入降低搜索工作量的启发信息而不牺牲找到最佳路径的保证。

示例代码

# 初始化棋盘
def init_board():
    return [[' ' for _ in range(3)] for _ in range(3)]


# 打印棋盘
def print_board(board):
    for row in board:
        print('|'.join(row))
        print('-----')


# 判断游戏是否结束
def game_over(board):
    # 检查行
    for row in board:
        if len(set(row)) == 1 and row[0] != ' ':
            return True, row[0]

    # 检查列
    for col in range(3):
        if len(set([board[row][col] for row in range(3)])) == 1 and board[0][col] != ' ':
            return True, board[0][col]

    # 检查对角线
    if len(set([board[i][i] for i in range(3)])) == 1 and board[0][0] != ' ':
        return True, board[0][0]
    if len(set([board[i][2 - i] for i in range(3)])) == 1 and board[0][2] != ' ':
        return True, board[0][2]

    # 检查平局
    if all([cell != ' ' for row in board for cell in row]):
        return True, 'Draw'

    return False, None


# 极大极小值搜索
def minimax(board, depth, is_maximizing):
    game_over_flag, winner = game_over(board)
    if game_over_flag:
        if winner == 'X':
            return -1
        elif winner == 'O':
            return 1
        else:
            return 0

    if is_maximizing:
        best_score = float('-inf')
        for i in range(3):
            for j in range(3):
                if board[i][j] == ' ':
                    board[i][j] = 'O'
                    score = minimax(board, depth + 1, False)
                    board[i][j] = ' '
                    best_score = max(score, best_score)
        return best_score
    else:
        best_score = float('inf')
        for i in range(3):
            for j in range(3):
                if board[i][j] == ' ':
                    board[i][j] = 'X'
                    score = minimax(board, depth + 1, True)
                    board[i][j] = ' '
                    best_score = min(score, best_score)
        return best_score


# AI走棋
def ai_move(board):
    best_score = float('-inf')
    best_move = None
    for i in range(3):
        for j in range(3):
            if board[i][j] == ' ':
                board[i][j] = 'O'
                score = minimax(board, 0, False)
                board[i][j] = ' '
                if score > best_score:
                    best_score = score
                    best_move = (i, j)
    board[best_move[0]][best_move[1]] = 'O'
    print("ai下棋:行:", best_move[0], "列:", best_move[1])


# 主程序
def main():
    board = init_board()
    while True:
        print_board(board)
        game_over_flag, winner = game_over(board)
        if game_over_flag:
            if winner == 'Draw':
                print("平局")
            else:
                print(f"胜利者是 {winner}!")
            break
        row, col = map(int, input("请下棋,输入行和列(从0开始),用空格隔开: ").split())
        if row >= 3 or col >= 3 or col <= -1 or row <= -1 or board[row][col] != ' ':
            print("输入不合法,请重新输入")
            continue
        board[row][col] = 'X'
        game_over_flag, winner = game_over(board)
        if game_over_flag:
            if winner == 'Draw':
                print("平局")
            else:
                print(f"胜利者是 {winner}!")
            break
        ai_move(board)


if __name__ == '__main__':
    main()

运行结果 

 | | 
-----
 | | 
-----
 | | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  1 1
ai下棋:行: 0 列: 0
O| | 
-----
 |X| 
-----
 | | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  0 2
ai下棋:行: 2 列: 0
O| |X
-----
 |X| 
-----
O| | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  1 0
ai下棋:行: 1 列: 2
O| |X
-----
X|X|O
-----
O| | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  2 2
ai下棋:行: 0 列: 1
O|O|X
-----
X|X|O
-----
O| |X
-----
请下棋,输入行和列(从0开始),用空格隔开:  1 0
输入不合法,请重新输入
O|O|X
-----
X|X|O
-----
O| |X
-----
请下棋,输入行和列(从0开始),用空格隔开:  2 1
平局
| | 
-----
 | | 
-----
 | | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  1 1
ai下棋:行: 0 列: 0
O| | 
-----
 |X| 
-----
 | | 
-----
请下棋,输入行和列(从0开始),用空格隔开:  0 1
ai下棋:行: 2 列: 1
O|X| 
-----
 |X| 
-----
 |O| 
-----
请下棋,输入行和列(从0开始),用空格隔开:  1 2
ai下棋:行: 1 列: 0
O|X| 
-----
O|X|X
-----
 |O| 
-----
请下棋,输入行和列(从0开始),用空格隔开:  0 2
ai下棋:行: 2 列: 0
O|X|X
-----
O|X|X
-----
O|O| 
-----
胜利者是 O!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值