1. 实现效果

Python五子棋小游戏


2. 游戏规则

规则说明,五子棋人机对战游戏规则如下:‌

Ⅰ 默认规则 – 五子棋规则

  • 对局双方‌:各执一色棋子,一方持黑色棋子,另一方持白色棋子。
  • 棋盘与开局‌:空棋盘开局,黑先、白后,交替下子,每次只能下一子。
  • 棋子落点‌:棋子下在棋盘的空白点上,下定后不得向其它点移动,也不得从棋盘上拿掉或拿起另落别处。
  • 黑方首子‌:黑方的第一枚棋子可下在棋盘任意交叉点上。
  • 轮流下子‌:轮流下子是双方的权利。
  • Ⅱ 设定规则

  • 双方(用户与程序)分别使用黑白两色的棋子,设定为玩家执黑,先下第一颗,程序执白。
  • 棋盘设为常规的15道盘,即15×15的方格。
  • 下在棋盘直线与横线的交叉点上,先形成五子连珠者获胜。
  • Ⅲ 其他规则

  • 高亮规则:动态高亮显示最新落子,便于观察程序上一步落在何处。
  • 防守机制:检查对方是否可以形成三子或四子
  • 获胜后不要退出窗口,而是停留,不然不知道怎么输的😂
  • 细节:1. 棋盘格外围边框加粗且为深色,棋盘格框线变细,高亮框线变细 2.一旦有一方赢就无法再落子了(主要是白子会在黑子赢了之后还落子) 3. 判平局 4. 棋子下在格线交叉点,而非格内。

  • 3. 环境配置

    程序中会用到的库:

    import sys
    import random
    import pygame
    

    其中sys库和random是python的内置库,不需要安装,pygame是三方库,需要安装。
    先安装 pygame,如果还没有安装,可以使用以下命令:

    pip install pygame
    

    4. 代码实现

    变量说明

    # 常量定义
    BOARD_SIZE = 15 					# 棋盘是15×15
    CELL_SIZE = 40 						# 每个棋格的大小
    WIDTH = BOARD_SIZE * CELL_SIZE		# 棋盘的大小 宽 = 15×40
    HEIGHT = 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 None
    
    def 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 pygame
    import sys
    import random
    
    # 常量定义
    BOARD_SIZE = 15
    CELL_SIZE = 40
    WIDTH = BOARD_SIZE * CELL_SIZE
    HEIGHT = BOARD_SIZE * CELL_SIZE
    BACKGROUND_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 = 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)
                # 在每个格子内绘制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 False
    
    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 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_defensive_move(board):
        # 检查对方是否可以形成三子或四子
        for position in check_threats(board, BLACK):
            return position  # 返回防守位置
        return None
    
    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 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()
    

    作者:镜花照无眠

    物联沃分享整理
    物联沃-IOTWORD物联网 » python 五子棋小游戏

    发表回复