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创建xml的方法
Mar 10 Python
Python Tkinter GUI编程入门介绍
Mar 10 Python
用Python的pandas框架操作Excel文件中的数据教程
Mar 31 Python
使用py2exe在Windows下将Python程序转为exe文件
Mar 04 Python
简单谈谈Python中的闭包
Nov 30 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
Oct 30 Python
Python对excel文档的操作方法详解
Dec 10 Python
使用Python横向合并excel文件的实例
Dec 11 Python
python批量创建变量并赋值操作
Jun 03 Python
教你如何使用Python实现二叉树结构及三种遍历
Jun 18 Python
一篇文章弄懂Python中的内建函数
Aug 07 Python
详解在OpenCV中如何使用图像像素
Mar 03 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计算两个整数的最大公约数常用算法小结
2015/03/05 PHP
PHP语法小结之基础和变量
2015/11/22 PHP
使用phpQuery获取数组的实例
2017/03/13 PHP
PHP单例模式实例分析【防继承,防克隆操作】
2019/05/22 PHP
Sample script that deletes a SQL Server database
2007/06/16 Javascript
Javascript 代码也可以变得优美的实现方法
2009/06/22 Javascript
jquery 日期分离成年月日的代码
2010/05/14 Javascript
JavaScript执行效率与性能提升方案
2012/12/21 Javascript
通过javascript把图片转化为字符画
2013/10/24 Javascript
javascript实现移动端上的触屏拖拽功能
2016/03/04 Javascript
Angularjs整合微信UI(weui)
2016/03/15 Javascript
jquery简单插件制作(fn.extend)完整实例
2016/05/24 Javascript
浅谈javascript运算符——条件,逗号,赋值,()和void运算符
2016/07/15 Javascript
浅谈jQuery的bind和unbind事件(绑定和解绑事件)
2017/03/02 Javascript
vue.js实现刷新当前页面的方法教程
2017/07/05 Javascript
js提取中文拼音首字母的封装工具类
2018/03/12 Javascript
vue中 this.$set的用法详解
2019/09/06 Javascript
layui实现数据表格自定义数据项
2019/10/26 Javascript
JavaScript修改注册表实例代码
2020/01/05 Javascript
Python smtplib实现发送邮件功能
2018/05/22 Python
Django 路由控制的实现
2019/07/17 Python
django formset实现数据表的批量操作的示例代码
2019/12/06 Python
Python 实现自动获取种子磁力链接方式
2020/01/16 Python
对python中各个response的使用说明
2020/03/28 Python
Django实现后台上传并显示图片功能
2020/05/29 Python
在Keras中实现保存和加载权重及模型结构
2020/06/15 Python
Win10下用Anaconda安装TensorFlow(图文教程)
2020/06/18 Python
Java语言程序设计测试题改错题部分
2014/07/22 面试题
幼儿园园长自我鉴定
2013/10/22 职场文书
小学教师岗位职责
2013/11/25 职场文书
管理心得体会
2013/12/28 职场文书
社区优秀志愿者先进事迹
2014/05/09 职场文书
2014年英语教研组工作总结
2014/12/06 职场文书
JavaScript canvas实现流星特效
2021/05/20 Javascript
Java由浅入深通关抽象类与接口(上篇)
2022/04/26 Java/Android
Python实现数据的序列化操作详解
2022/07/07 Python