使用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操作失效。
问题根源
- 绘制顺序错误:
showWinner()仅在鼠标松开事件中调用,且主循环每次都会先执行drawBoard()和dropPieces(),这两个函数会重新绘制背景和棋子,直接覆盖掉横幅。 - 游戏状态未锁定:分出胜负后未阻止玩家继续落子,导致状态被干扰。
- 横幅位置/尺寸不合理:原代码中横幅的坐标和尺寸可能导致显示区域偏移或被遮挡。
修复方案
- 调整绘制顺序:将
showWinner()移到主循环的dropPieces()之后,确保每次循环都能绘制横幅(如果有结果)。 - 锁定游戏状态:当
winner不为None时,禁止玩家进行落子操作。 - 优化横幅显示:调整横幅的位置和尺寸,确保文字完全显示。
修改后的完整代码
主程序文件
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
相关产品推荐
相关产品推荐

