COMP9021 Principles of Programming WEEK2

1. Monty Hall Problem

一个著名的博弈论游戏,起源大概是一个美国电视游戏节目叫做Let's make a deal,这个问题名字来源于节目主持人Monty Hall
游戏简述:
“参赛者会看见三扇关闭了的门,其中一扇的后面有一辆汽车或者是奖品,选中后面有车的那扇门就可以赢得该汽车或奖品,而另外两扇门后面则各藏有一只山羊或者是后面没有任何东西。当参赛者选定了一扇门,但未去开启它的时候,知道门后情形的节目主持人会开启剩下两扇门的其中一扇,露出其中一只山羊。主持人其后会问参赛者要不要换另一扇仍然关上的门。问题是:换另一扇门会否增加参赛者赢得汽车的机会率?如果严格按照上述的条件的话,答案是会。—换门的话,赢得汽车的概率是2/3。”
用python仿写这个游戏

大多程序都可以拆解为输入、处理和输出。本题就是按照这个思路写出相应的程序

1.1 输入1--模拟次数

While True:
#注意boolean的书写是大写的T,True
    try:
        n = int(input('How nany times do you want to run the simulation? '))
        #如果出现异常,不会继续运行try后面的程序行,而是跳入exceept程序段执行程序
        break
        #跳出当前循环,注意,如果有多个循环的时候,一次break不能跳出所有循环。
    except ValueError:
        print('Incorrect input, try again')
#这样实现了用户多次输入的功能,允许用户多次输入来调整想要的输入值。

这段程序使用的是之前lab1用过的try ... except ...被动异常捕获方法,但是只能保证输入值是int,而我们的输入值不仅是int,还需要>0,这里新引入一种主动异常处理方式--raise

While True:
    try:
        n = int(input('How nany times do you want to run the simulation? '))
        if n < = 0:
            raise ValueError
            #rasie命令使得程序进入except ValueError程序块,不执行后续的try程序块的命令。
        break
    except ValueError:
        print('Incorrect input, try again')

1.2 输入2--更改答案

和上文同理

while True:
    try:
        n = int(input('How nany times do you want to run the simulation? '))
        if n <= 0:
            raise ValueError
        break
    except ValueError:
        print('Incorrect input, try again')
print(n)

while True:
    switch = input('Do you want to switch? ')
    if switch in {'yes', 'Yes', 'y', 'Y'}:
        switch = True
        #由于switch只有两种情况,赋予boolean值效率最高,不要赋予其他int值。
        break
    if switch in {'no', 'No', 'n', 'N'}:
        switch = False
        break
    else:
        print('Incorrect input, try again')

1.3 游戏初始化

在三扇门后面要随机选择一个放入大奖,需要用随机函数来写,之前讲过import random,接下来的问题是查询使用哪个函数更方便。查询random的函数方法是dir(random),但是其中会有很多initilize的函数,这些函数命名两端是_,把他们删除的显示方法如下

import random
[x for x in dir(random) if not x.startswith('_')]

上文程序写法是简化的list生成方法,它等于下文程序

import random
result = []
for x in dir(random):
    if not x.startswith('_'):
        result.append(x)
result

从中选取了choice函数,因为它的属性是Choose a random element from a non-empty sequence.

from random import *
doors = ['A', 'B', 'C']
#用list记录三扇门
nb_of_wins = 0
#记录获奖次数,初始化为0
winning_door = choice(doors)
#随机从doors的list中选择一个放置大奖
first_choice = doors.pop(randrange(3))
#在index[0,2]中随机抽选一个int作为用户的初始选择index,并把doors中对应index的门assign给first_choice,再从doors中删除

1.4 游戏过程

游戏过程是主持人删除了一个错误答案,玩家决定是否更换选项。

if not switch:
#前文把switch赋予了boolean值,所以可以直接用not switch判断True or False
    second_choice = first_choice
if first_choice = winning_door:
#如果first_choice是winning_door,打开的门可以是doors剩下两扇门中的任何一个
    opened_door = doors.pop(randrange(2))
    #从剩下两扇门中随意找到一扇门打开,接下来是要看玩家选项是否switch
    if switch:
        second_choice = doors[0]
        #因为此时doors的list中只有一个元素,所以switch的话,就把doors中剩下的这个元素(index一定是0)assign给second_choice
    else:
        nb_of_wins += 1
        #因为最开始已经定义not switch时second_choice的赋值问题,所以可以直接确定中奖。
else:
    doors.remove(winning_door)
    #因为first_choice不是大奖,所以要从doors的list中删除大奖的门,大奖的门不能被主持人打开
    opened_door = doors[0]
    #此时doors的list中只剩下一个非大奖选项
    if switch:
        second_choice = winning_door
        nb_of_wins += 1      

1.5 模块组合和结果输出

输入模块、游戏初始化和游戏过程都已经写好,接下来整合模块,并且按照要求输出结果

from random import choice, randrange

while True:
    try:
        n = int(input(input('How nany times do you want to run the simulation? '))
        if n <= 0:
            raise ValueError
        break
    except ValueError:
        print('Incorrect input, try again')

while True:
    switch = input('Do you want to switch? ')
    if switch in {'y', 'Y', 'yes', "Yes'}:
        switch = True
        break
    if switch in {'n', 'N', 'no', ‘No'}:
        switch = False
        break
    print('Incorrect input, try again')

for _ in range(n):
    doors = ['A', 'B', 'C']
    winning_door = choice(doors)
    nb_of_wins = 0
    first_choice = doors.pop(randrange(3))
    if not switch:
        second_choice = first_choice

    if first_choice == winning_door:
        opened_door = doors.pop(randrange(2))
        if switch:
            second_choice = doors[0]
        else:
            nb_of_wins += 1
    else:
        doors.remove(winning_door)
        opened_door = doors[0]
        if switch:
            nb_of_wins += 1
            second_choice = winning_door
    
    print('Winning door:', winning_door)
    print('First choice:', first_choice)
    print('Opened door:', opened_door)
    print('Seconc choice:', second_choice)
    print()
print(nb_of_wins)

运行结果会发现switch的获奖概率是2/3,not switch的获奖概率是1/3。

2. PDF automated form filling

这个部分的内容没有详细讲解,主要是展示有这样的可能性。运行相关程序的时候需要install两个module,一个是PyPDF2,另一个是pyautogui,方法如下:

pip3 install PyPDF2
pip3 install pyobjc-core
pip3 install pybojc
pip3 install pyautogui

实际上打开这个程序的python源文档,并不难理解,大部分是字符串操作。

3. Elementary cellular automata (元胞自动机)

简单说:以1个符号作为种子,根据某种规则向下衍生。

3.1 规则制定

本问题的规则是根据一个输入的数转化为2进制后制定的,先要实现二进制显示8个数字的功能。以输入90为例:

bin(90)
>>> '0b1011010'

转化后数字前面有二进制符号0b,需要把它们去掉

bin(90)[2:]
>>> '1011010'

然后发现不同的数字二进制转化后并不能确定是8位数,所以要在前面补全数字0

'0' * (8 - len(bin(90)[2:]) + bin(90)[2:]
>>> '01011010'

这样的程序虽然达到了目的,但是太过复杂,想到之前提到过的格式化输出,可以利用string来帮助简化程序

f'{90:08b}'
>>> '01011010'

接下来完成输入值90的规则制定

n = f'{90:08b}'
rules = {}
for i in range(8):
    rules[(i // 4, i // 2 % 2, i % 2)] = n[7 - i]

使用python的简化写法

n = f'{90:08b}'
rules = {(i // 4, i // 2 % 2, i % 2): n[7 - i] for i in range(8)}

3.2 程序实现

def print_line(line):
#根据list调整输出格式
    for e in line:
        if e:
        #如果某个位置是非0的
            print('*', end = '')
        else:
            print(' ', end = '')
    print()
    #换行输出

n = f'{90:08b}'
rules = {(i // 4, i // 2 % 2, i % 2): int(n[7 - i]) for i in range(8)}

line = [0] * 20 + [1] + [0] * 20
#初始化,左右两边各20个0,中间有个1
print_line(line)
#输出初始化的第一行,后续行根据规则产生,边界是不能超出41个数字(20个0,1个1,20个0是初始化的位置)
for i in range(20):
#每次根据规则产生新的一行时,1的左右两侧各使用了1个0,所以只能产生20行,否则超出临界值。
    new_line = [0] * 41
    for j in range(20 - i, 20 + i + 1):
    #第i行需要根据规则产生数字的区域是[20-i, 20+i]
        new_line[j] = rules[line[j - 1], line[j], line[j + 1]]
    line = new_line
    print_line(line)
>>>
                    *                    
                   * *                   
                  *   *                  
                 * * * *                 
                *       *                
               * *     * *               
              *   *   *   *              
             * * * * * * * *             
            *               *            
           * *             * *           
          *   *           *   *          
         * * * *         * * * *         
        *       *       *       *        
       * *     * *     * *     * *       
      *   *   *   *   *   *   *   *      
     * * * * * * * * * * * * * * * *     
    *                               *    
   * *                             * *   
  *   *                           *   *  
 * * * *                         * * * * 

4. Rational Number

有理数用小数的形式表现的时候小数点后分为两个部分,有限的无规律数字组+无限的有规律的循环数字组。(Eric给的课上代码是有错误的,正确的如下)

sigma = input('Input sigma: ')
tau = input('Input tau:')
p = int(sigma) * ((10 ** (len(tau))) - 1) + int(tau)
q = ((10 ** len(tau)) -1) * 10 ** len(sigma)
print(p/q)

#[sigma * (10^{|tau|} - 1) + tau] /
#            [(10^{|tau|} - 1) * 10^{|sigma|}]
#该公式是从0.(sigma)(tau)(tau)(tau)...
          = sigma * 10^{-|sigma|} + tau(10^{-|sigma|-|tau|} +
                                        10^{-|sigma|-2|tau|} +
                                        ...)推导出来的
>>>
Input sigma: 27
Input tau:343
0.27343343343343346

在这个问题的python源文档中,有一种需要注意的函数调用方法

def f():
    return (2, 6)
def g(m, n):
    return m * n
print(g(*f()))
#注意f()前边的*,因为函数f()返回的是一个tuple(2,6),这是一个元素,而g()需要两个数的输入,所以要用*f()把tuple(2, 6)这样一个元素转化为两个元素。

再举一个例子

def f(a, b):
    return a + b
f(*(2, 6))
>>> 8
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容