pygame实现五子棋游戏


Posted in Python onOctober 29, 2019

本文实例为大家分享了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才能看到绘图显示

pygame实现五子棋游戏

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()前将棋子绘制出来看看效果

pygame实现五子棋游戏

可以看到,现在已经能点出棋子了,但是棋子的位置不是纵横线的交叉点,所以我们必须对鼠标位置进行取整,不能把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))

现在发现落子位置靠谱多了

pygame实现五子棋游戏

为了代码的可读性更好点,以后一些棋盘计算更方便,我们把放入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)

pygame实现五子棋游戏

现在看起来有点像那么回事了

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才能看到绘图显示

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

Python 相关文章推荐
决策树的python实现方法
Nov 18 Python
Python实现抓取页面上链接的简单爬虫分享
Jan 21 Python
python实现逆波兰计算表达式实例详解
May 06 Python
用python实现对比两张图片的不同
Feb 05 Python
Python将图片转换为字符画的方法
Jun 16 Python
关于python2 csv写入空白行的问题
Jun 22 Python
python 实现交换两个列表元素的位置示例
Jun 26 Python
如何在Django配置文件里配置session链接
Aug 06 Python
Python打开文件、文件读写操作、with方式、文件常用函数实例分析
Jan 07 Python
Django后台管理系统的图文使用教学
Jan 20 Python
使用tensorflow DataSet实现高效加载变长文本输入
Jan 20 Python
使用Python爬取弹出窗口信息的实例
Mar 14 Python
python多线程案例之多任务copy文件完整实例
Oct 29 #Python
jenkins配置python脚本定时任务过程图解
Oct 29 #Python
pygame实现成语填空游戏
Oct 29 #Python
Python多线程及其基本使用方法实例分析
Oct 29 #Python
基于python的itchat库实现微信聊天机器人(推荐)
Oct 29 #Python
pygame实现非图片按钮效果
Oct 29 #Python
线程安全及Python中的GIL原理分析
Oct 29 #Python
You might like
用php+javascript实现二级级联菜单的制作
2008/05/06 PHP
解析VS2010利用VS.PHP插件调试PHP的方法
2013/07/19 PHP
php的一个简单加密解密代码
2014/01/14 PHP
php生成短网址示例
2014/05/05 PHP
PHP处理二进制数据的实现方法
2016/06/13 PHP
php array_merge_recursive 数组合并
2016/10/26 PHP
jquery动态增加删除表格行的小例子
2013/11/14 Javascript
javascript中HTMLDOM操作详解
2014/12/11 Javascript
函数window.open实现关闭所有的子窗口
2015/08/03 Javascript
浅析jQuery中使用$所引发的问题
2016/05/29 Javascript
js基础之DOM中元素对象的属性方法详解
2016/10/28 Javascript
js实现点击每个li节点,都弹出其文本值及修改
2016/12/15 Javascript
jQuery鼠标移动图片上实现放大效果
2017/06/25 jQuery
layui问题之模拟select点击事件的实例讲解
2018/08/15 Javascript
keep-alive不能缓存多层级路由菜单问题解决
2020/03/10 Javascript
vue+vant使用图片预览功能ImagePreview的问题解决
2020/04/10 Javascript
js实现菜单跳转效果
2020/12/11 Javascript
Python中apply函数的用法实例教程
2014/07/31 Python
python实现查找excel里某一列重复数据并且剔除后打印的方法
2015/05/26 Python
Python实现的连接mssql数据库操作示例
2018/08/17 Python
python实现nao机器人身体躯干和腿部动作操作
2019/04/29 Python
24式加速你的Python(小结)
2019/06/13 Python
一篇文章弄懂Python中的可迭代对象、迭代器和生成器
2019/08/12 Python
pytorch 输出中间层特征的实例
2019/08/17 Python
Matplotlib scatter绘制散点图的方法实现
2020/01/02 Python
Python下使用Trackbar实现绘图板
2020/10/27 Python
TripAdvisor越南:全球领先的旅游网站
2017/09/21 全球购物
澳大利亚排名第一的儿童在线玩具商店:Toy Galaxy
2018/10/06 全球购物
接口可以包含哪些成员
2012/09/30 面试题
商务日语毕业生自荐信范文
2013/11/14 职场文书
纪念九一八事变演讲稿:青少年应树立远大理想
2014/09/14 职场文书
2014年客户经理工作总结
2014/11/20 职场文书
社会实践活动总结
2015/02/05 职场文书
工程部岗位职责
2015/02/10 职场文书
天那边观后感
2015/06/09 职场文书
golang goroutine顺序输出方式
2021/04/29 Golang