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实现多线程采集的2个代码例子
Jul 07 Python
Python获取暗黑破坏神3战网前1000命位玩家的英雄技能统计
Jul 04 Python
解析Python中的eval()、exec()及其相关函数
Dec 20 Python
python增加矩阵维度的实例讲解
Apr 04 Python
对python中dict和json的区别详解
Dec 18 Python
python协程之动态添加任务的方法
Feb 19 Python
Python Django框架防御CSRF攻击的方法分析
Oct 18 Python
python cv2在验证码识别中应用实例解析
Dec 25 Python
关于pytorch处理类别不平衡的问题
Dec 31 Python
基于python实现上传文件到OSS代码实例
May 09 Python
Python pandas如何向excel添加数据
May 22 Python
Python自动化工具之实现Excel转Markdown表格
Apr 08 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 empty函数判断mysql表单是否为空
2010/04/12 PHP
Yii学习总结之数据访问对象 (DAO)
2015/02/22 PHP
php+flash+jQuery多图片上传源码分享
2020/07/27 PHP
PHP 扩展Memcached命令用法实例总结
2020/06/04 PHP
xmlHTTP实例
2006/10/24 Javascript
基于jQuery的试卷自动排版系统实现代码
2011/01/06 Javascript
基于NodeJS的前后端分离的思考与实践(一)全栈式开发
2014/09/26 NodeJs
js实现图片从左往右渐变切换效果的方法
2015/02/06 Javascript
JS实现仿QQ聊天窗口抖动特效
2015/05/10 Javascript
javascript HTML+CSS实现经典橙色导航菜单
2016/02/16 Javascript
微信小程序 wxapp内容组件 icon详细介绍
2016/10/31 Javascript
Angular之指令Directive用法详解
2017/03/01 Javascript
深入理解在JS中通过四种设置事件处理程序的方法
2017/03/02 Javascript
AngularJS 最常用的八种功能(基础知识)
2017/06/26 Javascript
关于vue.extend和vue.component的区别浅析
2017/08/16 Javascript
Angular8 Http拦截器简单使用教程
2019/08/20 Javascript
使用localStorage替代cookie做本地存储
2019/09/25 Javascript
使用Vue-cli 中为单独页面设置背景图片铺满全屏
2020/07/17 Javascript
用Python进行一些简单的自然语言处理的教程
2015/03/31 Python
Python如何获取系统iops示例代码
2016/09/06 Python
利用Python yagmail三行代码实现发送邮件
2018/05/11 Python
python numpy 显示图像阵列的实例
2018/07/02 Python
python执行CMD指令,并获取返回的方法
2018/12/19 Python
python 瀑布线指标编写实例
2020/06/03 Python
解决pycharm不能自动保存在远程linux中的问题
2021/02/06 Python
详解CSS3的图层阴影和文字阴影效果使用
2016/06/09 HTML / CSS
客服端调用EJB对象的几个基本步骤
2012/01/15 面试题
学年自我鉴定
2014/01/16 职场文书
运输服务质量承诺书
2014/03/27 职场文书
撤诉书怎么写
2015/05/19 职场文书
战马观后感
2015/06/08 职场文书
治理商业贿赂工作总结
2015/08/10 职场文书
Golang二维切片初始化的实现
2021/04/08 Golang
Python中glob库实现文件名的匹配
2021/06/18 Python
Go语言并发编程 sync.Once
2021/10/16 Golang
java中为什么说子类的构造方法默认访问的是父类的无参构造方法
2022/04/13 Java/Android