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读取mp3中ID3信息的方法
Mar 05 Python
Python字符串、元组、列表、字典互相转换的方法
Jan 23 Python
深入理解Python中装饰器的用法
Jun 28 Python
Python学习笔记之解析json的方法分析
Apr 21 Python
Python简单生成8位随机密码的方法
May 24 Python
Python WXPY实现微信监控报警功能的代码
Oct 20 Python
hmac模块生成加入了密钥的消息摘要详解
Jan 11 Python
python适合人工智能的理由和优势
Jun 28 Python
python实现点击按钮修改数据的方法
Jul 17 Python
详解用python生成随机数的几种方法
Aug 04 Python
django创建超级用户过程解析
Sep 18 Python
Python self用法详解
Nov 28 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 ftp文件上传函数(基础版)
2010/06/03 PHP
PHP三元运算符的结合性介绍
2012/01/10 PHP
php输出echo、print、print_r、printf、sprintf、var_dump的区别比较
2013/06/21 PHP
php对象在内存中的存在形式分析
2015/02/03 PHP
Yii2中Restful API原理实例分析
2016/07/25 PHP
PHP面向对象程序设计之类与反射API详解
2016/12/02 PHP
Yii2实现中国省市区三级联动实例
2017/02/08 PHP
tp5框架使用cookie加密算法实现登录功能示例
2020/02/10 PHP
Docker 安装 PHP并与Nginx的部署实例讲解
2021/02/27 PHP
简单的js表单验证函数
2013/10/28 Javascript
javascript函数作用域学习示例(js作用域)
2014/01/13 Javascript
Jquery的each里用return true或false代替break或continue
2014/05/21 Javascript
使用GruntJS构建Web程序之安装篇
2014/06/04 Javascript
快速解决jquery.touchSwipe左右滑动和垂直滚动条冲突
2016/04/15 Javascript
js style.display=block显示布局错乱问题的解决方法
2016/09/21 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
2016/12/19 Javascript
JS常见疑难点分析之match,charAt,charCodeAt,map,search用法分析
2016/12/25 Javascript
Bootstrap面板(Panels)的简单实现代码
2017/03/17 Javascript
javascript实现多张图片左右无缝滚动效果
2017/03/22 Javascript
基于ajax和jsonp的原生封装(实例)
2017/10/16 Javascript
angularjs 获取默认选中的单选按钮的value方法
2018/02/28 Javascript
JS正则表达式验证端口范围(0-65535)
2020/01/06 Javascript
js实现简单的轮播图效果
2020/12/13 Javascript
JavaScript实现下拉列表
2021/01/20 Javascript
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
解决Python字典写入文件出行首行有空格的问题
2017/09/27 Python
详解Python核心对象类型字符串
2018/02/11 Python
python matplotlib实现双Y轴的实例
2019/02/12 Python
pytorch方法测试——激活函数(ReLU)详解
2020/01/15 Python
css3进行截取替代js的substring
2013/09/02 HTML / CSS
卡西欧B级产品官方网站:Casio Outlet
2018/05/22 全球购物
致短跑运动员广播稿
2014/01/09 职场文书
祖国在我心中演讲稿
2014/01/15 职场文书
2015大学生求职信范文
2015/03/20 职场文书
SQL基础查询和LINQ集成化查询
2022/01/18 MySQL
【海涛dota解说】一房久违的影魔魂守二连发
2022/04/01 DOTA