基于python纯函数实现井字棋游戏

1. 介绍

井字棋是一种非常受欢迎的人机博弈游戏,两个参与者轮流在3×3的棋盘上下棋,最先在横、竖、对角线上达成三子连珠者获胜。在这篇文章中,我们将使用Python编写一个纯函数版本的井字棋游戏。

2. 设计

2.1. 游戏状态

井字棋游戏最基本的元素是游戏状态。游戏状态可以表示为一个含有9个元素的列表,每个元素代表棋盘上的一个位置是否有棋子。

那么,我们可以把棋盘分成九个位置,编号如下:

board = [

0, 1, 2,

3, 4, 5,

6, 7, 8

]

游戏状态中每个位置分别对应这个列表中的元素,当某个位置有棋子时,对应位置的元素值为1。当某个位置没有棋子时,对应位置的元素值为0。

例如,如果当前游戏状态为:

[

1, 0, 0,

0, -1, 0,

0, 0, 1

]

那么棋盘上的状态为:

 X |   |  

---+---+---

| O |

---+---+---

| | X

其中,X表示先手玩家下的棋子,O表示后手玩家下的棋子。

2.2. 对手和游戏结束状态

在井字棋游戏中,先手玩家下的棋子为X,后手玩家下的棋子为O。

当游戏结束时,有三种情况:

先手玩家获胜

后手玩家获胜

平局

我们可以使用字母X和O表示先手和后手玩家,使用数字1和-1表示玩家在对应位置下的棋子。因此,在游戏结束时,可以根据游戏状态得到对应的对手和游戏结束状态。

def opponent(player):

return -player

def game_over(board, player):

lines = [

[board[0], board[1], board[2]],

[board[3], board[4], board[5]],

[board[6], board[7], board[8]],

[board[0], board[3], board[6]],

[board[1], board[4], board[7]],

[board[2], board[5], board[8]],

[board[0], board[4], board[8]],

[board[2], board[4], board[6]],

]

for line in lines:

if all(position == player for position in line):

return player

elif all(position == opponent(player) for position in line):

return opponent(player)

if 0 not in board:

return 0

return None

函数opponent返回对手的数字表示。函数game_over在游戏结束时返回胜者的数字表示,如果平局返回0,否则返回None。

3. 实现

3.1. 游戏操作

现在我们可以实现游戏操作。

首先,我们需要一个函数来检查是否可以在指定位置下棋。

def is_move_valid(board, move):

return board[move] == 0

如果指定位置没有棋子,返回True,否则返回False

然后,我们需要一个函数来执行玩家的下棋操作,并返回下个玩家。

def make_move(board, move, player):

new_board = board.copy()

new_board[move] = player

return new_board, opponent(player)

函数make_move把当前的游戏状态复制一份,并把指定位置下成玩家的棋子,接着返回新的游戏状态和下一个玩家。

3.2. 游戏循环

现在我们已经有了足够的代码来实现井字棋游戏循环了。

def play_game():

board = [

0, 0, 0,

0, 0, 0,

0, 0, 0

]

player = 1

while True:

print_board(board)

move = get_move(board, player)

board, player = make_move(board, move, player)

winner = game_over(board, player)

if winner is not None:

print_board(board)

if winner == 0:

print("平局")

else:

print("玩家{}获胜".format(winner))

return

在这个游戏循环中,我们从一个初始状态开始,打印当前的棋盘状态,获取玩家要下的位置,执行下棋操作,并检查是否游戏结束。如果游戏结束,则输出结果并结束循环。

3.3. 策略

一个好的AI程序需要一个合适的下棋策略。我们将使用Minimax算法来实现这个策略。

在实现Minimax算法之前,我们需要一个函数来计算当前游戏状态的分数。在本文中,我们将使用简单的评分函数。对于每行、每列和每条对角线,我们计算有多少棋子属于当前玩家,减去有多少棋子属于对手。

def score(board, player):

lines = [

[board[0], board[1], board[2]],

[board[3], board[4], board[5]],

[board[6], board[7], board[8]],

[board[0], board[3], board[6]],

[board[1], board[4], board[7]],

[board[2], board[5], board[8]],

[board[0], board[4], board[8]],

[board[2], board[4], board[6]],

]

score = 0

for line in lines:

count = line.count(player)

opponent_count = line.count(opponent(player))

if count == 3:

score += 100

elif count == 2 and opponent_count == 0:

score += 10

elif count == 1 and opponent_count == 2:

score -= 10

return score

现在,我们可以实现Minimax算法了。

3.4. Minimax算法

Minimax算法是一种递归算法,用于确定游戏的最优决策。在每个玩家的回合,他们都会尝试最大化可能的利益,而在对手的回合,他们则会尝试最小化玩家的利益。

我们可以使用以下函数来计算当前游戏状态的最优决策:

def minimax(board, player, depth=8):

if depth == 0:

return None, score(board, player)

if game_over(board, player) is not None:

return None, game_over(board, player)

scores = []

moves = []

for move in range(9):

if is_move_valid(board, move):

new_board, new_player = make_move(board, move, player)

_, move_score = minimax(new_board, new_player, depth - 1)

scores.append(move_score)

moves.append(move)

if player == 1:

max_score_index = scores.index(max(scores))

return moves[max_score_index], scores[max_score_index]

else:

min_score_index = scores.index(min(scores))

return moves[min_score_index], scores[min_score_index]

函数minimax使用递归方法计算当前游戏状态的最优决策。如果当前深度达到了设定的限制,或者游戏结束了,函数就会返回分数。否则,函数就会对每个合法位置进行尝试,并记录对应的分数。如果是玩家的回合,就返回分数最高的决策;如果是对手的回合,就返回分数最低的决策。

3.5. AI玩家

我们已经有了足够的代码来实现一个AI玩家了。

def get_move(board, player):

if player == 1:

print("玩家X的回合")

move = int(input("请输入要下棋子的位置:"))

else:

print("玩家O的回合")

move, _ = minimax(board, player)

while not is_move_valid(board, move):

print("无效的位置,请重新输入")

move = int(input("请输入要下棋子的位置:"))

return move

函数get_move获取玩家要下的位置,并使用Minimax算法计算AI要下的位置。

3.6. 打印棋盘

最后,我们需要一个函数来打印当前的棋盘状态。

def print_board(board):

symbols = {

-1: "O",

0: " ",

1: "X"

}

row = " {} | {} | {} "

hr = "\n-----------\n"

print((row + hr + row + hr + row).format(*(symbols[position] for position in board)))

函数print_board定义了三种不同的符号,用于打印X、O和空格。函数接受当前游戏状态作为输入,并打印出网格中的符号。

4. 运行

现在我们可以运行代码并开始玩井字棋游戏了!

play_game()

结论

在这篇文章中,我们一步步地学习了如何实现一个使用Minimax算法的井字棋游戏。我们实现了一个纯函数版本的井字棋游戏,并实现了一个基本的评分函数和一个简单的Minimax算法,让AI程序可以玩井字棋游戏并表现出不错的战略水平。

后端开发标签