You need to enable JavaScript to run this app. 如何修复Pygame井字棋游戏屏幕运行异常、无法正常执行的问题
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Pygame井字棋游戏屏幕运行异常、无法正常执行的问题

代码问题根源定位
  • 落子操作与棋盘状态完全脱节:鼠标点击仅在屏幕临时绘制X,从未将对应网格位置写入board二维数组,导致胜利检测逻辑永远读不到实际落子数据,无法触发对局结束判断,同时重复点击同一格子会出现多层重叠的X标记。
  • 绘制锚点错误:blit渲染文字时默认将文字表面的左上角对齐传入坐标,而代码传入的是格子中心点,会导致X/O标记偏移到相邻格子,无法正常落在目标区域。
  • 渲染流程缺失清屏步骤:每轮游戏循环没有先填充纯色底色重绘网格,直接在旧画面上叠加绘制按钮和文字,长时间运行后屏幕会因多层内容残留出现模糊、重影。
  • 函数返回值不完整:check_win遍历完所有获胜判定条件后,没有默认返回False的兜底逻辑,可能引发隐性类型判断错误。
  • 对局逻辑缺失:已编写的电脑落子、控制台输入取位置等函数完全没有和Pygame窗口流程适配,既会造成控制台输入和窗口操作的冲突,也无法实现人机交互的完整流程。
修复后可运行代码
import sys, pygame
from pygame.locals import *
import random

def setup_board(width=860, height=640):
    """初始化井字棋棋盘,返回屏幕对象、宽高尺寸"""
    size = width, height
    screen = pygame.display.set_mode(size)
    screen.fill('white')
    # 绘制垂直网格线
    pygame.draw.line(screen, 'black', (width/3, 0), (width/3, height), 3)
    pygame.draw.line(screen, 'black', (2*width/3, 0), (2*width/3, height), 3)
    # 绘制水平网格线
    pygame.draw.line(screen, 'black', (0, height/3), (width, height/3), 3)
    pygame.draw.line(screen, 'black', (0, 2*height/3), (width, 2*height/3), 3)
    return screen, width, height

def get_board_position(x, y):
    """根据鼠标坐标换算对应的棋盘网格行、列,以及单格宽高"""
    dw, dl = 860//3, 640//3
    col = x // dw
    row = y // dl
    # 处理点在窗口边缘的越界情况
    row = min(row, 2)
    col = min(col, 2)
    return int(row), int(col), dw, dl

def get_draw_position(row, col):
    """根据网格行列号换算标记的绘制中心点"""
    dw, dl = 860//3, 640//3
    center_x = col * dw + dw/2
    center_y = row * dl + dl/2
    return center_x, center_y

def get_computer_move(board):
    """电脑获取第一个空闲网格位置"""
    for row in range(3):
        for col in range(3):
            if board[row][col] == '':
                return row, col
    # 无空位时返回None
    return None

def check_win(board, mark):
    """检测指定标记的获胜状态,无获胜时返回False"""
    # 检测行获胜
    for row in range(3):
        if board[row][0] == board[row][1] == board[row][2] == mark:
            return True
    # 检测列获胜
    for col in range(3):
        if board[0][col] == board[1][col] == board[2][col] == mark:
            return True
    # 检测对角线获胜
    if board[0][0] == board[1][1] == board[2][2] == mark:
        return True
    if board[2][0] == board[1][1] == board[0][2] == mark:
        return True
    return False

def check_draw(board):
    """检测是否平局"""
    for row in range(3):
        for col in range(3):
            if board[row][col] == '':
                return False
    return True

# 初始化Pygame基础配置
pygame.init()
pygame.display.set_caption("人机对战井字棋")
font = pygame.font.SysFont('arial', 110)
small_font = pygame.font.SysFont('arial', 30)
screen, width, height = setup_board()
clock = pygame.time.Clock()

# 预渲染标记素材
x_render = font.render("X", False, "blue")
o_render = font.render("O", False, "red")
quit_text = small_font.render("Quit!", False, "red")
# 计算标记的半宽高,实现居中对齐
x_w, x_h = x_render.get_size()
o_w, o_h = o_render.get_size()

# 游戏全局状态
active_game = True
board = [['' ,'', ''], ['', '', ''],['', '', '']]
player_turn = True

while active_game:
    # 每帧重绘干净背景和网格
    screen.fill('white')
    pygame.draw.line(screen, 'black', (width/3, 0), (width/3, height), 3)
    pygame.draw.line(screen, 'black', (2*width/3, 0), (2*width/3, height), 3)
    pygame.draw.line(screen, 'black', (0, height/3), (width, height/3), 3)
    pygame.draw.line(screen, 'black', (0, 2*height/3), (width, 2*height/3), 3)

    # 绘制退出按钮
    quit_rect = pygame.draw.rect(screen, 'gray', (50, 50, 80, 40), 2)
    screen.blit(quit_text, (55, 55))

    # 绘制棋盘上已有的所有标记
    for row in range(3):
        for col in range(3):
            mark = board[row][col]
            center_x, center_y = get_draw_position(row, col)
            if mark == 'X':
                # 居中对齐绘制X
                screen.blit(x_render, (center_x - x_w/2, center_y - x_h/2))
            if mark == 'O':
                # 居中对齐绘制O
                screen.blit(o_render, (center_x - o_w/2, center_y - o_h/2))

    # 事件检测
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == MOUSEBUTTONUP:
            ex, ey = event.pos
            # 退出按钮点击检测
            if quit_rect.collidepoint(ex, ey):
                pygame.quit()
                sys.exit()
            # 玩家回合的落子检测
            if player_turn:
                row, col, _, _ = get_board_position(ex, ey)
                # 仅当目标格子为空时落子
                if board[row][col] == '':
                    board[row][col] = 'X'
                    player_turn = False

    # 电脑自动回合落子
    if not player_turn and active_game:
        pygame.time.wait(500) # 模拟电脑思考延迟
        comp_move = get_computer_move(board)
        if comp_move:
            c_row, c_col = comp_move
            board[c_row][c_col] = 'O'
            player_turn = True

    # 对局结束状态检测
    if check_win(board, 'X'):
        win_text = small_font.render("玩家获胜!", False, "blue")
        screen.blit(win_text, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        active_game = False
    if check_win(board, 'O'):
        win_text = small_font.render("电脑获胜!", False, "red")
        screen.blit(win_text, (300, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        active_game = False
    if check_draw(board):
        draw_text = small_font.render("平局!", False, "green")
        screen.blit(draw_text, (350, 300))
        pygame.display.flip()
        pygame.time.wait(3000)
        active_game = False

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 10:06:00