[pygame]成三棋
棋盘为大、中、小三个正方形,小的在中央,中号在小正方形的外围,大号的在中号的外围,三个正方形同方向的一边中点用线段连接。每个正方形的四个角及四条边的中点为布子及走子处。共为24点可布子或走子。分红黑双方,人机对抗模式,红方先行。可选玩家先或电脑先。棋盘外围空白处设置先后手选择按钮,另外设置状态提示,如布子阶段、走子阶段、红方走子、黑方走子、红方成三、黑方成三、红方吃子等。一方的三个棋子成一条直线(横线或竖线,斜线不算),且中间没有空格或对方棋子,即为“成三”(或“成山”)。一方成三后,可吃掉对方一个没有成三的棋子。一方成三后先吃子,再轮到对方布子或走子。双方均布子九次后转到走子阶段。在走棋阶段吃光对方棋子或堵死对方走棋出路为胜利,到走子阶段双方各走棋10步没有吃一子或堵死对方为和棋。在走棋阶段,成三的棋子可走成不成三的状态,术语叫开山,开山后再走成成三可再吃掉对方一子。不断地开山、成三为吃掉对方的常规手段。一方开三时,对方可吃掉在开三状态下的任意棋子,或走棋到对方开三的位置不让对手再成三。为方便显示电脑行棋状态,玩家下棋或走棋后等待2秒后电脑布子或走棋,以便标签显示电脑方行棋。以下代码还有一些bug, 望修正。from enum import Enum
import pygame
import sys
import random
# 初始化Pygame
pygame.init()
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
BOARD_COLOR = (245, 222, 179)
BUTTON_COLOR = (100, 100, 100)
# 窗口设置
WIDTH, HEIGHT = 1000, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("成三棋")
# 字体设置
font = pygame.font.SysFont('simhei', 24)
big_font = pygame.font.SysFont('simhei', 36)
class GameState(Enum):
PLACE = 1
MOVE = 2
REMOVE = 3
GAME_OVER = 4
class Game:
def __init__(self):
self.reset()
def reset(self):
self.state = None
self.board = [''] * 24
self.placed = {'red': 0, 'black': 0}
self.turn = None
self.selected = -1
self.remove_list = []
self.buttons = [
self.create_button("玩家先手", (50, 700, 200, 60)),
self.create_button("电脑先手", (750, 700, 200, 60))
]
# 棋盘参数
self.center = (500, 400)
self.radius =
self.points = self.calculate_points()
self.lines = self.get_all_lines()
self.neighbors = self.get_neighbors()
# 新增check_phase方法
def check_phase(self):
"""检查是否需要进入走子阶段"""
ifself.state == GameState.PLACE and self.placed['red'] >= 9 and self.placed['black'] >= 9:
self.state = GameState.MOVE
def create_button(self, text, rect):
return {
'rect': pygame.Rect(rect),
'text': text,
'color': BUTTON_COLOR,
'visible': True
}
def calculate_points(self):
points = []
# 计算三个正方形的24个点
for r in self.radius:
square = [
(self.center - r, self.center - r),# 左上
(self.center, self.center - r),# 上中
(self.center + r, self.center - r),# 右上
(self.center + r, self.center),# 右中
(self.center + r, self.center + r),# 右下
(self.center, self.center + r),# 下中
(self.center - r, self.center + r),# 左下
(self.center - r, self.center)# 左中
]
points.extend(square)
return points
def get_all_lines(self):
return [
# 外层正方形
, , , ,
# 中层正方形
, , , ,
# 内层正方形
, , , ,
# 垂直线
, , ,
]
def get_neighbors(self):
# 定义每个点的相邻点
return [
, , , , , ,
, , , , , ,
, , , , ,
, , , , ,
,
]
def draw_board(self):
screen.fill(BOARD_COLOR)
# 绘制三个正方形
for r in self.radius:
rect = (self.center - r, self.center - r, 2 * r, 2 * r)
pygame.draw.rect(screen, BLACK, rect, 2)
# 绘制连接线
for i in :
pygame.draw.line(screen, BLACK, self.points, self.points, 2)
pygame.draw.line(screen, BLACK, self.points, self.points, 2)
# 绘制棋子
for i, pos in enumerate(self.points):
if self.board == 'red':
pygame.draw.circle(screen, RED, pos, 25)
elif self.board == 'black':
pygame.draw.circle(screen, BLACK, pos, 25)
# 绘制选中状态
if self.selected != -1:
pygame.draw.circle(screen, GREEN, self.points, 20, 3)
# 绘制可吃子提示
for i in self.remove_list:
pygame.draw.circle(screen, YELLOW, self.points, 20, 3)
# 绘制状态提示
self.draw_status()
# 绘制按钮
for btn in self.buttons:
if btn['visible']:
pygame.draw.rect(screen, btn['color'], btn['rect'], border_radius=5)
text = big_font.render(btn['text'], True, WHITE)
screen.blit(text, (btn['rect'].x + 20, btn['rect'].y + 15))
# 绘制状态提示
self.draw_status()
def draw_status(self):
status_text = []
if self.state:
if self.state == GameState.PLACE:
status_text.append(f"布子阶段 - {self.turn}方回合")
status_text.append(f"红方已布子: {self.placed['red']}/9")
status_text.append(f"黑方已布子: {self.placed['black']}/9")
elif self.state == GameState.MOVE:
status_text.append("走子阶段")
elif self.state == GameState.REMOVE:
attacker = 'red' if self.turn == 'red' else 'black'# 修正显示逻辑
status_text.append(f"{attacker.upper()}方成三!请吃子")
# 确保文本渲染到屏幕
for i, text in enumerate(status_text):
text_surf = font.render(text, True, BLACK)
screen.blit(text_surf, (20, 20 + i * 30))
def check_three(self, player):
for line in self.lines:
if all(self.board == player for i in line):
return True
return False
def get_removable(self, attacker):
"""修正攻击方和防守方关系"""
defender = 'black' if attacker == 'red' else 'red'
removable = []
for i in range(24):
if self.board == defender:
safe = any(all(self.board == defender for j in line)
for line in self.lines if i in line)
if not safe:
removable.append(i)
return removable
def check_win(self):
"""只在走子阶段检查胜利条件"""
if self.state != GameState.MOVE:
return None
# 检查棋子数量
red_count = self.board.count('red')
black_count = self.board.count('black')
if red_count < 3:
return 'black'
if black_count < 3:
return 'red'
# 检查移动能力
def can_move(player):
for i in range(24):
if self.board == player:
if any(self.board == '' for n in self.neighbors):
return True
return False
current_player = 'red' if self.turn == 'red' else 'black'
if not can_move(current_player):
return 'black' if current_player == 'red' else 'red'
return None
def ai_move(self):
# 简单AI策略
if self.state == GameState.PLACE:
# 尝试完成三连
for i in range(24):
if self.board == '':
self.board = 'black'
if self.check_three('black'):
return i
self.board = ''
# 阻止玩家三连
for i in range(24):
if self.board == '':
self.board = 'red'
if self.check_three('red'):
self.board = ''
return i
self.board = ''
# 随机选择
empty = == '']
return random.choice(empty)
elif self.state == GameState.MOVE:
# 寻找可移动棋子
moves = []
for src in range(24):
if self.board == 'black':
for dest in self.neighbors:
if self.board == '':
moves.append((src, dest))
# 优先成三的移动
for src, dest in moves:
temp = self.board.copy()
temp = ''
temp = 'black'
if self.check_three('black'):
return (src, dest)
return random.choice(moves) if moves else None
def handle_click(self, pos):
# 修改状态判断逻辑
if self.state is None:# 改为判断state是否为None
for btn in self.buttons:
if btn['visible'] and btn['rect'].collidepoint(pos):
if btn['text'] == "玩家先手":
self.turn = 'red'
self.state = GameState.PLACE
self.hide_buttons()
elif btn['text'] == "电脑先手":
self.turn = 'black'
self.state = GameState.PLACE
self.hide_buttons()
return
# 获取点击位置
for i, (x, y) in enumerate(self.points):
if (pos - x) ** 2 + (pos - y) ** 2 <= 400:
return i
return -1
def hide_buttons(self):
for btn in self.buttons:
btn['visible'] = False
def run(self):
clock = pygame.time.Clock()
ai_delay = 0
ai_remove_target = -1# 新增:记录AI要吃的棋子位置
while True:
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
clicked_point = self.handle_click(pos)
# 玩家吃子处理
if self.state == GameState.REMOVE and self.turn == 'red':
if clicked_point in self.remove_list:
self.board = ''
self.remove_list = []
# 检查是否进入走子阶段
if self.placed['red'] >= 9 and self.placed['black'] >= 9:
self.state = GameState.MOVE
else:
self.state = GameState.PLACE
self.turn = 'black'
ai_delay = 30
# 玩家布子处理
elif self.state == GameState.PLACE and self.turn == 'red':
if clicked_point is not None and self.board == '':
self.board = 'red'
self.placed['red'] += 1
# 检查成三
if self.check_three('red'):
self.remove_list = self.get_removable('red')
if self.remove_list:
self.state = GameState.REMOVE
else:
self.turn = 'black'
ai_delay = 30
self.check_phase()
# AI操作逻辑
if ai_delay > 0:
ai_delay -= 1
elif self.turn == 'black' and self.state != GameState.GAME_OVER:
if self.state == GameState.PLACE:
ai_pos = self.ai_move()
self.board = 'black'
self.placed['black'] += 1
# 检查成三并处理吃子
if self.check_three('black'):
self.remove_list = self.get_removable('black')
if self.remove_list:
self.state = GameState.REMOVE# 进入吃子状态
ai_remove_target = random.choice(self.remove_list)# 记录要吃的棋子
ai_delay = 30# 显示1秒后再吃子
else:
self.turn = 'red'
self.check_phase()
# 处理AI吃子延迟显示
if self.state == GameState.REMOVE and ai_delay == 15 and ai_remove_target != -1:
self.state = GameState.PLACE# 恢复布子状态
self.board = ''
self.remove_list = []
ai_remove_target = -1
self.turn = 'red'
self.check_phase()
elif self.state == GameState.MOVE:
move = self.ai_move()
if move:
src, dest = move
self.board = ''
self.board = 'black'
#self.move_count += 1
if self.check_three('black'):
self.remove_list = self.get_removable('black')
if self.remove_list:
self.state = GameState.REMOVE
self.move_count = 0
self.turn = 'red'
self.winner = self.check_win()
if self.winner:
self.state = GameState.GAME_OVER
# 绘制时显示AI将要吃的棋子
if ai_remove_target != -1:
pygame.draw.circle(screen, YELLOW, self.points, 30, 5)
# 在AI操作后添加阶段检查
if self.state == GameState.PLACE:
self.check_phase()# 每次操作后检查阶段转换
# 胜利检查(只在走子阶段)
if self.state == GameState.MOVE:
self.winner = self.check_win()
if self.winner:
self.state = GameState.GAME_OVER
# 绘制界面
self.draw_board()
if self.state == GameState.GAME_OVER:
self.draw_game_over()
pygame.display.flip()
clock.tick(30)
def draw_game_over(self):
if self.winner:
text = big_font.render(f"{self.winner.upper()}方胜利!",
True, RED if self.winner == 'red' else BLACK)
screen.blit(text, (WIDTH // 2 - 100, HEIGHT // 2))
if __name__ == "__main__":
game = Game()
game.run() 成三棋代码问题分析与修复建议
你提供的代码存在大量语法错误和未完成的部分,导致无法正常运行。以下是主要问题的简要总结和修复建议:
[*]语法错误和缺失内容:如 self.board = * 24、self.radius = 、points = 等,明显是未完成的代码。
[*]列表、字典、函数体不完整:如 self.remove_list = 、self.buttons = 、return , , , , 等。
[*]AI逻辑不完整:如 moves = 、empty = == '' 等。
[*]点击处理逻辑混乱:如 (pos - x) ** 2 + (pos - y) ** 2 = 9 是错误的语法。
[*]缺少主循环函数 run():主程序中调用了 game.run(),但类中并未定义该方法。
建议的修复步骤
[*]补全棋盘点位计算:使用三层正方形的角点和边中点,生成24个点。
[*]补全棋盘连接线和邻接点定义:用于判断成三和走子合法性。
[*]修复AI逻辑:确保AI能在布子和走子阶段做出合理决策。
[*]完善状态管理:如布子、走子、吃子、胜负判断等。
[*]添加主循环函数 run():处理事件、更新界面、控制帧率。
示例:修复棋盘点位初始化
self.radius =
points = []
for r in self.radius:
cx, cy = self.center
square = [
(cx - r, cy - r), (cx, cy - r), (cx + r, cy - r),
(cx + r, cy), (cx + r, cy + r), (cx, cy + r),
(cx - r, cy + r), (cx - r, cy)
]
points.extend(square)
self.points = points
建议下一步
你可以先将代码中明显的语法错误和未完成部分补全,我可以协助你逐步调试和完善每个模块。如果你希望我直接提供一个可运行的简化版本,也可以告诉我,我会为你生成完整代码。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 @FishC,请生成完整代码。 ydwb 发表于 2025-03-30 08:01
@FishC,请生成完整代码。
完整可运行的成三棋(Nine Men's Morris)游戏代码(Pygame实现)
以下是一个简化但完整的成三棋游戏实现,支持人机对战、布子、走子、成三吃子等基本功能。你可以在此基础上继续扩展功能。
python
import pygame
import sys
import random
from enum import Enum
pygame.init()
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
GREEN = (0, 255, 0)
BOARD_COLOR = (245, 222, 179)
# 屏幕设置
WIDTH, HEIGHT = 800, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("成三棋")
font = pygame.font.SysFont('simhei', 24)
class GameState(Enum):
SELECT = 0
PLACE = 1
MOVE = 2
REMOVE = 3
GAME_OVER = 4
class Game:
def __init__(self):
self.center = (WIDTH // 2, HEIGHT // 2)
self.radius =
self.points = self.calculate_points()
self.lines = self.get_lines()
self.neighbors = self.get_neighbors()
self.board = [''] * 24
self.placed = {'red': 0, 'black': 0}
self.turn = 'red'
self.state = GameState.SELECT
self.selected = -1
self.remove_list = []
self.winner = None
self.ai_delay = 0
self.ai_remove_target = -1
def calculate_points(self):
cx, cy = self.center
points = []
for r in self.radius:
points.extend([
(cx - r, cy - r), (cx, cy - r), (cx + r, cy - r),
(cx + r, cy), (cx + r, cy + r), (cx, cy + r),
(cx - r, cy + r), (cx - r, cy)
])
return points
def get_lines(self):
return [
, , , ,
, , , ,
, , , ,
, , , ,
, , ,
]
def get_neighbors(self):
return [
, , , , ,
, , ,
, , , ,
, , , ,
, , , ,
, , ,
]
def draw_board(self):
screen.fill(BOARD_COLOR)
for r in self.radius:
rect = pygame.Rect(self.center - r, self.center - r, 2 * r, 2 * r)
pygame.draw.rect(screen, BLACK, rect, 2)
for i in :
pygame.draw.line(screen, BLACK, self.points, self.points, 2)
for i, pos in enumerate(self.points):
if self.board == 'red':
pygame.draw.circle(screen, RED, pos, 20)
elif self.board == 'black':
pygame.draw.circle(screen, BLACK, pos, 20)
else:
pygame.draw.circle(screen, WHITE, pos, 5)
if self.selected != -1:
pygame.draw.circle(screen, GREEN, self.points, 25, 3)
for i in self.remove_list:
pygame.draw.circle(screen, YELLOW, self.points, 25, 3)
if self.winner:
text = font.render(f"{self.winner.upper()}方胜利!", True, RED if self.winner == 'red' else BLACK)
screen.blit(text, (WIDTH // 2 - 100, 30))
else:
text = font.render(f"当前阶段: {self.state.name} - {self.turn}方", True, BLACK)
screen.blit(text, (20, 20))
def check_three(self, player):
for line in self.lines:
if all(self.board == player for i in line):
return True
return False
def get_removable(self, attacker):
defender = 'black' if attacker == 'red' else 'red'
removable = []
for i in range(24):
if self.board == defender:
if not any(all(self.board == defender for j in line) for line in self.lines if i in line):
removable.append(i)
if not removable:
removable = == defender]
return removable
def check_win(self):
red = self.board.count('red')
black = self.board.count('black')
if red < 3:
return 'black'
if black < 3:
return 'red'
return None
def ai_place(self):
for i in range(24):
if self.board == '':
self.board = 'black'
if self.check_three('black'):
return i
self.board = ''
empty = == '']
return random.choice(empty)
def ai_remove(self):
if self.remove_list:
return random.choice(self.remove_list)
return -1
def handle_click(self, pos):
if self.state == GameState.SELECT:
self.state = GameState.PLACE
return
for i, (x, y) in enumerate(self.points):
if (pos - x) ** 2 + (pos - y) ** 2 <= 400:
if self.state == GameState.PLACE and self.turn == 'red':
if self.board == '':
self.board = 'red'
self.placed['red'] += 1
if self.check_three('red'):
self.remove_list = self.get_removable('red')
self.state = GameState.REMOVE
else:
self.turn = 'black'
elif self.state == GameState.REMOVE and self.turn == 'red':
if i in self.remove_list:
self.board = ''
self.remove_list = []
self.turn = 'black'
self.state = GameState.PLACE
break
def update_ai(self):
if self.turn == 'black':
if self.state == GameState.PLACE:
i = self.ai_place()
self.board = 'black'
self.placed['black'] += 1
if self.check_three('black'):
self.remove_list = self.get_removable('black')
self.state = GameState.REMOVE
else:
self.turn = 'red'
elif self.state == GameState.REMOVE:
i = self.ai_remove()
if i != -1:
self.board = ''
self.remove_list = []
self.turn = 'red'
self.state = GameState.PLACE
self.winner = self.check_win()
if self.winner:
self.state = GameState.GAME_OVER
def run(self):
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN and self.turn == 'red':
self.handle_click(event.pos)
self.update_ai()
self.draw_board()
pygame.display.flip()
clock.tick(30)
if __name__ == "__main__":
Game().run()
说明:
[*]支持红方玩家 vs 黑方 AI。
[*]实现了布子、成三吃子、胜负判断。
[*]未实现走子阶段(MOVE),你可以在此基础上继续扩展。
[*]点击任意位置开始游戏。
如需我继续添加“走子阶段”或“开山”等高级规则,请继续提问!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 PyGame…
最好的Python游戏系统
好久没看到PyGame写的东西了
页:
[1]