通过游戏编程学Python(4)— 猜成语(上)
通过游戏编程学Python(3)— 赌大小
通过游戏编程学Python(2)— 脑筋急转弯
通过游戏编程学Python(1)— 猜数字
文章目录
- 通过游戏编程学Python
- 前言
- 一、知识点
- 二、第四个游戏 —— 猜成语(下)
- 1. 玩法简介
- 2. 游戏流程
- 三、程序代码(略)
- 四、用到的知识点
- 5. random模块里的其它函数
- 6. range对象
- 7. for循环
- 8. 游戏代码解析
- 总结与思考
前言
大家好,上节课不得已把内容一分为二,为的是尽可能清楚地把基础知识点覆盖全面。这样一来,当讲到后面稍微复杂一点的游戏程序时,我们可以更加关注编程的思路,以及代码的实现方法,而不用再去纠结具体的语法细节。
所以,本节课开始,问哥在最后的部分,会带着大家从头捋一遍游戏代码执行的全过程。以期从一个更全面的视角去看整个程序是如何实现游戏的。希望大家都能有所得着。
一、知识点
- 常量(上)
- 面向对象(上)
- 函数与方法(上)
- 列表及常用操作(上)
- random模块里的其它函数
- range对象
- for循环
首先准备一个四字成语词库,可多可少,不设限制(本例中准备了30个四字成语)。由计算机从里面随机抽取出一个成语,再从成语里随机取出两个汉字作为提示(如果太简单,可以改为只提示一个汉字),由玩家去猜这个成语是什么。程序会把成语里未知的部分汉字用X遮住打印出来。玩家共有6次机会,如果猜对了或者连续猜错6次,游戏结束。并询问玩家是否继续玩,如果玩家回答的不是yes或y,程序结束。
2. 游戏流程 三、程序代码(略)四、用到的知识点 5. random模块里的其它函数全部代码:见“猜成语(上)”
我们在前几课的例子里使用了random模块里的randint()函数,用来随机返回一个整数。这在游戏编程里可以说是最常被用到的,因为大多数游戏都需要随机性,比如主角的运气、敌人随机出现的位置等。但random这个模块里还提供了很多其他有用的函数。
比如本例中使用到的random.sample() 和random.choice() 函数:
提示字 = random.sample(range(4), 提示字数) 电脑选词 = random.choice(WORD)
random.sample()函数接收两个参数,第一个参数是容器类对象(可以是列表、range等),第二个参数是整数,表示数量。整个函数的意思就是从一个容器类对象里(本例使用range(4),稍后会介绍),随机选取几个(第二个参数)元素,组成一个新的列表并返回。本例中想要完成的功能是从0到3之间随机选取一或两个数字(根据玩家选择的难度决定变量提示字数的值),组成一个列表,赋值给变量提示字。
random.choice()函数只接收一个参数,就是容器类对象。函数的意思是从一个容器类对象里(本例是名为WORD的字符串列表)随机选出一个元素出来。本例中就是让电脑在我们定义好的成语词库里随机选一个出来,作为用户将要猜的成语。
注意:random.sample()函数返回的是列表,即使只选1个元素,返回的也是只含有一个元素的列表。而random.choice()函数返回的是一个元素。
6. range对象Python里的range是一个类(比对象更“高级”,但暂时不需要了解太多),其中的实例range对象并不是列表,而是表示一个整数范围。当不调用range的时候,它不包含任何元素,但当调用的时候,比如使用for循环,就可以像列表一样逐个读取里面的元素。形象地说,它表示了一条“定义元素的公式”。
可以使用range()创建一个range对象,数字范围,比如range(0, 5)就代表了从0到4,共5个整数。注意括号里右边的数字不在范围内,相当于数学上的 [0, 5)。如果括号里左边数字是0,可以省略,比如range(0, 5)可以简写为range(5)。
range()最最最常用的功能就是配合for循环,实现循环次数的控制。其次,就可以向列表一样代表一个数字范围,比如在本例中,就表示从0, 1, 2, 3四个整数中选取1或2(取决于变量提示字数的值)个数字。
提示字 = random.sample(range(4), 提示字数)
此外,我们还可以使用list()函数将一个range转换成包含范围内所有整数的列表。这在我们需要创建一个连续整数的列表时相当快捷。
编程无外乎两大法宝,判断和循环。无论多么复杂的程序,都是不断使用这两种手段、累积而成的。我们已经认识到 if…elif…else 判断语句,而 while 循环也是先判断(条件是否为True)再循环代码块里的操作。今天我们会接触到更为常用的一种循环语句,for循环,或者称为 for…in…循环。
使用方法如下:
for语句与其说是循环,不如说是遍历来得更为准确。它表示在一个容器里,从第一个元素,遍历到最后一个元素,然后在遍历的同时,顺便执行代码块里的所有语句。
上面例子里的 i 是一个临时变量,可以给它起任何名字。第一次循环的时候,for语句将容器里第一个元素赋值给 i,然后执行代码块(比如例子中的print(i)),执行后再回到for语句把第二个元素赋值给 i,如此循环第三次、第四次、直到把容器里的元素全都赋值一遍。所以当循环结束时,i 的内容是容器里最后一个元素。
比较有意思的是,代码块里的代码也可以完全不用调用变量 i。这个时候,i仅仅表示了循环次数的计数器。这种场景里,for循环常常与range()连用,表示某些代码重复操作多少次:
与while循环本质上不同的是,for循环不需要判断语句,而且可以比较容易地“预见”到循环的次数。更为重要的是for循环的遍历功能,在依次调用容器类对象的元素时非常有用。比如下面的例子,for…in…循环遍历了列表[1, 2, 3, 4, 5],并将里面的元素从头到尾逐个计算平方值并打印出来。
在了解了所有必须掌握的代码知识和函数用法后,让我们从头到尾解析一下代码。
游戏首先定义了一个成语库,保存在WORD常量里,然后定义了几个函数。我们可以先略过。然后从52行代码开始,电脑首先打印了游戏名,代表游戏开始。
print('《 开 心 猜 成 语 》n')
然后调用了难度选择() 这个自定义函数,
提示字数 = 难度选择()
根据玩家的选择(1或者2),决定是提示两个字(简单)还是一个字(困难)。
def 难度选择():
难度 = ''
while 难度 != '1' and 难度 != '2':
print('请选择游戏难度:(1-简单,2-困难)')
难度 = input()
if 难度 == '1':
return 2
else:
return 1
然后根据玩家选择的难度,随机选择出要提示成语里哪几个汉字。这里random.sample()函数从0、1、2、3里随机抽取一或两个不重复的随机数字,代表一个或两个会被提示的汉字在成语里的位置索引(还记得我们说过字符串的列表属性),于是,相应位置的汉字会被显示,以达到“提示”的目的。
提示字 = random.sample(range(4), 提示字数)
同时,定义了一个空的列表,用来存储玩家猜错的词语。设定了一个布尔值作为游戏是否结束的“标记”,还记得我们提到过的布尔值就像开关一样吗?游戏开始的时候,游戏当然没结束,所以它的值是False。而当游戏结束的时候,我们将它的值改为True,程序就会询问是否要通过break跳出while循环,结束程序。此外,电脑在这个时候从成语库里随机抽取了一个成语,作为玩家等会儿要猜的成语。
错词表 = [] 游戏结束 = False 电脑选词 = random.choice(WORD)
游戏正式开始的所有代码,是放在一个“死循环”里的。在我们后面讲到的例子里,会不断的使用类似的“死循环”。因为游戏就是一种不断循环的状态,只有当从用户接收到指令才会中断,比如本例中,只要用户最后输入的字符不是y,程序就会中断循环。
while True:
显示状态(提示字, 电脑选词)
猜 = 猜字母(错词表)
同时程序调用了两个自定义函数,显示状态() 和猜字母() ,前一个函数的功能就是把带有提示字的成语打印在终端上,后一个函数的功能是让玩家输入四个汉字,并通过主程序传入的错词表来判断玩家有没有猜过这个字。
def 显示状态(提示字, 电脑选词):
填空 = 'XXXX'
for i in 提示字: # 把X换成提示字
填空 = 填空[:i] + 电脑选词[i] + 填空[i+1:]
for 字 in 填空: # 汉字之间加上空格打印出来
print(字, end=' ')
print('n')
def 猜字母(猜过啥):
while True:
print('猜猜看,这是什么成语呢?')
print()
猜 = input()
if len(猜) != 4:
print('请输入一个四字成语')
print()
elif 猜 in 猜过啥:
print('这个词你已经猜过了,换一个试试吧')
print()
else:
return 猜
获取到玩家猜测的词组后,回到主程序while True循环里,去判断这个词是不是电脑所选的成语。如果猜对了,打印出“你赢了”,并设定游戏结束为True。如果猜错了,程序提示“不对哦”,并把猜错的词添加进错词表。然后再进入第二个循环,通过检查有多少个错词(使用len()函数),来判断用户是否已猜错达到6次,如果是,则公布答案,并结束游戏,如果没有达到6次,则又回到white True循环的最开始,重新让玩家猜。
if 猜 == 电脑选词:
# 如果猜对了游戏结束
print('没错!就是“' + 电脑选词 + '”!你赢了!')
游戏结束 = True
else:
print('不对哦~n')
错词表.append(猜)
# 检查玩家是否猜错太多次
if len(错词表) == 6:
显示状态(提示字, 电脑选词)
print('很遗憾,你已经猜错' + str(len(错词表)) + '次,游戏结束。' + '正确的成语是“' + 电脑选词 + '”。')
游戏结束 = True
在while循环的最后部分,通过检查游戏结束标记,来判断是否要重新开始游戏,还是关闭程序。这时调用再玩一次() 的函数,如果玩家输入以y开头的字符,则函数返回True,表示玩家想要再玩一次。则主程序里再开始游戏准备工作:难度选择、清空错词表、重置游戏结束标记、电脑重新选一个词等,然后回到while循环。如果玩家输入任何其他字符,函数返回False,则主程序执行break语句跳出while循环。程序结束。
if 游戏结束:
if 再玩一次():
提示字数 = 难度选择()
提示字 = random.sample(range(4), 提示字数)
错词表 = []
游戏结束 = False
电脑选词 = random.choice(WORD)
else:
break
def 再玩一次():
# 如果玩家输入yes或y,则游戏从头再来,否则游戏结束
print('还要继续玩吗?(yes-是,no-否)')
return input().lower().startswith('y')
总结与思考
好了,这两节课的游戏虽然还比较简单,已经可以初步看见调用自定义函数的威力了。把需要调用的某段功能封装成函数,放在主程序之外,等到需要用到的时候,就像填空一样把它召唤过来。如此一来,主程序会变得异常简洁易懂。后面几节课,问哥打算遵照书本的顺序,分析一下 Al Sweigart举的几个代表性的例子。
另外,我们需要掌握的基础语法,而且还相当好用的知识点——字典,也将在下节课为大家介绍。下次再见咯~



