1. 实现效果
Python五子棋小游戏
2. 游戏规则
规则说明,五子棋人机对战游戏规则如下:
Ⅰ 默认规则 - 五子棋规则
对局双方:各执一色棋子,一方持黑色棋子,另一方持白色棋子。棋盘与开局:空棋盘开局,黑先、白后,交替下子,每次只能下一子。棋子落点:棋子下在棋盘的空白点上,下定后不得向其它点移动,也不得从棋盘上拿掉或拿起另落别处。黑方首子:黑方的第一枚棋子可下在棋盘任意交叉点上。轮流下子:轮流下子是双方的权利。Ⅱ 设定规则
双方(用户与程序)分别使用黑白两色的棋子,设定为玩家执黑,先下第一颗,程序执白。棋盘设为常规的15道盘,即15×15的方格。下在棋盘直线与横线的交叉点上,先形成五子连珠者获胜。Ⅲ 其他规则
高亮规则:动态高亮显示最新落子,便于观察程序上一步落在何处。防守机制:检查对方是否可以形成三子或四子获胜后不要退出窗口,而是停留,不然不知道怎么输的?细节:1. 棋盘格外围边框加粗且为深色,棋盘格框线变细,高亮框线变细 2.一旦有一方赢就无法再落子了(主要是白子会在黑子赢了之后还落子) 3. 判平局 4. 棋子下在格线交叉点,而非格内。3. 环境配置
程序中会用到的库:
import sysimport randomimport pygame
其中sys库和random是python的内置库,不需要安装,pygame是三方库,需要安装。
先安装 pygame,如果还没有安装,可以使用以下命令:
pip install pygame
4. 代码实现
变量说明
# 常量定义BOARD_SIZE = 15 # 棋盘是15×15CELL_SIZE = 40 # 每个棋格的大小WIDTH = BOARD_SIZE * CELL_SIZE# 棋盘的大小 宽 = 15×40HEIGHT = BOARD_SIZE * CELL_SIZE # 棋盘高度BACKGROUND_COLOR = (250, 224, 161) # 棋盘的背景色GRID_COLOR = (0, 0, 0)# 棋盘格线 调成(200, 200, 200)会很好看HIGHLIGHT_COLOR = (255, 182, 193) # 高亮颜色, 粉色BORDER_COLOR = (139, 69, 19) # 棋盘外围边框颜色# 棋盘状态EMPTY = 0 # 未落子BLACK = 1 # 落黑子WHITE = 2 # 落白子
棋盘绘制
画棋盘、棋格、棋子、高亮框框、高亮圈圈
def draw_board(screen, board, last_move): screen.fill(BACKGROUND_COLOR) for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE) pygame.draw.rect(screen, GRID_COLOR, rect, 1) if board[x][y] == BLACK: pygame.draw.circle(screen, (0, 0, 0), rect.center, CELL_SIZE // 2 - 5) elif board[x][y] == WHITE: pygame.draw.circle(screen, (255, 255, 255), rect.center, CELL_SIZE // 2 - 5) if last_move: # row, col = latest_move # 方形高亮 棋格 highlight_rect = pygame.Rect(last_move[0] * CELL_SIZE, last_move[1] * CELL_SIZE, CELL_SIZE, CELL_SIZE) pygame.draw.rect(screen, HIGHLIGHT_COLOR, highlight_rect, 2) # 圆形高亮 棋子 highlight_center = (last_move[0] * CELL_SIZE + CELL_SIZE // 2, last_move[1] * CELL_SIZE + CELL_SIZE // 2) highlight_radius = CELL_SIZE // 2 - 5 # 与棋子相同的半径 pygame.draw.circle(screen, HIGHLIGHT_COLOR, highlight_center, highlight_radius+1.5, 2) # 用圆形高亮, 1.5是为了补偿高亮,高亮是2 pygame.draw.rect(screen, BORDER_COLOR, (0, 0, CELL_SIZE * BOARD_SIZE, CELL_SIZE * BOARD_SIZE), 5)# 绘制边框
判断赢家
在任意方达到五子的时候,判断赢了
def check_winner(board, player): for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == player: # 检查水平方向 if x + 4 < BOARD_SIZE and all(board[x + i][y] == player for i in range(5)): return True # 检查垂直方向 if y + 4 < BOARD_SIZE and all(board[x][y + i] == player for i in range(5)): return True # 检查斜向(左上到右下) if x + 4 < BOARD_SIZE and y + 4 < BOARD_SIZE and all(board[x + i][y + i] == player for i in range(5)): return True # 检查斜向(右上到左下) if x - 4 >= 0 and y + 4 < BOARD_SIZE and all(board[x - i][y + i] == player for i in range(5)): return True return False
程序落子(随机)
一开始纯随机,棋子分布散乱,很容易白子就输了,没有难度和趣味性。后来程序才加策略,提高白子获胜率。
def get_random_move(board): empty_cells = [(x, y) for x in range(BOARD_SIZE) for y in range(BOARD_SIZE) if board[x][y] == EMPTY] return random.choice(empty_cells) if empty_cells else None
防御机制
程序检测玩家连续棋子的数量是否对自身存在威胁性。
def check_threats(board, player): three_in_a_row_positions = [] for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == EMPTY: board[x][y] = player # 模拟落子 if check_winner(board, player): board[x][y] = EMPTY return [(x, y)] # 直接获胜 # 检测是否出现三子的情况 if count_consecutive(board, x, y, player) == 3: three_in_a_row_positions.append((x, y)) board[x][y] = EMPTY return three_in_a_row_positions def get_defensive_move(board): # 检查对方是否可以形成三子或四子 for position in check_threats(board, BLACK): return position # 返回防守位置 return Nonedef count_consecutive(board, x, y, player): # 检查周围的棋子数量 count = 0 for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (1, 1), (-1, 1), (1, -1)]: temp_count = 0 for step in range(1, 5): # 只检测四个方向 nx, ny = x + dx * step, y + dy * step if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and board[nx][ny] == player: temp_count += 1 else: break count += temp_count return count
追踪策略
为了便于堵截玩家,提高难度。
def get_preferred_move(board): preferred_moves = [] for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == EMPTY: # 优先选择靠近黑子的位置 for dx in [-1, 0, 1]: for dy in [-1, 0, 1]: nx, ny = x + dx, y + dy if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and board[nx][ny] == BLACK: preferred_moves.append((x, y)) break return random.choice(preferred_moves) if preferred_moves else get_random_move(board)
主函数
def main(): pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("五子棋") game_over = False # 游戏是否结束 board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)] last_move = None while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if game_over: continue # 如果游戏结束,不处理任何落子 # 检查是否平局 if all(board[x][y] != EMPTY for x in range(BOARD_SIZE) for y in range(BOARD_SIZE)): game_over = True print("游戏平局!") if event.type == pygame.MOUSEBUTTONDOWN: x, y = event.pos x //= CELL_SIZE y //= CELL_SIZE if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and board[x][y] == EMPTY: board[x][y] = BLACK last_move = (x, y) if check_winner(board, BLACK): game_over = True print("黑方获胜!") #pygame.quit() #sys.exit() # 白方落子 if not game_over and not (all(board[x][y] != EMPTY for x in range(BOARD_SIZE) for y in range(BOARD_SIZE))): move = get_defensive_move(board) if move is None: # 若没有可防守的位置,落子 move = get_preferred_move(board) board[move[0]][move[1]] = WHITE last_move = move if check_winner(board, WHITE): game_over = True print("白方获胜!") # pygame.quit() # sys.exit() draw_board(screen, board, last_move) pygame.display.flip() pygame.quit()
完整代码
import pygameimport sysimport random# 常量定义BOARD_SIZE = 15CELL_SIZE = 40WIDTH = BOARD_SIZE * CELL_SIZEHEIGHT = BOARD_SIZE * CELL_SIZEBACKGROUND_COLOR = (250, 224, 161)GRID_COLOR = (245, 245, 220) #GRID_COLOR = (0, 0, 0)FADED_GRID_COLOR = (200, 200, 200) # 使用一个更亮的颜色来模仿淡化效果 淡化的格线颜色 (220, 220, 220)HIGHLIGHT_COLOR = (255, 182, 193) # 粉色高亮颜色BORDER_COLOR = (139, 69, 19) # 边框颜色# 棋盘状态EMPTY = 0BLACK = 1WHITE = 2def draw_board(screen, board, last_move): screen.fill(BACKGROUND_COLOR) for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE) pygame.draw.rect(screen, GRID_COLOR, rect, 1) # 在每个格子内绘制2份纵横线 for i in range(1, 2): # 横线 pygame.draw.line(screen, FADED_GRID_COLOR, (x * CELL_SIZE, y * CELL_SIZE + i * (CELL_SIZE // 2)), (x * CELL_SIZE + CELL_SIZE, y * CELL_SIZE + i * (CELL_SIZE // 2)), 1) # 竖线 pygame.draw.line(screen, FADED_GRID_COLOR, (x * CELL_SIZE + i * (CELL_SIZE // 2), y * CELL_SIZE), (x * CELL_SIZE + i * (CELL_SIZE // 2), y * CELL_SIZE + CELL_SIZE), 1) # 绘制交叉点 pygame.draw.circle(screen, (0, 0, 0), (x * CELL_SIZE + CELL_SIZE - CELL_SIZE/2, y * CELL_SIZE + CELL_SIZE - CELL_SIZE/2), 2) # 使用半径为2的圆点 if board[x][y] == BLACK: pygame.draw.circle(screen, (0, 0, 0), rect.center, CELL_SIZE // 2 - 5) elif board[x][y] == WHITE: pygame.draw.circle(screen, (255, 255, 255), rect.center, CELL_SIZE // 2 - 5) if last_move: # row, col = latest_move # 方形高亮 棋格 highlight_rect = pygame.Rect(last_move[0] * CELL_SIZE, last_move[1] * CELL_SIZE, CELL_SIZE, CELL_SIZE) pygame.draw.rect(screen, HIGHLIGHT_COLOR, highlight_rect, 2) # 圆形高亮 棋子 highlight_center = (last_move[0] * CELL_SIZE + CELL_SIZE // 2, last_move[1] * CELL_SIZE + CELL_SIZE // 2) highlight_radius = CELL_SIZE // 2 - 5 # 与棋子相同的半径 pygame.draw.circle(screen, HIGHLIGHT_COLOR, highlight_center, highlight_radius+1.5, 2) # 用圆形高亮, 1.5是为了补偿高亮,高亮是2 pygame.draw.rect(screen, BORDER_COLOR, (0, 0, CELL_SIZE * BOARD_SIZE, CELL_SIZE * BOARD_SIZE), 5)# 绘制边框def check_winner(board, player): for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == player: # 检查水平方向 if x + 4 < BOARD_SIZE and all(board[x + i][y] == player for i in range(5)): return True # 检查垂直方向 if y + 4 < BOARD_SIZE and all(board[x][y + i] == player for i in range(5)): return True # 检查斜向(左上到右下) if x + 4 < BOARD_SIZE and y + 4 < BOARD_SIZE and all(board[x + i][y + i] == player for i in range(5)): return True # 检查斜向(右上到左下) if x - 4 >= 0 and y + 4 < BOARD_SIZE and all(board[x - i][y + i] == player for i in range(5)): return True return Falsedef check_threats(board, player): three_in_a_row_positions = [] for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == EMPTY: board[x][y] = player # 模拟落子 if check_winner(board, player): board[x][y] = EMPTY return [(x, y)] # 直接获胜 # 检测是否出现三子的情况 if count_consecutive(board, x, y, player) == 3: three_in_a_row_positions.append((x, y)) board[x][y] = EMPTY return three_in_a_row_positionsdef count_consecutive(board, x, y, player): # 检查周围的棋子数量 count = 0 for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (1, 1), (-1, 1), (1, -1)]: temp_count = 0 for step in range(1, 5): # 只检测四个方向 nx, ny = x + dx * step, y + dy * step if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and board[nx][ny] == player: temp_count += 1 else: break count += temp_count return countdef get_defensive_move(board): # 检查对方是否可以形成三子或四子 for position in check_threats(board, BLACK): return position # 返回防守位置 return Nonedef get_random_move(board): empty_cells = [(x, y) for x in range(BOARD_SIZE) for y in range(BOARD_SIZE) if board[x][y] == EMPTY] return random.choice(empty_cells) if empty_cells else Nonedef get_preferred_move(board): preferred_moves = [] for x in range(BOARD_SIZE): for y in range(BOARD_SIZE): if board[x][y] == EMPTY: # 优先选择靠近黑子的位置 for dx in [-1, 0, 1]: for dy in [-1, 0, 1]: nx, ny = x + dx, y + dy if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and board[nx][ny] == BLACK: preferred_moves.append((x, y)) break return random.choice(preferred_moves) if preferred_moves else get_random_move(board)def main(): pygame.init() screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("五子棋") game_over = False # 游戏是否结束 board = [[EMPTY for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)] last_move = None while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if game_over: continue # 如果游戏结束,不处理任何落子 # 检查是否平局 if all(board[x][y] != EMPTY for x in range(BOARD_SIZE) for y in range(BOARD_SIZE)): game_over = True print("游戏平局!") if event.type == pygame.MOUSEBUTTONDOWN: x, y = event.pos x //= CELL_SIZE y //= CELL_SIZE if 0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE and board[x][y] == EMPTY: board[x][y] = BLACK last_move = (x, y) if check_winner(board, BLACK): game_over = True print("黑方获胜!") #pygame.quit() #sys.exit() # 白方落子 if not game_over and not (all(board[x][y] != EMPTY for x in range(BOARD_SIZE) for y in range(BOARD_SIZE))): move = get_defensive_move(board) if move is None: # 若没有可防守的位置,落子 move = get_preferred_move(board) board[move[0]][move[1]] = WHITE last_move = move if check_winner(board, WHITE): game_over = True print("白方获胜!") # pygame.quit() # sys.exit() draw_board(screen, board, last_move) pygame.display.flip() pygame.quit()if __name__ == "__main__": main()