You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pygame开发Connect4:结束条件与获胜信息显示异常

Connect4游戏胜负结果显示问题修复

问题描述

用Pygame开发Connect4游戏,除胜负结果显示外其余功能正常。定义了winner变量,取值为None、y、r或draw;c4rules.py中的checkWin函数可根据棋盘状态返回对应结果,通过逻辑更新winner = rules.checkWin(board.returnBoard())。期望winner不为None时显示获胜横幅,但该功能失效。

测试代码:

if (rules.checkWin(board.returnBoard()) != None):
   run = False

程序能在分出胜负时关闭,但自定义结果显示无反应,不确定是winner未更新还是showWinner的blit操作失效。

问题根源

  1. 绘制顺序错误:showWinner()仅在鼠标松开事件中调用,且主循环每次都会先执行drawBoard()和dropPieces(),这两个函数会重新绘制背景和棋子,直接覆盖掉横幅。
  2. 游戏状态未锁定:分出胜负后未阻止玩家继续落子,导致状态被干扰。
  3. 横幅位置/尺寸不合理:原代码中横幅的坐标和尺寸可能导致显示区域偏移或被遮挡。

修复方案

  1. 调整绘制顺序:将showWinner()移到主循环的dropPieces()之后,确保每次循环都能绘制横幅(如果有结果)。
  2. 锁定游戏状态:当winner不为None时,禁止玩家进行落子操作。
  3. 优化横幅显示:调整横幅的位置和尺寸,确保文字完全显示。

修改后的完整代码

主程序文件

import pygame
from pygame.locals import *
from c4board import *
from c4rules import *

pygame.init()

width = 700
height = 600
font = pygame.font.SysFont(None, 40)
screen= pygame.display.set_mode((width, height))
pygame.display.set_caption("Connect 4")

yellow = (255, 255, 0)
red = (255, 0, 0)
green = (0, 255, 0)
black = (0, 0, 0)

run = True
clicked = False
pos = []
player = "y"
winner = None

board = c4board()
rules = c4rules()

def drawBoard():
    background_color = (255, 255, 255)
    line_col = black
    screen.fill(background_color)
    for col in range(0, 7):
        pygame.draw.line(screen, line_col, (col * 100, 0), (col * 100, height), 2)
    for row in range(0, 6):
        pygame.draw.line(screen, line_col, (0, row * 100), (width, row * 100), 2)

def dropPieces():
    temp = board.returnBoard()
    for r in range(len(temp)):
        for c in range(len(temp[r])):
            if (temp[r][c] == "y"):
                pygame.draw.circle(screen, yellow, (c * 100 + 50, r * 100 + 50), 38, 0)
            if (temp[r][c] == "r"):
                pygame.draw.circle(screen, red, (c * 100 + 50, r * 100 + 50), 38, 0)

def showWinner():
    if winner is None:
        return  # 无结果时不绘制
    
    result = ""
    if winner == "draw":
        result = "Draw!"
    elif winner == "y":
        result = "Yellow Pieces Win!"
    elif winner == "r":
        result = "Red Pieces Win!"
    
    # 渲染文字,用黑色避免和绿色背景冲突
    result_img = font.render(result, True, black)
    # 获取文字尺寸,调整横幅大小适配文字
    text_rect = result_img.get_rect()
    banner_width = text_rect.width + 20
    banner_height = text_rect.height + 10
    # 居中显示横幅
    banner_x = width // 2 - banner_width // 2
    banner_y = height // 2 - banner_height // 2
    
    pygame.draw.rect(screen, green, (banner_x, banner_y, banner_width, banner_height))
    screen.blit(result_img, (banner_x + 10, banner_y + 5))

while run:
    drawBoard()
    dropPieces()
    
    # 每次循环都检查并绘制结果
    showWinner()
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        
        # 有结果时禁止操作
        if winner is not None:
            continue
        
        if event.type == pygame.MOUSEBUTTONDOWN and not clicked:
            clicked = True
        if event.type == pygame.MOUSEBUTTONUP and clicked:
            clicked = False
            pos = pygame.mouse.get_pos()
            col = pos[0] // 100
            if board.freeCol(col):
                board.playerMove(player, col)
                # 切换玩家
                player = "r" if player == "y" else "y"
                # 更新胜负状态
                winner = rules.checkWin(board.returnBoard())
            
    pygame.display.update()

pygame.quit()

c4board.py(保留原代码)

import pygame

#c4board class
class c4board:
    def __init__(self):
        self.board = [[None, None, None, None, None, None, None],
                      [None, None, None, None, None, None, None],
                      [None, None, None, None, None, None, None],
                      [None, None, None, None, None, None, None],
                      [None, None, None, None, None, None, None],
                      [None, None, None, None, None, None, None],]
        
    def returnBoard(self):
        return self.board
        
    def playerMove(self, player, col):
        valid = False
        if (self.freeCol(col) == True):
            while (valid == False):
                first = True
                for r in reversed(range(len(self.board))):
                    if (self.board[r][col] == None):
                        if (first == True):
                            self.board[r][col] = player
                            first = False
                            valid = True
        return
    
    def freeCol(self, col): #checks if column is full
        if (self.board[0][col] != None):
            return False
        else:
            return True

c4rules.py(优化逻辑可读性)

import pygame
#c4rules class
class c4rules:
    def __init__(self):
        pass
    def checkWin(self, board):
        full_board = True
        winner = None
        switched = [[None]*6 for _ in range(7)]
        for r in range(len(switched)): # 转置棋盘,检查竖列四子连
            for c in range(len(switched[r])):
                switched[r][c] = board[c][r]

        # 检查棋盘是否已满
        for row in board:
            if None in row:
                full_board = False
                break
                    
        # 检查横向四子连
        for row in board:
            win_result = self.across_win(row)
            if win_result is not None:
                return win_result
            # 检查对角线四子连
            for c in range(len(row)):
                diag_result = self.diag_win(board, board.index(row), c)
                if diag_result is not None:
                    return diag_result
        # 检查竖列四子连
        for col in switched:
            win_result = self.across_win(col)
            if win_result is not None:
                return win_result
            
        if full_board and winner is None:
            return "draw"
        
        return None
        


    def across_win(self, row, counter = 0, current_winner = ""):
        if counter == 4:
            return current_winner
        if not row:
            return None
        if counter == 0:
            if row[0] is not None:
                current_winner = row[0]
                counter = 1
            return self.across_win(row[1:], counter, current_winner)
        else:
            if row[0] == current_winner:
                counter += 1
                return self.across_win(row[1:], counter, current_winner)
            else:
                if row[0] is not None:
                    return self.across_win(row[1:], 1, row[0])
                else:
                    return self.across_win(row[1:], 0, "")

    def diag_win(self, board, r, c):
        # 右下对角线
        if r < 3 and c < 4:
            if board[r][c] is not None:
                if board[r][c] == board[r+1][c+1] == board[r+2][c+2] == board[r+3][c+3]:
                    return board[r][c]
        # 左下对角线
        if r < 3 and c > 2:
            if board[r][c] is not None:
                if board[r][c] == board[r+1][c-1] == board[r+2][c-2] == board[r+3][c-3]:
                    return board[r][c]
        return None

内容的提问来源于stack exchange,提问作者soapeater

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:17:40