python 基础系列篇:七、以函数方式编写一个数字华容道
python 基础系列篇:七、以函数方式编写一个数字华容道
- 数字华容道
- 游戏分析
- 开始编写
- 完整代码
- 代码解说
- 定义方法的规律
- 小结
数字华容道
嗯,就是一个简单的益智游戏,把数字按照特定规律排列,并比矩阵少一个格,用来进行移动。
具体游戏方式就不细说了,还不了解的可以自行百度一下。
正好,老顾最近是没有什么灵感,不知道用什么举例来讲解一下怎么去划分函数,减少工作,然后就在昨天,问答有小伙伴问到了数字华容道的问题。然后老顾就决定用这个做个例子来讲解。
CSDN 文盲老顾的博客, https://blog.csdn.net/supewrfei
游戏分析
老规矩,我们先分析一下需要完成的内容有哪些。既然是做数字华容道,我们先列举一下,这个游戏需要什么。
1、在一个特定长和宽的矩阵里,有 长 乘 宽 减 一 个可移动的方块
2、只有空位周边的方块可移动至空位
3、游戏开始时,方块顺序是混乱的
4、指定一个最终结果,作为胜利条件,如不指定,则以横向连续为胜利条件
5、用户可以通过上下左右(wsad)来移动方块
在游戏需求列完了,我们再列举一下,我们需要做哪些准备
1、可由用户指定游戏区域的宽和高
2、每个可移动块要标记一个记号
3、接收用户输入的移动方向
4、记录移动步数
5、生成胜利指定的最终结果,用以判定胜利条件
开始编写
相信已经看过 2048 的小伙伴,对这个感觉非常熟悉了。没错,大部分的内容,可能会与 2048 有些重合,但今天的内容,使用函数才是重点哦。
我们先规划一下,我们应该需要定义哪些方法:
1、用以定义长和宽的用户输入部分
2、用以显示游戏界面的部分
3、用来进行游戏时,接收用户输入的部分及移动
4、用来进行胜利判定的部分
5、用来进行游戏衔接的一些内容,比如是否开始新游戏,是否退出游戏等
完整代码
任何游戏都有一个进入游戏、开始游戏的指令。由于我们是在 python 开发环境里写,所以进入游戏就省略了,只写一个开始即可。在开发环境外,就用 python 指定运行文件的方式来进入游戏即可。
这次,老顾就先放出完整代码,然后再进行讲解。边写代码边写博客讲解有点费劲了。
import sys
import re
import random
import copy# 用来呈现用户界面
def ShowBoard(data):# 用户界面用到的制表符'''─┐┌└┘├┤┬┴┼│'''# 根据用户定义的区域大小,来确定最大数字的长度,每个数字占用位置,以此为依据计算length = len(str(data['blank'])) + 1# 输出区域顶部边界,依据是字符占位宽度 length 和 横向数字数量 data['width']print(('┌' + (('─' * length) + '┬') * data['width'])[:-1] + '┐')for i in range(data['height']):# 输出每行的数字信息print('│' + '│'.join([str(v).rjust(length) if v != data['blank'] else ' ' * length for v in data['board'][i * data['width']:(i + 1) * data['width']]]) + '│')if i < data['height'] - 1:# 如果不是最后一行,输出间隔行print(('├' + (('─' * length) + '┼') * data['width'])[:-1] + '┤')else:# 输出底部边界print(('└' + (('─' * length) + '┴') * data['width'])[:-1] + '┘')# 对游戏对象进行数据填充
def InitBoard(data):sys.stdout.flush()inp = input('如果想更改区域大小,请输入两个数字,以空格分开:')if re.fullmatch('\s*\d+\s+\d+\s*',inp):data['width'],data['height'] = map(int,inp.split())data['blank'] = data['width'] * data['height']data['success'] = list(range(1, data['blank'] + 1))data['board'] = copy.deepcopy(data['success'])random.shuffle(data['board'])# 是否新开游戏
def NewGame():a = ''while a not in 'yYnN' or len(a) < 1:sys.stdout.flush()a = input('是否开始新游戏(Y/N)?')return a in 'yY'# 游戏主线程
def GetInput(data):ShowBoard(data)sys.stdout.flush()arrow = input('请选择方向(上w下s左a右d,退出q):').lower()if arrow == 'q':return True# 得到当前空位所在的位置blank = data['board'].index(data['blank'])if arrow == 'w' and blank // data['width'] < data['height'] - 1:data['steps'] += 1data['board'][blank],data['board'][blank + data['width']] = data['board'][blank + data['width']],data['board'][blank]if arrow == 'a' and blank % data['width'] < data['width'] - 1:data['steps'] += 1data['board'][blank],data['board'][blank + 1] = data['board'][blank + 1],data['board'][blank]if arrow == 's' and blank // data['width'] > 0:data['steps'] += 1data['board'][blank],data['board'][blank - data['width']] = data['board'][blank - data['width']],data['board'][blank]if arrow == 'd' and blank % data['width'] > 0:data['steps'] += 1data['board'][blank],data['board'][blank - 1] = data['board'][blank - 1],data['board'][blank]if data['board'] == data['success']:print('你用了{}步,取得了胜利。'.format(data['steps']))return Truedef HuaRongDao():while True:data = {'width' : 4,'height' : 4,'board' : [],'steps' : 0}if not NewGame():returnInitBoard(data)while True:if GetInput(data):breakif __name__ == '__main__':HuaRongDao()
代码解说
首先,我们在 HuaRongDao 方法里定义了一个死循环,通过死循环,来保证用户不会跳出游戏。每一次循环,表示一轮新游戏。
data = {…}
然后,在循环里定义了一个初始字典,用来存放游戏数据。每轮的数据都需要重新定义。
在初始化游戏字典后,我们询问用户是否进行新游戏,如果不进行则跳出。
data[‘width’],data[‘height’]
在初始化游戏界面的方法 InitBoard 里,我们允许用户输入两个整数,来改变游戏区域大小。毕竟是小游戏,打发时间的,可以自行加难度。而我们默认的初始难度是 4 * 4 ,算是很简单的了。
data[‘blank’] = data[‘width’] * data[‘height’]
不管用户是否改变区域大小,我们之后的内容,就是根据区域大小,来填充游戏数据了,先确定最大数字是多少,将这个数字定义为空位。
data[‘success’] = list(range(1, data[‘blank’] + 1))
然后,生成一个连续序列,表示胜利时的状态。
data[‘board’] = copy.deepcopy(data[‘success’])
再然后,用深拷贝,复制一个胜利状态的数据。
random.shuffle(data[‘board’])
最后,用随机洗牌函数,将用户需要进行操作的数据打乱。
至此,游戏初始化内容完成,可以进行游戏了。
在这里,除了最初的 data 定义,其他都放在了 InitBoard 方法里。
其实最初的定义也可以放到 InitBoard ,然后 return data,在 之前定义的循环里接收这个结果。老顾随手写的是这样,就不修改了。
因为字典是一个引用型对象,所以,我们通过传递 data 这个对象,并直接修改这个对象,是相当于在原有对象上操作的,不用担心我操作的内容会丢失。
在初始化结束后,就是正式的用户交互部分了,我们定义了一个 GetInput 的方法。
而在用户输入信息前,调用了一个 ShowBoard 方法,用来显示游戏当前界面。
在现实了界面后,用户才会知道自己应该怎么移动。
在输入部分,限定一下输入内容,并允许跳出游戏。即只接收 asdwq 5个字符,其他字符视为无效。
blank = data[‘board’].index(data[‘blank’])
然后就是根据空位的信息,来验证是否移动方式可行。
data[‘steps’] += 1
如果可行,则移动步数加一。在这里,老顾定义的方向也不知道是否符合大家的习惯,如果不习惯,可以将 ws 互调,ad 互调。
if data[‘board’] == data[‘success’]:
最后,用户移动完成时,验证是否胜利。
这样,一个简单的数字华容道就完成了。
定义方法的规律
在我们定义的这几个方法里,HuaRongDao 的使用频率是最低的,他相当于游戏的主控线程。定义这个,主要是为了方便外部执行不产生冲突。
其次,频率倒数第二低的,就是 NewGame 和 InitBoard 了,每新开一轮游戏,才调用一次,如果玩上一下午,调用次数还是不少的。
再然后,就是调用频率最高的 GetInput 了,还有同样频率的 ShowBoard。
至于为什么分成两个,一个是管输出,一个是管输入控制,分开的话,逻辑就更清晰,维护更方便罢了。
最后,老顾在 GetInput 的时候,有一些情况下具有了一个 True 的返回值,在这个代码里,这个返回值就代表了游戏结束哦,不管是胜利还是退出,对游戏逻辑来说都是一样的,只是对用户反馈信息不一样罢了。
那么,大体上的朴素逻辑就出来了,就是需要多次运行的内容,做成函数或方法,不同使用频率的,则做成不同的方法。而不同用途的,或者不同功能性的,也尽量拆分开做成不同的方法,这样后续维护,也很容易定位。
在本文中,老顾就是一个举例,具体到实际,每个人都有自己的定义方法的习惯,不用照抄老顾的习惯哦。
小结
这次,我们通过一个完整的示例代码,来了解了函数、方法的使用方式,以及朴素规律,后边我们就可以自行发挥,培养自己的代码风格和书写习惯了。
多读别人的代码,是培养代码风格和熟悉习惯的办法之一。
然后,今天引用的几个包再说明一下:
1、sys 包
主要使用 sys.stdout.flush() 避免用户输入信息提示串行,造成用户输入信息时无响应
2、re 包
用正则方式判断用户是否输入了两个整数,来确定是否需要变更区域大小。如果不用正则方式,那么用户输入信息的可能性太多,做起验证也很麻烦。
3、random 包
所有使用随机数的代码都会用到,本文主要用到 random.shuffle,对迭代对象进行打乱(洗牌)处理。
4、copy 包
在复制引用类型的数据时,应该使用深拷贝,否则你可能引用的是同一个对象,最后发现数据全乱套了。
那么,今天就到这里,大家晚安。
相关文章:

python 基础系列篇:七、以函数方式编写一个数字华容道
python 基础系列篇:七、以函数方式编写一个数字华容道 数字华容道游戏分析开始编写完整代码代码解说定义方法的规律 小结 数字华容道 嗯,就是一个简单的益智游戏,把数字按照特定规律排列,并比矩阵少一个格,用来进行移…...

2023年前端面试题
1.position都有哪些属性 2.1px等于多少rem,rem根据根元素的大小,根元素是谁 3.Es6操作数组的方法 4.防抖和节流以及应用场景 5.Vue和ajax最大的区别是什么(Vue和ajax怎么操作dom的,vue虚拟dom) 6.js数据类型有哪些&…...

快速入门量化交易
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注"慕课网"! 原作者:袁霄|慕课网讲师 近来“量化交易”这个词听得越来越频繁,多数人对量化交易的第一印象是“高大上的技术”…...

Mongodb oplog
在MongoDB复制集中,oplog信息存储在oplog.rs集合中。 oplog.rs集合是一个固定大小的集合(capped collection),它位于local数据库中。 当我们在源MongoDB实例上启用了复制(replication)功能,MongoDB会自动在local数据库中创建oplog.rs集合。此后,所有在该实例上的写操作都会生…...

python基础篇: python字符串方法都有哪些?你知道多少?
❝ Python提供了丰富的字符串处理方法,可以方便地对字符串进行操作、处理和转换。在本文中,我们将介绍Python中常用的字符串方法。 ❞ python中字符串内置方法很多,可以通过dir()方式查看具体有哪些方法,下表是python字符串的全部…...

chmod 命令 (chmod 0660)
chmod的作用: 用于设置文件所有者和文件关联组的命令,就是控制用户的权限命令 注意事项: chown 需要超级用户 root 的权限才能执行此命令。 自己常用chmod 命令是 chmod 777 * 给所有文件权限 chmod 777 文件名 给单独文件权限 这个777 是怎么来的, 或者chmod 0660 这…...

Qt应用开发常用功能
Qt判断当前操作系统? #ifdef Q_OS_MAC //mac ... #endif#ifdef Q_OS_LINUX //linux ... #endif#ifdef Q_OS_WIN32 //win ... #endif#ifdef __arm__ //arm ... #endifQt实现应用程序关闭和重启? //关机按钮-点击槽函数 void SystemD::on_shutdownButton…...

麻了,部门新来的00后给我卷崩溃了...
今天上班开早会就是新人见面仪式,听说来了个很厉害的大佬,年纪还不大,是上家公司离职过来的,薪资已经达到中高等水平,很多人都好奇不已,能拿到这个薪资应该人不简单,果然,自我介绍的…...

代码随想录算法训练营第56天|583. 两个字符串的删除操作,72. 编辑距离
代码随想录算法训练营第56天|583. 两个字符串的删除操作,72. 编辑距离 583. 两个字符串的删除操作72. 编辑距离 583. 两个字符串的删除操作 题目链接:583. 两个字符串的删除操作,难度:中等 【实现代码】 class Solution { publi…...

【嵌入式笔/面试】嵌入式软件基础题和真题总结——操作系统
在学习的时候找到几个十分好的工程和个人博客,先码一下,内容都摘自其中,有些重难点做了补充! 才鲸 / 嵌入式软件笔试题汇总 嵌入式与Linux那些事 阿秀的学习笔记 小林coding 百问网linux 嵌入式软件面试合集 2022年春招实习十四面…...

2023浙江省赛“信息安全管理与评估“--Web渗透测试(高职组)
2022全国职业技能大赛“信息安全管理与评估”(高职组)任务书 2022全国职业技能大赛“信息安全管理与评估”任务书第一阶段竞赛项目试题第二阶段竞赛项目试题第三阶段竞赛项目试题任务2:Web渗透测试2022全国职业技能大赛“信息安全管理与评估”任务书 第一阶段竞赛项目试题 …...

垃圾收集器面试总结(二)
G1 收集器 G1 (Garbage-First) 是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器。 以极高概率满足 GC 停顿时间要求的同时,还具备高吞吐量性能特征。 被视为 JDK1.7 中 HotSpot 虚拟机的一个重要进化特征。它具备以下特点: 并行与并发&am…...

语音交友app开发中的用户积分系统
引言 在当今数字时代,语音交友app已成为一种流行的社交工具。它们给用户提供了一个平台,在这里他们可以结交新朋友,分享他们的生活和信仰,并建立深厚的人际关系。然而,市场上存在大量的语音交友app,这使得…...

Nature:惊人的突破!科学家们成功破译人类嗅觉感应机制的奥秘!
加州大学旧金山分校(UCSF)的科学家们创造了第一张关于气味分子如何激活人类气味受体的分子水平的3D图片,这是破译嗅觉的关键一步,该成果打破了长期以来研究人员对嗅觉理解的僵局。 该研究成果于2023年3月15日发表在《Nature》&…...
WPF教程(九)--数据绑定(2)--绑定模式
一、绑定模式 绑定模式以及模式的使用效果。 示例如下是根据ListBox中的选中项,去改变TextBlock的背景色。将 TextBlock 的背景色绑定到在 ListBox 中选择的颜色。在下面的代码中针对TextBlock的 Background 属性使用绑定语法绑定从 ListBox 中选择的值。代码如下。…...

湿法冶金以及铼提取工艺,湿法冶金工艺特点及工艺流程
湿法冶金是利用浸出剂在一定温度压力下与矿石接触,把矿石中有用的金属溶解后再从溶液中回收有价金属的一种工艺,因为其过程大都是在水溶液中进行,所以又被称为“水法冶金”。 01 湿法冶金工艺特点及工艺流程 湿法冶金作为解决我国金属矿产资…...

kafka集群搭建
1.本次搭建涉及3台centos7主机,防火墙与selinux服务均关闭 2.主机参数如下表所示 nameIPportserviceA10.1.60.1122128、2888、3888、9092kafka、zookeeperB10.1.60.1142128、2888、3888、9092kafka、zookeeperC10.1.60.1152128、2888、3888、9092kafka、zookeeper…...

【UE】将存档的值显示在控件蓝图上
上一篇博客(【UE】保存游戏的demo)已经实现了存档功能,本篇博客介绍的是如何将存档的值显示在控件蓝图上。 效果 可以看到我们存档的值显示在文本控件上 步骤 1. 新建一个蓝图类,父类为“HUD” 命名为“NewHudClassBP” 2. 在世…...

考研数据结构代码篇
文章目录 数据结构线性表基本操作顺序表的定义顺序表基本操作 单纯上传一下数据结构中可能考察的代码,规格很乱,过几天改规格,提前水一篇 数据结构 线性表 基本操作 InitList(&L) // 初始化表。构造一个空的线性表L࿰…...

css-设置单行文本溢出省略号,使用overflow:hidden属性之后的出现的问题几解决办法。
1 设置单行文本溢出后出现省略号 必要:需要设置固定宽度,不允许换行 width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; 2 设置N行文本…...

js的方法
字符串方法: substring(startIndex, endIndex):从指定的字符串中提取字符并返回新字符串,不包括结束位置的字符。substr(startIndex, length):从指定字符串中提取指定长度的字符并返回新字符串。indexOf(searchValue, startIndex…...
[NSSRound#11] 密码学个人赛
这个比赛没有参加,跟别人要了些数据跑一下,其实交互这东西基本上一样,跑通就行. ez_enc 这题有点骗人,给了一堆AB串,一开始以为是培根密码,结果出来很乱.再看长度:192 应该就是01替换 a ABAABBBAABABAABBABABAABBABAAAABBABABABAAABAAABBAABBBBABBABBABBABABABAABBAABBABAA…...

玩转树莓派四、修改国内源提高更新速度
树莓派的软件包源默认连接的是官方源,速度不是很快,我们可以更换为第三方源以提高下载速度和体验。 首先通过命令 lsb_release -a 获取到版本号为 bullseye piRpi4B2G:/etc/apt $ lsb_release -a No LSB modules are available. Distributor ID: Debian Descripti…...

苹果手机网速慢怎么办?这些方法帮你解决网速慢的问题!
案例:苹果手机数据网络信号差,怎么解决? 【家人们,苹果手机不知咋回事,网速很慢,想要在某宝买个东西都得卡个半天。哭了!有没有什么方法解决?】 苹果手机作为一款高端智能手机&…...

linux_时序竞态-pause函数-sigsuspend函数-异步I/O-可重入函数-不可重入函数
接上一篇:linux_信号捕捉-signal函数-sigaction函数-sigaction结构体 今天来分享时序竞态的知识,关于时序竞态的问题,肯定会和cpu有关,也会学习两个函数,pause函数,sigsuspend函数, 也会分享什么…...

Tomcat的负载均衡和动静分离
---------------------NginxTomcat负载均衡、动静分离------------------------- Nginx 服务器:192.168.80.10:80 Tomcat服务器1:192.168.80.100:80 Tomcat服务器2:192.168.80.101:8080 192.168.80.101:8081 1.部署Nginx 负载均衡器 system…...

C++每日一练:最长递增区间 阿波罗的魔力宝石 投篮
文章目录 前言一、最长递增区间二、阿波罗的魔力宝石三、投篮总结 前言 今天的题太简单,甚至 “最长递增区间” 和 “投篮” 就是一个问题。实在没事干,也给做了!直接上代码算了… 提示:以下是本篇文章正文内容 一、最长递增区间…...

HCIP之VLAN
目录 网络的三层架构 接入层 无线的缺陷: 上网用户数量增多,网络卡顿的原因 CSMA/CD --- 载波侦听多路访问/冲突检测 CSMA/CA --- 载波侦听多路访问/冲突避免 无线网络没有使用冲突检测技术的原因 汇聚层 连接两条线路的原因 核心层 VLAN VLAN配…...

1686_MATLAB处理Excel文件
全部学习汇总: GreyZhang/g_matlab: MATLAB once used to be my daily tool. After many years when I go back and read my old learning notes I felt maybe I still need it in the future. So, start this repo to keep some of my old learning notes servral …...

亿发软件:中大型仓库进出货管理系统解决方案,定制软件让仓储作业高效便捷
中大型仓库出入库管理是传统厂家供应链管理流程的重要部分,直接关乎货物在仓库当中存储的安全,和员工工作的效率。一旦仓库管理当中出现了疏漏,那么货物的信息数据就会发生变动,导致实际与账目不符。人工带来的低效与不可控是传统…...