Python实现还原方阵游戏:基于NumPy的逻辑推理与矩阵操作详解
本文详细介绍如何利用Python的NumPy模块开发一款还原方阵游戏。通过生成随机矩阵并给出行列连续棋子计数,玩家需推理还原原始布局。教程涵盖环境配置、矩阵初始化、用户交互逻辑、胜负判定及计分系统,适合NumPy初学者进行逻辑编程训练。
一、前言
本文的创作灵感源自一次游戏经历。在某游戏中,有玩家构建了名为“还原方阵”的趣味关卡,其精巧的设计令人印象深刻。由此引发思考:Python中强大的矩阵处理能力是否可用于复现此类游戏?
经过实践验证,该项目的开发效率极高。相较于此前耗时一周完成的蜘蛛纸牌项目,本游戏仅用2小时即完成编码,这主要得益于前期积累的编程经验。
本文将逐步引导读者完成该小游戏的开发,旨在为NumPy初学者提供一个实用的练手案例。感谢阅读,欢迎支持。
二、游戏规则
该游戏暂无官方名称,此处为便于描述而自定。
核心规则如下:系统生成一个方阵,部分位置放置棋子,部分为空。程序会提供每行和每列中连续棋子的数量信息,玩家需根据这些线索还原出完整的方阵布局。若棋子之间存在空隙,则用空格分隔表示。例如一个3x3方阵的初始状态可能如下:
棋 空 空
棋 空 棋
空 空 棋
根据上述布局,第一列包含两个连续棋子,因此给出数值2;第二列无棋子,故不提供数值;第三列包含两个连续棋子,同样给出数值2。
对于行信息,第一行有一个棋子,给出数值1;第二行有一个棋子,隔一个空格后又有另一个棋子,故给出数值“1 1”;第三行有一个棋子,给出数值1。
玩家的任务是依据提供的行列线索,推导出正确的方阵布局。
该游戏旨在锻炼逻辑推理能力。为优化用户体验,程序提供另一个矩阵供玩家标注,当玩家标注的矩阵与系统生成的正确矩阵完全一致时,游戏判定为胜利。
三、numpy模块
在编写代码前,首先介绍核心依赖库NumPy。
NumPy是Python中专门用于矩阵运算的模块,提供了丰富的函数以简化矩阵相关操作。
安装NumPy需确保已安装Python环境及pip包管理工具(若未安装请自行查阅相关教程)。在Windows系统中,按Win+R键打开运行窗口,输入cmd启动命令行,随后执行以下命令:
pip install numpy
等待安装完成,若无报错信息,则表明安装成功。随后执行以下命令:
pip list
检查pip已安装的模块列表,若其中包含numpy,则说明安装成功。
NumPy在功能上类似于嵌套列表,但其操作便捷性远超后者,许多复杂操作是普通列表无法实现的。
NumPy应用广泛,因其不像其他库那样局限于游戏、网站或爬虫等特定领域,而是作为通用“金牌辅助”,在各类涉及矩阵计算的场景中均有重要地位。例如前文提到的蜘蛛纸牌游戏也使用了该库。
NumPy支持多种赋值方式。若需对特定位置赋值,需使用二级索引,其中第一个数字代表行号,第二个代表列号,且索引从0开始。例如,将名为a的矩阵第一行第二列的值设为0,代码为a[0][1]=0。
接下来,我们将开始编写程序。
四、第一步:大循环and获取规格
首先设定游戏规则:玩家需成功还原5次矩阵即可获胜。使用while循环构建主程序框架。
为支持不同规模的矩阵,程序需获取用户输入的规格以动态调整。
首先,通过while True和try-except结构对用户输入进行校验。
采用这两者的原因在于:try-except用于处理用户输入不符合规范的情况,而while True则确保在发生错误后能提示用户重新输入。
规定支持的规格为4种:输入3对应3x3矩阵,输入4对应4x4矩阵,输入5对应5x5矩阵,输入6对应6x6矩阵。用户输入的数字必须介于3到6之间。
若用户输入其他数字,程序应如何处理?
可通过条件判断,若数字不在3至6范围内,则使用raise抛出异常,程序跳转至except块处理。这是一种严谨的处理方式。
虽然代码量稍多,但这是排除非法输入并确保程序正确运行的最佳方案。
那么,如何退出该输入循环呢?
无需复杂逻辑,只要程序执行完毕未报错,即说明输入合法,直接添加break语句退出循环即可。
win=0#初始化变量
while win<=5:#主体程序大循环
while True:#while True出山
try:#try出山
guige=int(input("输入规格,3x3输入3,4x4输入4,5x5输入5,6x6输入6"))#获取用户输入
if guige<3 or guige>6:#输入必须在3到6的数字之间
raise(VauleError())#否则直接报错
break#如果程序到了最后还没有报错就退出循环,正常执行
except:#如果报错
print("请正确输入")#让用户重新输入
至此,第一步已完成。
五、第二步:初始化棋盘
前文提到需使用两个矩阵:一个用于存储正确答案,命名为yes_numpy;另一个用于存储玩家尝试结果,命名为try_numpy。其中,1代表有棋子,0代表无棋子。
对于try_numpy中尚未标记的位置,该如何处理?
此处需引入None值。
None是一个特殊值,转换为布尔类型时为False,它既不是0也不是空字符串,表示“无值”。例如,获取无返回值的函数结果时,通常得到None。
虽然矩阵元素不能为字符串,但可以为None。
需将矩阵所有元素初始化为None,可通过两层嵌套for循环实现赋值。
对于yes_numpy,其元素需在0和1之间随机生成,同样使用两层嵌套for循环进行赋值。
为简化代码,将numpy模块别名为np,random模块别名为r。
完整初始化代码如下:
import random as r#导入random模块
import numpy as np#导入numpy模块
print("正在生成题目…")#提示
yes_numpy=np.zeros((guige,guige))#yes_numpy为全0矩阵
try_numpy=np.zeros((guige,guige))#try_numpy为全0矩阵
for i in range(guige):#第一层循环为行
for j in range(guige):#第二层循环为列
try_numpy[i][j]=None#try_numpy全部赋值为None
print(try_numpy)#输出try_numpy
for i in range(guige):#第一层循环为行
for j in range(guige):#第二层循环为列
yes_numpy[i][j]=r.choice((1,0))#yes_numpy赋值为1 0随机数
六、第三步:标注矩阵功能(难)
接下来是程序的核心部分。
首先需获取用户执行的操作。目前支持5种操作:标注矩阵填1,查看标注矩阵填2,胜利侦测填3,查看行列信息填4,重新开始填5。
由于这些操作需重复执行,使用while True包裹主逻辑。
获取用户操作时,依然采用while True和try-except组合,并结合raise和break,思路与第一步一致。由于外层已有循环,可省略一层while,将break替换为continue。
首先实现标注矩阵功能,即修改try_numpy。当用户输入1时,执行以下逻辑。
随后需让用户输入要修改位置的行、列及目标值(0、1或None),这需再增加一层while True和try-except。
这也是为何强调添加注释和控制代码层级的重要性。此类程序常涉及多层循环嵌套,逻辑复杂,此处已达第五层嵌套。
如此设计的原因在于,此前开发的蜘蛛纸牌项目因结构复杂导致运行卡顿、耗时较长且易出错,甚至出现输入时自动弹出乱码导致报错的问题。吸取教训后,本程序采用了更严谨的结构。
需考虑两种异常:输入超出矩阵范围,或修改的值非0或1。将这些异常控制在初始阶段,确保用户输入合法。
修改矩阵逻辑简单,只需定位对应位置并赋值即可。
若上述逻辑难以理解,请结合代码进行对照:
while True:#游戏开始
try:#还是熟悉的try
caozuo=int(input("输入操作,标注矩阵填1,查看目前改变矩阵填2,胜利侦测填3,查看行列信息填4,重新开始填5。"))#询问操作
if caozuo<1 or caozuo>4:#必须1到4之内
raise(ValueError())#报错
except:#如果错误
print("请正确输入")#提示
continue#从头开始
if caozuo==1:#如果操作是1
while True:
try:#老两样
gai_hang,gai_lie,gai_neirong=map(int,input("输入标注位置的行、列(下标),以及改变成0还是1(用空格隔开三个值)\n").split())#询问三个标注信息
if gai_neirong<0 or gai_neirong>1:#内容非0即1
print("只能改变成0和1,",end="")#提示
raise(ValueError())#报错
if gai_hang>=guige or gai_lie>=guige:#行列不能超出矩阵规格
print("输入超出规格,",end="")#提示
raise(ValueError())#报错
break#如果没有异常就退出循环
except:#如果异常
print("请正确输入")#提示
try_numpy[gai_hang][gai_lie]=gai_neirong#赋值
print("标注成功")#提示
continue#从头开始,节约时间此部分较为复杂,建议仔细理解并消化。
七、第四步:查看标注矩阵功能
接下来实现查看标注矩阵的功能。
该功能实质上是输出try_numpy的内容。
if caozuo==2:#如果要查看标注矩阵
print(try_numpy)#直接输出
continue#从头开始,节约时间
实现起来相对简单。
八、第五步:胜利侦测
为节省运行时间,胜利侦测仅在用户输入3时触发。
不能直接比较两个矩阵是否相等,需使用NumPy提供的all()函数。将两个矩阵通过等号连接进行比较,返回True或False。
if caozuo==3:#如果要检测是否胜利
if np.all(yes_numpy==try_numpy):#如果两个矩阵全部相等
print("你胜利了!")#提示
zhuangtai="win"#改变变量
break#退出循环
else:#否则
print("还不对哦!")#提示
continue#从头开始
这些代码位于while True循环内,因此可使用break退出,并返回至win<5的外层循环。建议结合完整代码理解。
此处新建变量zhuangtai,是为了后续区分玩家是因获胜还是因重新开始而退出大循环。
九、第六步:查看行列信息(难)
接下来实现查看行列信息的程序。
由于矩阵完全随机,程序需自行侦测并输出行列信息。
设置一个计数变量shu。
逻辑如下:若侦测到1,则shu自增。
若侦测到0且前一项为1,则输出shu加空格,随后将shu清零。
若侦测到0且前一项为0,则不输出,可忽略侦测。
若遍历结束后shu不为0,则输出shu并换行。
逐行逐列进行侦测并输出结果。
具体程序如下,请仔细消化:
shu=0
if caozuo==4:#如果要查看行列信息
for i in range(guige):#每一行
print("第",i,"行:")#提示到底是第几行
for j in range(guige):#每一列
if yes_numpy[i][j]==1:#如果矩阵的这一格为1
shu+=1#shu自增
if yes_numpy[i][j]==0:#如果矩阵的这一格为0
if shu!=0:#且前一格不是0(直接侦测shu的状态效果一样)
print(shu,end="")#输出shu
shu=0#shu清零
if shu!=0:#如果结束之后shu不为0
print(shu)#输出shu要换行
shu=0#shu清零
print()#输出空行之后显示列
shu=0#初始化变量
#以下程序是把遍历行列进行交换,来达到不用改变主体侦测矩阵列的效果
for j in range(guige):
print("第",j,"列:")
for i in range(guige):
if yes_numpy[i][j]==1:
shu+=1
if yes_numpy[i][j]==0:
if shu!=0:
print(shu,end="")
shu=0
if shu!=0:
print(shu)
shu=0
print()十、第七步:重新开始功能
矩阵重新开始只需break,但需调整zhuangtai变量。
#内层循环的程序
if caozuo==5:#如果操作是5
zhuangtai="0"#状态区分
break#直接退出循环
#这里是最外层循环的程序
if zhuangtai=="win":#如果是因为获胜退出的循环
win+=1#win自增
十一、得分与完善and完整代码
可添加得分功能以完善程序,使用变量defen记录分数,提升玩家成就感。
整合上述程序并修复各种Bug,最终代码如下:
import numpy as np
import random as r
win=0
defen=500
shu=0
print("游戏开始。游戏规则:我会给出一个矩阵,并且给出每行每列有几个1的个数信息,如果有两个数字代表有两个空,举个例子:\n[[ 1,1,1]\n[0,0,1]\n[1,0,0]]\n在这个列表中,例如第0列为1,0,1,有两个间断的1那我就给出1 1,第1列有1 0 0,那我就给出1,第2列为1,1,0,有两个不间断的1那我就给出2。\p,请复原这个矩阵。\n另外还有分数系统,标注错一次-10分,标注对一次+10分,初始500分,获胜了+规格x50分。\n胜5局即可胜利。\n")
while win<=5:
while True:
try:
guige=int(input("输入规格,3x3输入3,4x4输入4,5x5输入5,6x6输入6"))
if guige<3 or guige>6:
raise(VauleError())
break
except:
print("请正确输入")
print("正在生成题目…")
yes_numpy=np.zeros((guige,guige))
try_numpy=np.zeros((guige,guige))
for i in range(guige):
for j in range(guige):
try_numpy[i][j]=None
print(try_numpy)
for i in range(guige):
for j in range(guige):
yes_numpy[i][j]=r.choice((1,0))
print(yes_numpy)
while True:#游戏开始
try:
caozuo=int(input("输入操作,标注矩阵填1,查看目前改变矩阵填2,胜利侦测填3,查看行列信息填4,重新开始填5。"))
if caozuo<1 or caozuo>4:
raise(ValueError())
except:
print("请正确输入")
continue
if caozuo==1:
while True:
try:
gai_hang,gai_lie,gai_neirong=map(int,input("输入标注位置的行、列(下标),以及改变成0还是1(用空格隔开三个值)\n").split())
if gai_neirong<0 or gai_neirong>1:
print("只能改变成0和1,",end="")
raise(ValueError())
if gai_hang>=guige or gai_lie>=guige:
print("输入超出规格,",end="")
raise(ValueError())
break
except:
print("请正确输入")
try_numpy[gai_hang][gai_lie]=gai_neirong
if try_numpy[gai_hang][gai_lie]==yes_numpy[gai_hang][gai_lie]:
defen+=10
else:
defen-=10
print("标注成功")
continue
if caozuo==2:
print(try_numpy)
continue
if caozuo==3:
if np.all(yes_numpy==try_numpy):
print("你胜利了!")
zhuangtai="win"
defen+=200
break
else:
print("还不对哦!")
continue
if caozuo==4:
for i in range(guige):
print("第",i,"行:")
for j in range(guige):
if yes_numpy[i][j]==1:
shu+=1
if yes_numpy[i][j]==0:
if shu!=0:
print(shu,end="")
shu=0
if shu!=0:
print(shu)
shu=0
print()
shu=0
for j in range(guige):
print("第",j,"列:")
for i in range(guige):
if yes_numpy[i][j]==1:
shu+=1
if yes_numpy[i][j]==0:
if shu!=0:
print(shu,end="")
shu=0
if shu!=0:
print(shu)
shu=0
print()
if caozuo==5:
zhuangtai= "0 "
break
if zhuangtai=="win":
win+=1
print("获胜达到5局!你真厉害!目前的分:",defen)注:代码第26和31行为了方便测试直接输出了两个矩阵,正式游玩时请删除这两行代码。
至此,关于利用Python还原方阵游戏的详解文章结束。更多相关Python内容请搜索本站往期文章或继续浏览相关文章,希望大家多多支持本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









