利用Python还原方阵游戏详解
¿¿¿¡¡¡ 人气:0一、前言
写这篇文章的灵感来源于我玩游戏的时候(为了避免过不了审就不说是啥游戏了),看见一个大佬在游戏里面建造了“还原方阵游戏”,就感觉很牛掰,就想着python不是有矩阵吗,可不可以还原一下呢?
说干就干,我写的那个蜘蛛纸牌用了一星期,写这玩意儿只用了2小时,估计是有了经验吧。
这篇文章会手把手教你完成这个小游戏,算是新手的numpy练手程序了。写作不易,支持一波~
二、游戏规则
其实这个游戏我也不知道叫啥,就是自己瞎编的名字(bushi。
游戏规则:有一个方阵,里面有的点位有棋子,有的点位没有棋子,我会给出每行每列的棋子个数,请复原这个方阵。注:如果棋子之间有空位就用空格代替。例如这个方阵:
棋 空 空
棋 空 棋
空 空 棋
第一列里面有两个连续的棋子,那我就给出2。第二列里没有棋子,那我就啥也不给。第三列里有两个连续棋子,那我就给出2。
第一行里有一个棋子,那我就给出1。第二行里有一个棋子,空一格又有一个棋子,那我就给出1 1。第三行里有一个棋子,那我就给出1。
通过给出的信息,请还原方阵。
这个游戏是对逻辑思维的推理。为了方便用户操作,我们给出另一个矩阵,让用户在上面标注,当标注矩阵=正确矩阵就结束游戏。
三、numpy模块
写代码之前,我们先了解一下numpy模块。
numpy模块,就是矩阵模块,其中有很多很多的函数,让我们完成矩阵的相关操作。
安装numpy模块,首先你要有python,之后要有万能的pip包(没有自己网上查怎么下载)。之后,我们win+R,输入cmd打开熟悉的命令行,输入:
pip install numpy
等一会儿,如果没出现错误就是安装成功了。之后输入:
pip list
来查看pip包所有安装的模块,有numpy就是成功了。
numpy,其实和嵌套列表差不多,但是人家操作十分方便,有许多函数都是嵌套列表做不到的。
numpy可以在很多方面发光发热,因为它不像其他模块那样,专门做游戏,专门做网站,专门爬虫等等啥的,无论是什么方面,都常常遇到矩阵,可以说是个金牌辅助了。我之前那做的那个蜘蛛纸牌游戏也是用的他。
numpy的赋值有很多方法,如果你要给其中一个位置赋值,那就要用二级索引,在numpy里面第一个数字代表第几行,第二个代表第几列。注意要用下标数字哦!例如我们要把一个叫做a的矩阵的第一行第二列变成0,那我们就a[0][1]=0。
接下来,我们就开始写程序吧!
四、第一步:大循环and获取规格
首先,我们设置一个规则:还原矩阵5次时候就胜利了。用while把主体程序套进大框架里面。
为了能调整不同的大小,我们可以获取用户的输入来调整规格。
首先,我们要来帮用户正骨,就用while True和try-except。
为啥要用他俩兄弟呢?首先,try-except的作用是在用户输入不正确或不符合规定时作出处理,while True则是为了作出处理之后让用户重新来输入一遍。
我们现在就规定:规格有4种,让用户3x3输入3,4x4输入4,5x5输入5,6x6输入6。用户的数字就必须在3到6之间。
但是如果用户输入的是其他数字呢?
没事,我们可以用一个条件判断,如果数字不是3~6之间就直接掏出raise,抛出异常,程序转移到except那边。是不是很完美?
别看这样写字多了,这是排除所有其他输入还能正确运行的最佳方案。
那么该怎么退出循环呢?
nonono,不要想太复杂了,只要程序执行完了还没有报错就说明输入正确,直接加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循环,赋值0或1的随机数。
为了方便,我们把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!
知道为啥让你们有注释和减少层级了吧?写这样的程序的时候经常循环套循环,太乱了!写到这里已经是第五层程序了。
我这么做也是有原因的,因为上一个写的蜘蛛纸牌程序比较大型,用起来很卡,时间也长,容易输入错误,并且不知道为啥输入的时候总是自动弹出来一个cde fg,不知道你们有没有这种问题,导致报错。这个程序就长教训了。
输入超出矩阵范围或者修改的不是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退出,再回到while 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行为了方便测试直接输出了两个矩阵,玩的之后删了这两行代码就行。
加载全部内容