侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

pygame实现五子棋游戏

Python  /  管理员 发布于 5年前   196

本文实例为大家分享了pygame五子棋游戏的具体代码,供大家参考,具体内容如下

1.设置棋盘

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

# -*- coding=utf-8 -*-import randomimport pygamepygame.init()space = 60 # 四周留下的边距cell_size = 40 # 每个格子大小cell_num = 15grid_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 randomimport pygamefrom pygame.locals import MOUSEBUTTONUPpygame.init()space = 60 # 四周留下的边距cell_size = 40 # 每个格子大小cell_num = 15grid_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+=1def 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 randomimport pygamefrom pygame.locals import MOUSEBUTTONUPpygame.init()space = 60 # 四周留下的边距cell_size = 40 # 每个格子大小cell_num = 15grid_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+=1def 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 Falsewhile 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才能看到绘图显示

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    pygame实现俄罗斯方块游戏(基础篇1)
    下一条:
    pygame实现成语填空游戏
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客