内容简介:今年年初,新一季的《最强大脑》开播了,第一集选拔的时候大家做了一个数字游戏,名叫《数字华容道》,当时何猷君以十几秒的成绩夺得该项目的冠军,看了这个游戏之后我决定要写一个《数字华容道》的程序,过去了半年,我终于记起了这件事,今天就来实现。数字推盘游戏(n-puzzle)是一种智力游戏,常见的类型有十五数字推盘游戏和八数字推盘游戏等。十五数字推盘游戏的板上会有十五个方块和一个大小相当于一个方块的空位(供方块移动之用),当15个数字依次排序并且最后一个格子为空位即代表挑战成功。本文使用
今年年初,新一季的《最强大脑》开播了,第一集选拔的时候大家做了一个数字游戏,名叫《数字华容道》,当时何猷君以十几秒的成绩夺得该项目的冠军,看了这个游戏之后我决定要写一个《数字华容道》的程序,过去了半年,我终于记起了这件事,今天就来实现。
数字推盘游戏(n-puzzle)是一种智力游戏,常见的类型有十五数字推盘游戏和八数字推盘游戏等。十五数字推盘游戏的板上会有十五个方块和一个大小相当于一个方块的空位(供方块移动之用),当15个数字依次 排序 并且最后一个格子为空位即代表挑战成功。
本文使用 PyQt5 进行设计与实现,PyQt5 是该程序的一个呈现方式,最重要的是 算法 ,学会了算法,完全可以使用 PyGame 或者 Tkinter 实现。
PyQt5安装: pip install PyQt5
本文使用环境:
- 系统:Windows 10 64位
- Python版本:3.6
1、布局设计
做一个简版的数字华容道,布局设计如图所示:
简版数字华容道布局
- 图中灰色的部分使用 QWidget 作为整个游戏的载体;
- 黄色部分使用 QGridLayout 作为数字方块的布局;
- 红色部分使用 QLabel 作为数字方块。
2、算法设计
如上图所示,本游戏共需要15个方块,每个方块代表一个数字。我们可以使用 一个 二维 list 来存储方块上的数字。其实我们要创建一个 4x4 的 list 存储 0~15 各个数字,0 代表空的位置。
2.1 创建并初始化数组
创建数组的方法:
- 创建一个长度为16的数组,并且在对应位置上保存着 0~15 ;
- 打乱顺序
import random
# 用来存放位置信息的二维数组
blocks = []
# 产生随机数组,0 代表空的位置
arr = range(16)
numbers = random.sample(arr, 16)
for row in range(4):
blocks.append([])
for column in range(4):
blocks[row].append(numbers[row*4 + column])
# 打印结果
for i in range(4):
print(blocks[i])
[out]
[2, 5, 7, 9]
[11, 8, 4, 12]
[6, 13, 10, 15]
[1, 14, 0, 3]
[Finished in 0.1s]
2.2 移动算法
假如移动之前个数字位置如左图所示,那么当按下左箭头时,会变成如右图所示:
左移
可以看到 (1, 2) 和 (1, 3) 两个位置上的数字互换了,即 0 和 8 互换;如果右图所示再次按下左箭头,那么所有数字都不会改变,因为 数字 0 右边没有数了。
总结一下:如果 数字 0 所在位置为 (row, column),并且 column≠3 那么按下 左箭头 之后,(row, column) 和 (row, column+1) 位置上的数组互换,同理可得:
- 如果 数字 0 所在位置为 (row, column),并且 column≠0 那么按下 右箭头 之后,(row, column) 和 (row, column-1) 位置上的数组互换;
- 如果 数字 0 所在位置为 (row, column),并且 row≠3 那么按下 上箭头 之后,(row, column) 和 (row+1, column) 位置上的数组互换;
- 如果 数字 0 所在位置为 (row, column),并且 row≠0 那么按下 下箭头 之后,(row, column) 和 (row-1, column) 位置上的数组互换;
将移动算法封装成一个函数如下:
# 移动
# zero_row 代表数字0 所在二维数组的行下标,zero_column代表数字0 所在二维数组的列下标
def move(direction):
if(direction == 'UP'): # 上
if zero_row != 3:
blocks[zero_row][zero_column] = blocks[zero_row + 1][zero_column]
blocks[zero_row + 1][zero_column] = 0
zero_row += 1
if(direction == 'DOWN'): # 下
if zero_row != 0:
blocks[zero_row][zero_column] = blocks[zero_row - 1][zero_column]
blocks[zero_row - 1][zero_column] = 0
zero_row -= 1
if(direction == 'LEFT'): # 左
if zero_column != 3:
blocks[zero_row][zero_column] = blocks[zero_row][zero_column + 1]
blocks[zero_row][zero_column + 1] = 0
zero_column += 1
if(direction == 'RIGHT'): # 右
if zero_column != 0:
blocks[zero_row][zero_column] = blocks[zero_row][zero_column - 1]
blocks[zero_row][zero_column - 1] = 0
zero_column -= 1
2.3 是否胜利检测算法
检测是否胜利其实很简单: 前15个位置分别对应,最后一个为0即为胜利 ,不过为了避免不必要的计算,我们先检测最后一个是否为 0 ,如果不为0 前面的就不用比较了。具体代码实现如下:
# 检测是否完成
def checkResult():
# 先检测最右下角是否为0
if blocks[3][3] != 0:
return False
for row in range(4):
for column in range(4):
# 运行到此处说名最右下角已经为0,pass即可
if row == 3 and column == 3:
pass
# 值是否对应
elif blocks[row][column] != row * 4 + column + 1:
return False
return True
3、实现
下面讲解所有功能模块的实现。
3.1 框架搭建
创建 QWidget 作为整个游戏的载体:
import sys
from PyQt5.QtWidgets import QWidget, QApplication
class NumberHuaRong(QWidget):
""" 华容道主体 """
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 设置宽和高
self.setFixedSize(400, 400)
# 设置标题
self.setWindowTitle('数字华容道')
# 设置背景颜色
self.setStyleSheet("background-color:gray;")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = NumberHuaRong()
sys.exit(app.exec_())
运行结果如下图所示:
框架运行结果
3.2 数字方块实现
前面已经提到,用一个二维数组来存放 0~16 个数字,最终我们要转换成一个数字方块,单独创建一个类:
class Block(QLabel):
""" 数字方块 """
def __init__(self, number):
super().__init__()
self.number = number
self.setFixedSize(80, 80)
# 设置字体
font = QFont()
font.setPointSize(30)
font.setBold(True)
self.setFont(font)
# 设置字体颜色
pa = QPalette()
pa.setColor(QPalette.WindowText, Qt.white)
self.setPalette(pa)
# 设置文字位置
self.setAlignment(Qt.AlignCenter)
# 设置背景颜色\圆角和文本内容
if self.number == 0:
self.setStyleSheet("background-color:white;border-radius:10px;")
else:
self.setStyleSheet("background-color:red;border-radius:10px;")
self.setText(str(self.number))
该类继承自 QLablel ,初始化需要传入一个参数 number ,number就是数字方块上显示的数字。
3.3 将数字转换成方块添加到布局
布局采用 QGridLayout 创建一个 4X4 的 self.gltMain ,将16个 Block 添加到 self.gltMain:
def updatePanel(self):
for row in range(4):
for column in range(4):
self.gltMain.addWidget(Block(self.blocks[row][column]), row, column)
self.setLayout(self.gltMain)
3.4 初始化布局
初始化布局包括 随机数据的产生 与将 数字转换成方块添加到布局 :
```python
初始化布局
def onInit(self):
# 产生随机数组,0 代表空的位置
arr = range(16)
self.numbers = random.sample(arr, 16)
# 将数字方块添加到布局
for row in range(4):
self.blocks.append([])
for column in range(4):
temp = self.numbers[row * 4 + column]
以上所述就是小编给大家介绍的《简版数字华容道》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 数字中台:企业数字营销的支点
- 对称加密,非对称加密,数字签名,数字证书,SSL握手
- 海康联手新中大推进「数字建企」,实现数字化工地与项目管理
- 数字政务势在必行 人民政务扛起国家队大旗推动数字政务发展
- Oracle字符类型存数字及查询数字时使用单引号走不走索引的问题
- Python Number(数字)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Visual C++网络通信协议分析与应用实现
汪晓平、钟军 / 人民邮电出版社 / 2003-2-1 / 60.00元
本书介绍了如何利用Visual一起来看看 《Visual C++网络通信协议分析与应用实现》 这本书的介绍吧!