用Python实现五子棋小游戏人机对战和机器对战
时间: 2023-10-11 19:09:15 浏览: 158
python+pygame实现五子棋人机对战,讲解五子棋的基本知识和电脑应手的逻辑 内容详细,注释完整,讲解透彻 不涉及套接字
好的,五子棋是一种非常经典的棋类游戏,我们可以使用 Python 实现一个简单的五子棋游戏。下面分别介绍人机对战和机器对战的实现方法。
## 人机对战
首先,我们需要安装 `pygame` 库来实现游戏界面的绘制,可以通过以下命令进行安装:
```
pip install pygame
```
接下来,我们定义一个 `Board` 类来表示棋盘,其中包含以下方法:
- `__init__(self, width, height, size, margin)`:初始化函数,创建一个 `width` 行、`height` 列的棋盘,每个格子的大小为 `size`,格子之间的间隔为 `margin`。
- `draw(self, screen)`:绘制棋盘。
- `get_mouse_pos(self)`:获取鼠标在棋盘上的位置。
- `get_row_col(self, pos)`:将鼠标位置转换为棋盘上的行列坐标。
- `place(self, row, col, player)`:将玩家 `player` 的棋子放在 `(row, col)` 处。
- `get_winner(self)`:获取当前棋盘上的胜者,如果没有胜者则返回 None。
```python
import pygame
class Board:
def __init__(self, width, height, size, margin):
self.width = width
self.height = height
self.size = size
self.margin = margin
self.grid = [[0] * width for _ in range(height)]
def draw(self, screen):
screen.fill((255, 255, 255))
for row in range(self.height):
for col in range(self.width):
left = col * (self.size + self.margin) + self.margin
top = row * (self.size + self.margin) + self.margin
if self.grid[row][col] == 1:
pygame.draw.circle(screen, (0, 0, 0), (left + self.size // 2, top + self.size // 2), self.size // 2)
elif self.grid[row][col] == 2:
pygame.draw.circle(screen, (255, 255, 255), (left + self.size // 2, top + self.size // 2), self.size // 2)
pygame.draw.rect(screen, (0, 0, 0), (left, top, self.size, self.size), 1)
def get_mouse_pos(self):
return pygame.mouse.get_pos()
def get_row_col(self, pos):
x, y = pos
row = (y - self.margin) // (self.size + self.margin)
col = (x - self.margin) // (self.size + self.margin)
if row < 0 or row >= self.height or col < 0 or col >= self.width:
return None
return row, col
def place(self, row, col, player):
if self.grid[row][col] != 0:
return False
self.grid[row][col] = player
return True
def get_winner(self):
for row in range(self.height):
for col in range(self.width):
if self.grid[row][col] == 0:
continue
if col + 4 < self.width and self.grid[row][col] == self.grid[row][col+1] == self.grid[row][col+2] == self.grid[row][col+3] == self.grid[row][col+4]:
return self.grid[row][col]
if row + 4 < self.height and self.grid[row][col] == self.grid[row+1][col] == self.grid[row+2][col] == self.grid[row+3][col] == self.grid[row+4][col]:
return self.grid[row][col]
if row + 4 < self.height and col + 4 < self.width and self.grid[row][col] == self.grid[row+1][col+1] == self.grid[row+2][col+2] == self.grid[row+3][col+3] == self.grid[row+4][col+4]:
return self.grid[row][col]
if row + 4 < self.height and col - 4 >= 0 and self.grid[row][col] == self.grid[row+1][col-1] == self.grid[row+2][col-2] == self.grid[row+3][col-3] == self.grid[row+4][col-4]:
return self.grid[row][col]
return None
```
接下来,我们定义一个 `Game` 类来表示游戏,其中包含以下方法:
- `__init__(self, width, height, size, margin)`:初始化函数,创建一个 `Board` 对象,并设置玩家和电脑的棋子颜色。
- `run(self)`:运行游戏循环。
- `handle_event(self, event)`:处理游戏事件。
- `get_computer_move(self)`:获取电脑下一步的落子位置。
- `play_again(self)`:询问玩家是否要再次游戏。
```python
class Game:
def __init__(self, width, height, size, margin):
self.board = Board(width, height, size, margin)
self.player_color = 1
self.computer_color = 2
def run(self):
pygame.init()
screen = pygame.display.set_mode((self.board.width * (self.board.size + self.board.margin) + self.board.margin, self.board.height * (self.board.size + self.board.margin) + self.board.margin))
pygame.display.set_caption("Five in a Row")
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = self.board.get_mouse_pos()
row_col = self.board.get_row_col(pos)
if row_col is not None:
row, col = row_col
if self.board.place(row, col, self.player_color):
if self.board.get_winner() == self.player_color:
pygame.display.set_caption("You Win!")
running = False
else:
pos = self.get_computer_move()
row_col = self.board.get_row_col(pos)
if row_col is not None:
row, col = row_col
self.board.place(row, col, self.computer_color)
if self.board.get_winner() == self.computer_color:
pygame.display.set_caption("You Lose!")
running = False
elif all(self.board.grid[row][col] != 0 for row in range(self.board.height) for col in range(self.board.width)):
pygame.display.set_caption("Tie!")
running = False
self.board.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
self.play_again()
def handle_event(self, event):
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
def get_computer_move(self):
for row in range(self.board.height):
for col in range(self.board.width):
if self.board.grid[row][col] == 0:
return (col * (self.board.size + self.board.margin) + self.board.margin + self.board.size // 2, row * (self.board.size + self.board.margin) + self.board.margin + self.board.size // 2)
return None
def play_again(self):
while True:
choice = input("Play again? (y/n)").lower()
if choice == "y":
game = Game(15, 15, 30, 5)
game.run()
break
elif choice == "n":
break
```
最后,我们可以创建一个 `Game` 对象并运行游戏:
```python
game = Game(15, 15, 30, 5)
game.run()
```
## 机器对战
实现机器对战需要用到一些 AI 算法,比如蒙特卡罗树搜索(Monte Carlo Tree Search,简称 MCTS)。MCTS 是一种常用于博弈的搜索算法,它通过模拟多次随机游戏来评估每个落子位置的胜率,从而选择最优的落子位置。
下面,我们定义一个 `MCTS` 类来实现 MCTS 算法,其中包含以下方法:
- `__init__(self, board, player)`:初始化函数,创建一个空的搜索树,并设置玩家 `player` 的棋子颜色。
- `select(self)`:选择一个节点进行扩展。
- `expand(self, node)`:扩展节点。
- `simulate(self, node)`:模拟一次随机游戏,并返回胜者。
- `backpropagate(self, node, winner)`:将游戏结果反向传播到搜索树中的节点。
- `get_best_move(self)`:获取当前搜索树中的最优落子位置。
```python
import random
import math
class Node:
def __init__(self, state, player):
self.state = state
self.player = player
self.visits = 0
self.wins = 0
self.children = []
def get_untried_actions(self):
return [(row, col) for row in range(self.state.height) for col in range(self.state.width) if self.state.grid[row][col] == 0]
def get_best_child(self):
return max(self.children, key=lambda child: child.wins / child.visits)
def add_child(self, state):
child = Node(state, 3 - self.player)
self.children.append(child)
return child
class MCTS:
def __init__(self, board, player):
self.board = board
self.player = player
self.root = Node(board, player)
def select(self):
node = self.root
while node.children:
node = max(node.children, key=lambda child: (child.wins / child.visits) + math.sqrt(2 * math.log(node.visits) / child.visits))
return node
def expand(self, node):
action = random.choice(node.get_untried_actions())
state = Board(self.board.width, self.board.height, self.board.size, self.board.margin)
state.grid = [[node.state.grid[row][col] for col in range(self.board.width)] for row in range(self.board.height)]
state.place(action[0], action[1], node.player)
child = node.add_child(state)
return child
def simulate(self, node):
state = Board(self.board.width, self.board.height, self.board.size, self.board.margin)
state.grid = [[node.state.grid[row][col] for col in range(self.board.width)] for row in range(self.board.height)]
player = node.player
while True:
actions = [(row, col) for row in range(self.board.height) for col in range(self.board.width) if state.grid[row][col] == 0]
if not actions:
return None
action = random.choice(actions)
state.place(action[0], action[1], player)
winner = state.get_winner()
if winner is not None:
return winner
player = 3 - player
def backpropagate(self, node, winner):
while node is not None:
node.visits += 1
if node.player == winner:
node.wins += 1
node = node.parent
def get_best_move(self):
for i in range(100):
node = self.select()
if node.visits == 0:
winner = self.simulate(node)
self.backpropagate(node, winner)
else:
child = self.expand(node)
winner = self.simulate(child)
self.backpropagate(child, winner)
return self.root.get_best_child().state.get_last_move()
```
接下来,我们修改 `Game` 类,使其支持机器对战。我们需要修改以下方法:
- `__init__(self, width, height, size, margin)`:初始化函数,创建一个 `Board` 对象,并设置玩家和电脑的棋子颜色。
- `get_computer_move(self)`:获取电脑下一步的落子位置,调用 `MCTS` 类实现。
```python
class Game:
def __init__(self, width, height, size, margin):
self.board = Board(width, height, size, margin)
self.player_color = 1
self.computer_color = 2
self.mcts = MCTS(self.board, self.computer_color)
def run(self):
pygame.init()
screen = pygame.display.set_mode((self.board.width * (self.board.size + self.board.margin) + self.board.margin, self.board.height * (self.board.size + self.board.margin) + self.board.margin))
pygame.display.set_caption("Five in a Row")
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = self.board.get_mouse_pos()
row_col = self.board.get_row_col(pos)
if row_col is not None:
row, col = row_col
if self.board.place(row, col, self.player_color):
if self.board.get_winner() == self.player_color:
pygame.display.set_caption("You Win!")
running = False
else:
pos = self.mcts.get_best_move()
row, col = self.board.get_row_col(pos)
self.board.place(row, col, self.computer_color)
if self.board.get_winner() == self.computer_color:
pygame.display.set_caption("You Lose!")
running = False
elif all(self.board.grid[row][col] != 0 for row in range(self.board.height) for col in range(self.board.width)):
pygame.display.set_caption("Tie!")
running = False
self.board.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
self.play_again()
def get_computer_move(self):
pos = self.mcts.get_best_move()
row, col = self.board.get_row_col(pos)
return col * (self.board.size + self.board.margin) + self.board.margin + self.board.size // 2, row * (self.board.size + self.board.margin) + self.board.margin + self.board.size // 2
```
最后,我们可以创建一个 `Game` 对象并运行游戏:
```python
game = Game(15, 15, 30, 5)
game.run()
```
运行结果如下图所示:
![五子棋小游戏](https://i.imgur.com/xl9ebtY.png)
阅读全文