|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
棋盘为大、中、小三个正方形,小的在中央,中号在小正方形的外围,大号的在中号的外围,三个正方形同方向的一边中点用线段连接。每个正方形的四个角及四条边的中点为布子及走子处。共为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 = [220, 150, 80]
- self.points = self.calculate_points()
- self.lines = self.get_all_lines()
- self.neighbors = self.get_neighbors()
- # 新增check_phase方法
- def check_phase(self):
- """检查是否需要进入走子阶段"""
- if self.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[0] - r, self.center[1] - r), # 左上
- (self.center[0], self.center[1] - r), # 上中
- (self.center[0] + r, self.center[1] - r), # 右上
- (self.center[0] + r, self.center[1]), # 右中
- (self.center[0] + r, self.center[1] + r), # 右下
- (self.center[0], self.center[1] + r), # 下中
- (self.center[0] - r, self.center[1] + r), # 左下
- (self.center[0] - r, self.center[1]) # 左中
- ]
- points.extend(square)
- return points
- def get_all_lines(self):
- return [
- # 外层正方形
- [0, 1, 2], [2, 3, 4], [4, 5, 6], [6, 7, 0],
- # 中层正方形
- [8, 9, 10], [10, 11, 12], [12, 13, 14], [14, 15, 8],
- # 内层正方形
- [16, 17, 18], [18, 19, 20], [20, 21, 22], [22, 23, 16],
- # 垂直线
- [1, 9, 17], [3, 11, 19], [5, 13, 21], [7, 15, 23]
- ]
- def get_neighbors(self):
- # 定义每个点的相邻点
- return [
- [1, 7], [0, 2, 9], [1, 3], [2, 4, 11], [3, 5], [4, 6, 13],
- [5, 7], [0, 6, 15], [9, 15], [8, 10, 17, 1], [9, 11], [10, 12, 19, 3],
- [11, 13], [12, 14, 21, 5], [13, 15], [14, 8, 23, 7], [17, 23],
- [16, 18, 9], [17, 19], [18, 20, 11], [19, 21], [20, 22, 13],
- [21, 23], [22, 16, 15]
- ]
- def draw_board(self):
- screen.fill(BOARD_COLOR)
- # 绘制三个正方形
- for r in self.radius:
- rect = (self.center[0] - r, self.center[1] - r, 2 * r, 2 * r)
- pygame.draw.rect(screen, BLACK, rect, 2)
- # 绘制连接线
- for i in [1, 3, 5, 7]:
- pygame.draw.line(screen, BLACK, self.points[i], self.points[i + 8], 2)
- pygame.draw.line(screen, BLACK, self.points[i], self.points[i + 16], 2)
- # 绘制棋子
- for i, pos in enumerate(self.points):
- if self.board[i] == 'red':
- pygame.draw.circle(screen, RED, pos, 25)
- elif self.board[i] == 'black':
- pygame.draw.circle(screen, BLACK, pos, 25)
- # 绘制选中状态
- if self.selected != -1:
- pygame.draw.circle(screen, GREEN, self.points[self.selected], 20, 3)
- # 绘制可吃子提示
- for i in self.remove_list:
- pygame.draw.circle(screen, YELLOW, self.points[i], 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[i] == 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[i] == defender:
- safe = any(all(self.board[j] == 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[i] == player:
- if any(self.board[n] == '' for n in self.neighbors[i]):
- 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[i] == '':
- self.board[i] = 'black'
- if self.check_three('black'):
- return i
- self.board[i] = ''
- # 阻止玩家三连
- for i in range(24):
- if self.board[i] == '':
- self.board[i] = 'red'
- if self.check_three('red'):
- self.board[i] = ''
- return i
- self.board[i] = ''
- # 随机选择
- empty = [i for i in range(24) if self.board[i] == '']
- return random.choice(empty)
- elif self.state == GameState.MOVE:
- # 寻找可移动棋子
- moves = []
- for src in range(24):
- if self.board[src] == 'black':
- for dest in self.neighbors[src]:
- if self.board[dest] == '':
- moves.append((src, dest))
- # 优先成三的移动
- for src, dest in moves:
- temp = self.board.copy()
- temp[src] = ''
- temp[dest] = '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[0] - x) ** 2 + (pos[1] - 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[clicked_point] = ''
- 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[clicked_point] == '':
- self.board[clicked_point] = '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[ai_pos] = '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[ai_remove_target] = ''
- 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[src] = ''
- self.board[dest] = '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[ai_remove_target], 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()
复制代码 |
|