五、pygame做一个简单的五子棋游戏

1.设置棋盘

五子棋标准棋盘是15x15的,如果我们每个格子的大小是40x40的话,棋盘应该是40x(15-1)=560的宽度,我们在四面各保留60的边距,那么窗口的长宽各是40x(15-1)+60x2

# -*- coding=utf-8 -*-
import random
import pygame
pygame.init()

space = 60 # 四周留下的边距
cell_size = 40 # 每个格子大小
cell_num = 15
grid_size = cell_size * (cell_num - 1) + space * 2 # 棋盘的大小
screencaption = pygame.display.set_caption('FIR')
screen = pygame.display.set_mode((grid_size,grid_size)) #设置窗口长宽

while True:
    for event in pygame.event.get():
         if event.type == pygame.QUIT:
             pygame.quit()
             exit()

    screen.fill((0,0,150)) # 将界面设置为蓝色

    for x in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(x+space,0+space),(x+space,cell_size*(cell_num-1)+space),1)
    for y in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(0+space,y+space),(cell_size*(cell_num-1)+space,y+space),1)
   
    pygame.display.update() # 必须调用update才能看到绘图显示

在这里插入图片描述

2.落子

首先我们定义一个chess_arr数组用于存储落到棋盘上的棋子

chess_arr = []

然后在游戏主循环监听下鼠标弹起事件,然后在捕捉到鼠标弹起事件时获取鼠标位置并把位置添加进chess_arr

for event in pygame.event.get():
        ……
    
         if event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起
             x, y = pygame.mouse.get_pos() # 获取鼠标位置
             chess_arr.append((x,y))

最后我们在pygame.display.update()前将棋子绘制出来看看效果
在这里插入图片描述
可以看到,现在已经能点出棋子了,但是棋子的位置不是纵横线的交叉点,所以我们必须对鼠标位置进行取整,不能把x,y这个位置加的这么随意,处理下x,y位置的代码如下

for event in pygame.event.get():
        ……
         if event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起
             x, y = pygame.mouse.get_pos() # 获取鼠标位置
             xi = int(round((x - space)*1.0/cell_size)) # 获取到x方向上取整的序号
             yi = int(round((y - space)*1.0/cell_size)) # 获取到y方向上取整的序号
             if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num:
                 chess_arr.append((xi*cell_size+space,yi*cell_size+space))

现在发现落子位置靠谱多了
在这里插入图片描述
为了代码的可读性更好点,以后一些棋盘计算更方便,我们把放入chess_arr数组的绝对坐标改成放入的是格子的序号,也就是把

 chess_arr.append((xi*cell_size+space,yi*cell_size+space))

改成

chess_arr.append((xi,yi))

然后在画棋子的地方也稍作修改,把

pygame.draw.circle(screen,(205,205,205), [x, y], 16,16)

改成

pygame.draw.circle(screen,(205,205,205), [x*cell_size+space, y*cell_size+space], 16,16)

接下来还有个问题,因为进到chess_arr数组前并没有判断某一位置是否已经有棋子,存在重复落子的情况,所以这边还要多加个判断,因为python语言够强大,可以直接判断是否包含tuple或者数组,所以只要多加一个(xi,yi) not in chess_arr的判断就好了,开不开森~

    for event in pygame.event.get():
         ……
         if event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起
             ……
             if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num and (xi,yi) not in chess_arr:
                     chess_arr.append((xi,yi))

为免代码偏差,先更新下目前的完整代码

# -*- coding=utf-8 -*-
import random
import pygame
from pygame.locals import MOUSEBUTTONUP
pygame.init()

space = 60 # 四周留下的边距
cell_size = 40 # 每个格子大小
cell_num = 15
grid_size = cell_size * (cell_num - 1) + space * 2 # 棋盘的大小
screencaption = pygame.display.set_caption('FIR')
screen = pygame.display.set_mode((grid_size,grid_size)) #设置窗口长宽

chess_arr = []

while True:
    for event in pygame.event.get():
         if event.type == pygame.QUIT:
             pygame.quit()
             exit()
    
         if event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起
             x, y = pygame.mouse.get_pos() # 获取鼠标位置
             xi = int(round((x - space)*1.0/cell_size)) # 获取到x方向上取整的序号
             yi = int(round((y - space)*1.0/cell_size)) # 获取到y方向上取整的序号
             if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num and (xi,yi) not in chess_arr:
                 chess_arr.append((xi,yi))

    screen.fill((0,0,150)) # 将界面设置为蓝色

    for x in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(x+space,0+space),(x+space,cell_size*(cell_num-1)+space),1)
    for y in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(0+space,y+space),(cell_size*(cell_num-1)+space,y+space),1)

    for x, y in chess_arr:
        pygame.draw.circle(screen,(205,205,205), [x*cell_size+space, y*cell_size+space], 16,16)

    pygame.display.update() # 必须调用update才能看到绘图显示

3.区分黑白子

这里常规的想法可能有这么两种:1.chess_arr理论应该是黑白相间的,一个隔一个不同颜色画就好了(这种在不考虑正规比赛五手两打或者让子的情况下是没问题的) 2.往chess_arr里填(x,y)时多填一个黑白标记改成(x,y,flag) ,这里我们选择第二种方案
首先,我们全局定义个flag变量

flag = 1 # 1黑 2白

我们把

if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num and (xi,yi) not in chess_arr:
                 chess_arr.append((xi,yi))

这里改成

if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num and (xi,yi,1) not in chess_arr and (xi,yi,2) not in chess_arr:
                 chess_arr.append((xi,yi,flag))
                 flag = 2 if flag == 1 else 2

再把画棋的

for x, y in chess_arr:
        pygame.draw.circle(screen,(205,205,205), [x*cell_size+space, y*cell_size+space], 16,16)

改成

for x, y, c in chess_arr:
        chess_color = (30,30,30) if c == 1 else (225,225,225)
        pygame.draw.circle(screen, chess_color, [x*cell_size+space, y*cell_size+space], 16,16)

在这里插入图片描述
现在看起来有点像那么回事了

4.判断输赢

判断输赢的关键当然还是使用chess_arr这个数组,这个数组用来判断胜利并不太方便,我们把它转一个15*15的二维数组来计算,转换代码如下

m = [[0]*15 for i in range(15)] # 先定义一个15*15的全0数组
for x, y, c in chess_arr:
    m[y][x] = 1 # 上面有棋则标1

我们把这代码一起放到一个check_win(chess_arr, flag)函数里,用于判断某一方是否胜利,基本流程是分别判断最后一颗落下的子的横线、竖线、斜线上是不是有5个以上子,有则返回True,函数代码如下:

def get_one_dire_num(lx, ly, dx, dy, m):
    tx = lx
    ty = ly
    s = 0
    while True:
        tx += dx
        ty += dy
        if tx < 0 or tx >= cell_num or ty < 0 or ty >= cell_num or m[ty][tx] == 0: return s
        s+=1

def check_win(chess_arr, flag):
    m = [[0]*cell_num for i in range(cell_num)] # 先定义一个15*15的全0的数组,不能用[[0]*cell_num]*cell_num的方式去定义因为一位数组会被重复引用
    for x, y, c in chess_arr:
        if c == flag:
            m[y][x] = 1 # 上面有棋则标1
    lx = chess_arr[-1][0] # 最后一个子的x
    ly = chess_arr[-1][1] # 最后一个子的y
    dire_arr = [[(-1,0),(1,0)],[(0,-1),(0,1)],[(-1,-1),(1,1)],[(-1,1),(1,-1)]] # 4个方向数组,往左+往右、往上+往下、往左上+往右下、往左下+往右上,4组判断方向
    
    for dire1,dire2 in dire_arr:
        dx, dy = dire1
        num1 = get_one_dire_num(lx, ly, dx, dy, m)
        dx, dy = dire2
        num2 = get_one_dire_num(lx, ly, dx, dy, m)
        if num1 + num2 + 1 >= 5: return True

    return False

判断函数完成了,我们再定一个全局变量用于保存游戏状态

game_state = 1 # 游戏状态1.表示正常进行 2.表示黑胜 3.表示白胜

我们在鼠标添加棋子的代码后面做下修改,调用判断胜利的函数

                 if check_win(chess_arr, flag):
                     game_state = 2 if flag == 1 else 3
                 else:
                     flag = 2 if flag == 1 else 1

最后在pygame.display.update()前加个游戏状态判断,用于显示获胜文字

    if game_state != 1:
        myfont = pygame.font.Font(None,60)
        white = 210,210,0
        win_text = "%s win"%('black' if game_state == 2 else 'white')
        textImage = myfont.render(win_text, True, white)
        screen.blit(textImage, (260,320))

另外,鼠标事件判断处也要做下修改,判断下游戏状态是不是游戏中

if game_state == 1 and event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起

至此主要的代码都完整了,下面是效果图
在这里插入图片描述
最后贴下完整程序,这边没有做禁手的判断和判输,后面有时间再处理

# -*- coding=utf-8 -*-
import random
import pygame
from pygame.locals import MOUSEBUTTONUP
pygame.init()

space = 60 # 四周留下的边距
cell_size = 40 # 每个格子大小
cell_num = 15
grid_size = cell_size * (cell_num - 1) + space * 2 # 棋盘的大小
screencaption = pygame.display.set_caption('FIR')
screen = pygame.display.set_mode((grid_size,grid_size)) #设置窗口长宽

chess_arr = []
flag = 1 # 1黑 2白
game_state = 1 # 游戏状态1.表示正常进行 2.表示黑胜 3.表示白胜

def get_one_dire_num(lx, ly, dx, dy, m):
    tx = lx
    ty = ly
    s = 0
    while True:
        tx += dx
        ty += dy
        if tx < 0 or tx >= cell_num or ty < 0 or ty >= cell_num or m[ty][tx] == 0: return s
        s+=1

def check_win(chess_arr, flag):
    m = [[0]*cell_num for i in range(cell_num)] # 先定义一个15*15的全0的数组,不能用[[0]*cell_num]*cell_num的方式去定义因为一位数组会被重复引用
    for x, y, c in chess_arr:
        if c == flag:
            m[y][x] = 1 # 上面有棋则标1
    lx = chess_arr[-1][0] # 最后一个子的x
    ly = chess_arr[-1][1] # 最后一个子的y
    dire_arr = [[(-1,0),(1,0)],[(0,-1),(0,1)],[(-1,-1),(1,1)],[(-1,1),(1,-1)]] # 4个方向数组,往左+往右、往上+往下、往左上+往右下、往左下+往右上,4组判断方向
    
    for dire1,dire2 in dire_arr:
        dx, dy = dire1
        num1 = get_one_dire_num(lx, ly, dx, dy, m)
        dx, dy = dire2
        num2 = get_one_dire_num(lx, ly, dx, dy, m)
        if num1 + num2 + 1 >= 5: return True

    return False

while True:
    for event in pygame.event.get():
         if event.type == pygame.QUIT:
             pygame.quit()
             exit()
    
         if game_state == 1 and event.type == pygame.MOUSEBUTTONUP: # 鼠标弹起
             x, y = pygame.mouse.get_pos() # 获取鼠标位置
             xi = int(round((x - space)*1.0/cell_size)) # 获取到x方向上取整的序号
             yi = int(round((y - space)*1.0/cell_size)) # 获取到y方向上取整的序号
             if xi>=0 and xi<cell_num and yi>=0 and yi<cell_num and (xi,yi,1) not in chess_arr and (xi,yi,2) not in chess_arr:
                 chess_arr.append((xi,yi,flag))
                 if check_win(chess_arr, flag):
                     game_state = 2 if flag == 1 else 3
                 else:
                     flag = 2 if flag == 1 else 1

    screen.fill((0,0,150)) # 将界面设置为蓝色

    for x in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(x+space,0+space),(x+space,cell_size*(cell_num-1)+space),1)
    for y in range(0,cell_size*cell_num,cell_size):
        pygame.draw.line(screen,(200,200,200),(0+space,y+space),(cell_size*(cell_num-1)+space,y+space),1)

    for x, y, c in chess_arr:
        chess_color = (30,30,30) if c == 1 else (225,225,225)
        pygame.draw.circle(screen, chess_color, [x*cell_size+space, y*cell_size+space], 16,16)

    if game_state != 1:
        myfont = pygame.font.Font(None,60)
        white = 210,210,0
        win_text = "%s win"%('black' if game_state == 2 else 'white')
        textImage = myfont.render(win_text, True, white)
        screen.blit(textImage, (260,320))
    
    pygame.display.update() # 必须调用update才能看到绘图显示
<think>好的,用户想用Pygame制作一个五子棋游戏。首先,我需要回忆一下五子棋的基本规则和Pygame的基本用法。五子棋需要棋盘、黑白棋子交替落子,判断胜负的条件是横向、纵向或斜向连续个同色棋子。Pygame方面,需要初始化窗口,处理事件,绘制图形,还有交互逻辑。 用户可能是一个刚开始学习Python游戏开发的人,所以需要步骤清晰,代码简单易懂。可能用户对Pygame不太熟悉,所以得先确保他们了解如何安装和导入库。还要考虑棋盘的绘制,比如使用网格线,间隔均匀。棋子的话,用圆圈表示,黑白两色交替。 然后,事件处理是关键。鼠标点击的位置需要转换为棋盘的网格坐标,可能需要计算行列号。每次点击后,检查该位置是否已经有棋子,没有的话就放置,并切换玩家。同时,每次落子后要判断是否有一方获胜,这需要遍历所有可能的连续个棋子。 可能用户没有考虑到胜负判断的复杂性,这里需要详细说明。例如,检查四个方向:水平、垂直、左斜、右斜。对于每个方向,遍历每个可能的起点,检查连续个是否同色。这一步可能会有些难度,需要仔细处理数组边界,避免越界。 另外,用户可能需要图形界面的提示,比如当前轮到哪位玩家,游戏结束后的提示信息。这些可以通过Pygame的字体渲染功能实现。需要提醒用户安装pygame并正确导入,同时注意资源管理,比如释放字体和窗口。 测试的时候,可能会有棋子重叠的问题,或者胜负判断不准确,所以代码中需要有相应的检查。比如,在落子前检查该位置是否已经被占用。胜负判断函数需要全面覆盖所有可能的情况。 可能用户还想知道如何优化代码,比如使用更高效的算法来判断胜负,或者增加AI对手。但作为基础版本,先实现双人对战比较合适。如果需要的话,可以后续添加人机对战的功能,使用简单的算法如极大极小搜索。 总结下来,步骤大概是:初始化Pygame,创建窗口,绘制棋盘,处理鼠标事件,落子,判断胜负,显示提示信息。代码结构需要模块化,比如分开绘制棋盘、绘制棋子、处理事件、判断胜负等函数,这样便于维护和扩展。 最后,确保代码的每一部分都有注释,解释清楚逻辑,特别是坐标转换和胜负判断的部分。这样用户能更好地理解每个步骤的作用,方便他们进行修改和调试。</think>以下是用Pygame制作五子棋游戏的基本实现思路和核心代码框架: ```python import pygame import sys # 初始化参数 GRID_SIZE = 30 # 格子尺寸 BOARD_SIZE = 15 # 棋盘15x15 WIDTH = GRID_SIZE * (BOARD_SIZE + 1) # 窗口宽度 # 颜色定义 BLACK = (0, 0, 0) WHITE = (255, 255, 255) BOARD_COLOR = (199, 148, 87) # 木质棋盘色 # 初始化Pygame pygame.init() screen = pygame.display.set_mode((WIDTH, WIDTH)) pygame.display.set_caption("五子棋") # 创建棋盘二维数组(0-空,1-黑,2-白) board = [[0] * BOARD_SIZE for _ in range(BOARD_SIZE)] current_player = 1 # 当前玩家 def draw_board(): """绘制棋盘""" screen.fill(BOARD_COLOR) # 绘制网格线 for i in range(BOARD_SIZE): pygame.draw.line(screen, BLACK, (GRID_SIZE, GRID_SIZE*(i+1)), (GRID_SIZE*BOARD_SIZE, GRID_SIZE*(i+1))) pygame.draw.line(screen, BLACK, (GRID_SIZE*(i+1), GRID_SIZE), (GRID_SIZE*(i+1), GRID_SIZE*BOARD_SIZE)) def draw_piece(row, col): """绘制棋子""" color = BLACK if current_player == 1 else WHITE center = (GRID_SIZE*(col+1), GRID_SIZE*(row+1)) pygame.draw.circle(screen, color, center, GRID_SIZE//2 - 2) def check_win(row, col): """检查是否获胜""" directions = [(1,0), (0,1), (1,1), (1,-1)] # 四个检查方向 for dr, dc in directions: count = 1 # 正向检查 i, j = row + dr, col + dc while 0 <= i < BOARD_SIZE and 0 <= j < BOARD_SIZE and board[i][j] == current_player: count += 1 i += dr j += dc # 反向检查 i, j = row - dr, col - dc while 0 <= i < BOARD_SIZE and 0 <= j < BOARD_SIZE and board[i][j] == current_player: count += 1 i -= dr j -= dc if count >= 5: return True return False # 游戏主循环 while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN: # 将鼠标坐标转换为棋盘坐标 x, y = pygame.mouse.get_pos() col = round((x - GRID_SIZE) / GRID_SIZE) row = round((y - GRID_SIZE) / GRID_SIZE) if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE and board[row][col] == 0: board[row][col] = current_player draw_piece(row, col) if check_win(row, col): print(f"玩家{current_player}获胜!") pygame.quit() sys.exit() current_player = 2 if current_player == 1 else 1 # 切换玩家 draw_board() pygame.display.flip() ``` 主要实现步骤说明: 1. 初始化游戏参数 - 定义棋盘尺寸、格子大小等基础参数 - 初始化Pygame窗口和棋盘二维数组 2. 绘制功能 - `draw_board()`:绘制棋盘网格线 - `draw_piece()`:根据当前玩家绘制棋子 3. 核心游戏逻辑 - 鼠标事件处理:将物理坐标转换为棋盘逻辑坐标 - 落子有效性判断:检查点击位置是否在棋盘范围内且无棋子 - 胜负判断:通过四个方向(水平/垂直/双斜线)检查连续子 4. 游戏流程控制 - 玩家轮流下棋(黑棋先行) - 每次落子后立即进行胜负判断 - 获胜后终止游戏 扩展建议: 1. 增加游戏状态提示(当前玩家/获胜提示) 2. 添加重新开始按钮 3. 实现人机对战(AI算法) 4. 添加音效和更美观的棋子皮肤 5. 增加禁手规则(专业五子棋规则) 运行前需要安装pygame: ```bash pip install pygame ``` 这个基础版本实现了双人对战的核心逻辑,可以作为五子棋游戏的开发起点。后续可以根据需求逐步添加更多功能和规则完善。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰风漫天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值