哈利波特之心灵感应魔法是一种常见的儿童益智游戏。表演者首先会要求观众在心中默想一个60以内的整数,然后依次将下述卡片1到卡片6出示给观众看,并询问观众他所默想的数字是否在卡片上。在卡片出示的过程中,卡片是背对表演者的,即表演者是看不到卡片的。在听完观众的6个回答之后,表演者即可"猜"出观众默想的数字,仿佛掌握了"读心术"。
本文引用自作者编写的下述图书; 本文允许以个人学习、教学等目的引用、讲授或转载,但需要注明原作者"海洋饼干叔
叔";本文不允许以纸质及电子出版为目的进行抄摘或改编。
1.《Python编程基础及应用》,陈波,刘慧君,高等教育出版社。免费授课视频 Python编程基础及应用
2.《Python编程基础及应用实验教程》, 陈波,熊心志,张全和,刘慧君,赵恒军,高等教育出版社Python编程基础及应用实验教程
3. 《简明C及C++语言教程》,陈波,待出版书稿。免费授课视频
表演者显然没有"读心术", 他依赖于观众关于数字在不在卡片上的6个回答来计算答案。解题思路与二进制有关。一个6位的二进制数,其可以表达的最大数字是26 - 1 = 63。所以,任意60以内的整数,都可以用不超过6位的二进制数来表达。比如,41,其二进制值如下图所示:
我们以十进制整数(4321)₁₀来说明表3.3中的位号、位值及位权。位值1、2、3、4从低到高,分别处于位号1(个位)到位号4(千位)。而(4321)₁₀ = 4 ⅹ10³ + 3ⅹ10²+2ⅹ10¹+1ⅹ10⁰,这里的10³为位号4的位权,10⁰为位号1的位权。同理,(41)₁₀=(101001)₂中,位号6处的位值为1,其对应的位权为2⁵=32;位号2处的位值为0,其对应的位权为2¹=2。
每一个60以内的整数,均可转换成一个6位二进制数。如果对应的二进制数的第1位(最低位)为1,该数包括在卡片1中,同理,二进制第2位为1的数包括在卡片2中,… 二进制第6位为1的数包括在卡片6中。上述数字41,其二进制的第1, 4, 6位为1。读者可以看到,41只出现在卡片1,4,6中,卡片2,3,5里没有41。所以,观众每回答一个按顺序给出的问题,其实就告诉了表演者该数字6位二进制数中的其中一位是0还是1。
我们用数字58来模拟一下。卡片1,3里没有58,卡片2,4,5,6里有58。所以表演者从观众那里得到的回答从1到6依次是:无,有,无,有,有 ,有。将上述回答换成二进制就是111010。按照对应的位权把0b111010换成十进制就是32+16+8+2 = 58。
现在我们知道表演者是如何表演的了。他一直在做加法,从0值开始。如果卡片1的回答是有,加1,卡片2的回答是有,加2,卡片3有,加4,… , 卡片6有,加32。最后直接报出和数即可。
读者可以运行下述程序才模拟执行上述游戏过程:心里先默想一个数,然后运行程序,通过输入y或者n来回答6个问题。看看计算机能否猜出你默想的数,是否跟你有心灵感应。
#nummagic.py
card1 = """Card 1:
1 11 21 31 41 51
3 13 23 33 43 53
5 15 25 35 45 55
7 17 27 37 47 57
9 19 29 39 49 59"""
...
card6 = """Card 6:
32 37 42 47 52 57
33 38 43 48 53 58
34 39 44 49 54 59
35 40 45 50 55 60
36 41 46 51 56 *"""
sQuestion = "\nIs your number in this card? y for yes, n for no:"
b1 = 1 if input(card1+sQuestion).lower().strip() == 'y' else 0
b2 = 1 if input(card2+sQuestion).lower().strip() == 'y' else 0
b3 = 1 if input(card3+sQuestion).lower().strip() == 'y' else 0
b4 = 1 if input(card4+sQuestion).lower().strip() == 'y' else 0
b5 = 1 if input(card5+sQuestion).lower().strip() == 'y' else 0
b6 = 1 if input(card6+sQuestion).lower().strip() == 'y' else 0
print("Binary answer:",b6,b5,b4,b3,b2,b1)
print("The number is:", b6*32 + b5*16 + b4*8 + b3*4 + b2*2 + b1*1)
执行结果(输入依次为y,y,y,y,n,y):
...
Card 6:
32 37 42 47 52 57
33 38 43 48 53 58
34 39 44 49 54 59
35 40 45 50 55 60
36 41 46 51 56 *
Is your number in this card? y for yes, n for no:y
Binary answer: 1 0 1 1 1 1
The number is: 47
代码说明
变量card1-6是6个用"““包裹起来的多行字符串;””"除了用于多行注释外,也可以用于表达一个多行字符串。
input().lower().strip()涉及三个函数,input()函数提示操作者输入并返回输入的字符串;该字符串对象的lower()成员函数返回一个新字符串,其为原字符串的小写形式;最后执行lower()函数返回字符串的strip()成员函数,去除其前后空格。
b1 = 1 if input(card1+sQuestion).lower().strip() == ‘y’ else 0称之为条件语句,我们将在后续6.2节中正式讨论。如果输入是"y"或者"Y",b1为1,否则为0。
b6,b5,b4,b3,b2,b1分别对应数字的6个二进制位,倒数第二行使用print()将数字的二进制形式打印出来。
将每个二进制位乘以对应的位权,然后相加,即得猜测数。
为了帮助更多的年轻朋友们学好编程,作者在B站上开了两门免费的网课,一门零基础讲Python,一门零基础C和C++一起学,拿走不谢!
如果你觉得纸质书看起来更顺手,目前Python有两本,C和C++在出版过程中。