在生活节奏不断加快的现代社会,轻松的益智游戏对缓解生活压力调节情绪具有重要意义,而五子棋这一款游戏正好符合大众的心理。为了迎合众多用户的需求,开发了这款叫做五子棋的小游戏,并且这款小游戏适合社会各阶层的人士,此外,它还有很强的娱乐性和交互性。
尽管现在市面上存在的游戏版本很多,可是五子棋的市场还是很大的,原因就在于它能引人入深,爱不释手。随着游戏速度的逐渐加快,其刺激性也更强。可以说,游戏的优势不仅在于简单易行,而且在于他能很快顺利的运行。对于那些在外忙忙碌碌的人们,想让他们花费大量的时间在大型游戏上显然是不可能的,可是小游戏却能刚好迎合他们的需求。
本设计以python为基础,通过pycharm来设计实现,首先简单介绍了开发工具,然后从需求分析,总体设计,详细设计与实现等方面介绍五子棋游戏的设计与实现过程。
随着信息技术的飞速发展,5G时代已经到来。游戏也迎来了新的发展,现在电脑手机的功能已不仅仅是简单的工作、交际了,工作之余的娱乐享受也相当的重要。众多的用户都认为小型的休闲游戏是最受欢迎的。因为小型游戏非常方便,随时都可以玩。这些游戏可以缓解人们的工作压力,同时调动了人们的思维。我们开发的这款打地鼠小游戏,足以满足大多数用户的需求,并且与现在的手机规模相符合。
五子棋不仅能增强人们的抽象思维能力、逻辑推理能力、空间想象力,提高人们的记忆力、心算能力等,而且深含哲理,有助于修身养性。五子棋既有现代休闲方式所特有的特征“短、平、快”,又有中国古典哲学所包含的高深学问“阴阳易理”,它既有简单易学的特点,为人民群众所喜闻乐见,又有深奥的技巧,既能组织举办群众性的比赛、活动,又能组织举办高水平的国际性比赛。
现在越来越多的人注重精神层面的享受,游戏的出现让很多人喜欢上这一娱乐方式,游戏的娱乐可以带给人们轻松与欢笑,在电脑手机普遍后,这个现象更是明显。人们开始在网络上寻求娱乐方式,在空闲时间玩玩游戏打发时间,足不出户就可以与其他人交流。于是打地鼠这款游戏出现了,这款游戏简单操作简单,容易上手,毫不费力,对于时间少的人也是如此,玩玩小游戏,让生活变得轻松。
本游戏需要满足以下几点要求:
(1) 游戏规则:实现五子棋游戏规则,双方玩家按照规则进行游戏。
(2) 游戏界面设计:实现游戏的图形化界面,让玩家可以方便的进行操作。
(3) 人机对战:实现人机对战功能,通过编写算法进行对战。
(4) 双人对战:实现双人对战功能,玩家可以在同一页面进行对战。
(5) 联机对战:实现联机对战功能,玩家可以通过共享棋盘界面与其他玩家进行对战。
此次项目应用Python语言作为基础、通过Pycharm集成开发环境进行搭建设计并实现。
Python是一种跨平台的计算机程序设计语言。由荷兰的龟叔创造,是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。它语法简介而清晰,易学易懂,很多学校用它当作基础入门的语言。
Pycharm 是一种Python 集成开发环境,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,Pycharm里面包含了许多第三方的库,本次设计使用了其内置的第三方库PyQt5。
五子棋游戏是一款简单的大众游戏,很符合现代人的休闲特点的益智类游戏,其是我国古代围棋的的衍生物,本系统主要由三个部分组成:人机对战,双人对战和联机对战。
计算机硬件和软件技术的飞速发展,为游戏系统的开发提供了设备条件。当前在网络上有许多的五子棋软件可供参考借鉴,并且我自己也在老师的指导下掌握了python语言在pycharm环境下的基本应用,因此本游戏的开发技术上是完全可行的。
3.1.1功能需求:
(1)实现三种游戏模式:人机对战、双人对战、联机对战
(2)实现在棋盘上落子
(3)实现游戏输赢
(4)设计算法模块:实现电脑自动落子
(5)实现菜单界面:具有三种游戏模式选择
(6)网络配置界面:实现玩家在局域网下的联机对战
(7)定义游戏按钮:实现游戏开始,返回,悔棋,催促、认输按钮
3.2.2性能需求
本软件在设计方面本着方便、实用及娱乐性高的宗旨,在对界面进行设计的过程中,始终坚持清晰明了,在性能方面能够实现效率高,不易出错等优点。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gO5w4izX-1688035783197)(C:\Users\Morii\AppData\Roaming\Typora\typora-user-images\image-20230629172320907.png)]
本系统主要是完成五子棋游戏的基本操作。用户可以自己练习和娱乐。本系统主要分为三个模块。如图1所示。
1、 游戏核心模块:
该模块主要对五子棋游戏的基本功能进行设计,主要包含按钮功能结束,玩家落子的控制,以及游戏输赢结果的判断。
2、 游戏界面模块:
游戏界面模块主要包含游戏进入界面、游戏运行界面、网络配置界面三个模块组成。各个模块具有以下功能:
(1)游戏进入界面:
主要包括游戏图形区域界面,里面包含人机对战、双人对战、联机对战三种游戏模式。
(2)游戏运行界面:
人机对战界面:主要由五子器棋盘、返回、开始、悔棋、认输等功能。
双人对战界面:主要由五子器棋盘、返回、开始、悔棋、认输等功能。
联机对战界面:主要由五子器棋盘、返回、开始、悔棋、认输,催促等功能。
(3)网络配置界面:
主要对网络配置界面实现,包含姓名、ip地址、端口号,连接主机、我是主机模块。
3、 游戏功能模块:
本系统具有人机对战、双人对战、联网对战三种游戏模式,每个模式具有不同的逻辑功能,对于不同模块应该具有以下功能:
人机对战:实现电脑自动落子。
双人对战:实现玩家交替落子。
联网对战:实现局域网内联网对战。
(1)编写按钮类MyButton
(2)初始化菜单界面:设置窗体样式、放置背景、将画板应用到窗口
(3)添加三个按钮
(4)定义按钮信号
(5)将信号和按钮进行绑定
(1) 定义按钮类MyButton
(2) 编写游戏界面类GameWidget
(3) 对游戏界面设置背景图片
(4) 在游戏界面实例化返回,悔棋,认输按钮
(5) 根据图片像素大小设置棋子的落子位置
(6) 将鼠标坐标与棋盘坐标进行转化获取落子位置
(1) 设置标题
(2)构建组件:姓名、ip、端口号、按钮组件
(3) 创建网格并将组件添加到网格
(4) 将网格布局应用到网络配置窗口上
(5) 定义点击我是主机实现的方法
(6) 定义连接主机实现的方法
(7)定义关闭窗口事件
(1)存储棋盘信息:二维列表,将棋盘坐标和二维数组下标对应起来
(2)落子:落字时判断游戏状态,是否落子成功,若落子成功判断是否有输赢
(3)重置游戏:将棋盘消息清空
(4)悔棋:将棋盘中最后一颗棋子拿掉
(6)认输:停止游戏,并显示另一方胜
(5)判断输赢:每次落子都更新这个棋盘信息,并且使用judge_win方法
以当前下棋的位置为基准,分别扫描该位置纵向,横向,左斜,右斜方向上的棋子数。
以纵向为例:
先向下扫描一位若有与自身颜色相同的棋子就计数加一并继续,直到碰到异色棋子或棋盘边界,再向上扫描,扫描完成后判断是否形成五子连珠,是则返回胜利的一方,否则继续扫描横向,左斜,右斜方向。如果都没有形成五子连珠则返回“Down”表示游戏继续。此方法每下一次棋子便执行一次。
代码实现:
\# 判断输赢
def judge_win(self, x: int, y: int, color:str):
\# 判断纵向有没有五子连珠(左右)
count = 1 # 初始化计数
\# 向下检索
j = y + 1
while j <= 18:
If self.chessboard[j][x] == None or self.chessboard[j][x] != color:
break
count += 1
j += 1
\# 向上检索
j = y - 1
while j >= 0:
if self.chessboard[j][x] == None or self.chessboard[j][x] != color:
break
count += 1
j -= 1
if count >= 5:
\# 已经构成五子连珠, 返回胜利的棋子颜色
return color
(1)初始化游戏
(2)定义棋子转换 get_reverse_color
(3)定义转换当前棋子颜色swith_color
(4)实现落子
(5)实现悔棋
(6)实现认输
(7)实现返回游戏胜利
(1)编写人机对战类:继承双人对战类,
(2)并重写down_chess方法
(3)编写算法类Algorithm:分析棋盘局势,找到最优落子位置
(4)定义computer_down_chess方法:传入算法实现电脑的自动落子
人机算法设计思路:
获取当前位置分数:
遍历棋盘,在空位置模拟落子,然后将二维列表转化为一维列表,最后将一维列表合并,以获取获取当前位置的最大分数。
@property
def get_point(self):
\# 记录白棋的分数
white_score = [[0 for _ in range(19)] for _ in range(19)]
\# 记录黑棋的分数
black_score = [[0 for _ in range(19)] for _ in range(19)]
for j in range(19):
for i in range(19):
if self.chessboard[j][i] is None:
self.chessboard[j][i] = 'white'
\# 落子后判断 当前位置落 白子 分数是多少
white_score[j][i] = self.get_point_score(x=i, y=j, color='white')
self.chessboard[j][i] = None
\# 模拟落黑子
self.chessboard[j][i] = 'black'
black_score[j][i] = self.get_point_score(x=i, y=j, color='black')
self.chessboard[j][i] = None
\# 将二维列表转换成一维列表 找到最大值 再复原该位置的坐标
r_white_score = []
r_black_score = []
for i in white_score:
r_white_score.extend(i)
for j in black_score:
r_black_score.extend(j)
score_list = [max(x, y) for x, y in zip(r_white_score, r_black_score)]
\# 找到当前列表中的最大值和其下标
index = score_list.index(max(score_list))
x = index % 19
y = index // 19
return x, y
求最大分数:
首先需要传入一个点坐标和对应的颜色创建两个长度为4的列表用于存储当前棋子颜色四个方向的分数,然后进行遍历计算。
以纵向为例:
按下标顺序分别记录竖直,水平,左斜,右斜方向上的自身棋子和空白位置的数目,将其数目当作这一点位的分数。遍历棋盘所有空位,计算棋子在所有空点位下棋所得分数(从竖直,水平,左斜,右斜四个方向的分数中取最大值),以此找到最优落子位置
def get_point_score(self, x, y, color):
color_score = [0, 0, 0, 0]
blank_score = [0, 0, 0, 0]
\# 向下寻找
i = x # 列
j = y # 行
while j <= 18:
if self.chessboard[j][i] == color:
\# color_score 分数加一分
color_score[1] += 1
elif self.chessboard[j][i] is None:
\# 遇到空白位置 空白分数加一分
blank_score[1] += 1
break
else:
\# 遇到异色棋子
break
\# 在五个子内遍历
if j >= y + 5:
break
j += 1
\# 向上寻找
i = x # 列
j = y # 行
while j >= 0:
if self.chessboard[j][i] == color:
color_score[1] += 1
elif self.chessboard[j][i] is None:
blank_score[1] += 1
break
else:
break
if j <= y - 5:
break
j -= 1 # 继续循环 直到退出循环
设计思路:
(1)初始化游戏界面:定义 GameWidgetPlus,重写creatButton添加催促按钮
(2)搭建网络配置窗口:调用 NetConfigWidget
定义服务器类和客户端类实现服务端与客户端的信息交互
(3)动态创建网络对象
(4)定义游戏的基本功能:初始化游戏、开始游戏、落子、悔棋、认输、催促、判断输赢
(5) 添加开始游戏请求、接受服务器落子,让客户端落子、同意悔棋请求
(6)定义parse函数实现对不同类型的消息进行处理
当点击联机对战时会弹出网络配置的窗口,玩家可以在此界面配置姓名,ip地址,端口号。当点击“我是主机时”会创建服务器端,等待客户端连接。当点击“连接主机”时会创建客户端,客户端会主动连接输入的ip所对应的服务器端。具体界面如下图所示
5.2.3.2服务器与客户端的交互
当玩家在网络配置模块点击“我是主机”就会创建出服务器端。有自己的ip,端口号,服务器名,以此创建出客户端的socket。然后监听,并以线程的方式开启接收函数,用来接收客户端的连接,和接收客户端发来的消息。主线程用来给客户端发送消息。
以服务器接受客服端的连接为例:
def acceptConnect(self):
try:
self.cli_socket, addr = self.socket.accept()
except Exception as e:
print('错误信息是: ', e)
\# 获取客户端发送的数据---开始,悔棋,认输,催促
while True:
try:
data = self.cli_socket.recv(4096).decode()
self.msg_signal.emit(data)
except Exception as e:
print("错误信息是: ", e)
首先根据需求创建网络类型,完成创建让配置界面隐藏并进人游戏界面,通过使用多态实现连接,将信息处理函数和信号绑定来实现响应的功能,其中信息处理函数主要实现服务器和客户端之间不同类型信息的处理。
以事件处理函数parse为例(开始游戏)
拿到消息 根据消息类型做出不同的处理
def parse(self, data):
try:
msg = json.loads(data) # 将json消息转成字典
except Exception as e:
print("错误的消息类型")
return
if msg['msg_type'] == 'position':
self._down_chess(position=(msg['x'], msg['y']))
\# 开始游戏
elif msg['msg_type'] == 'restart':
\# 对方请求开始游戏
result = QMessageBox.information(
self.game_widget,
'开始游戏提示', '对方请求开始游戏,你是否同意?',
QMessageBox.Yes | QMessageBox.No
)
if result == QMessageBox.Yes:
self._start_game() # 初始化游戏
self.m_color = 'white' # 切换对手的棋子颜色
msg = { }
msg['msg_type'] = 'response' # 返回响应
msg['action_type'] = 'restart' # 响应类型
msg['action_result'] = 'Yes' # 同意
self.net_object.send(json.dumps(msg))
elif result == QMessageBox.No:
msg = { }
msg['msg_type'] = 'response' # 返回响应
msg['action_type'] = 'restart' # 响应类型
msg['action_result'] = 'No' #
self.net_object.send( json.dumps(msg))
self.m_color = ‘white’ # 切换对手的棋子颜色
msg = { }
msg[‘msg_type’] = ‘response’ # 返回响应
msg[‘action_type’] = ‘restart’ # 响应类型
msg[‘action_result’] = ‘Yes’ # 同意
self.net_object.send(json.dumps(msg))
elif result == QMessageBox.No:
msg = { }
msg[‘msg_type’] = ‘response’ # 返回响应
msg[‘action_type’] = ‘restart’ # 响应类型
msg[‘action_result’] = ‘No’ #
self.net_object.send( json.dumps(msg))