Python3 欧拉计划 问题84 大富翁

作者: AiFany | 来源:发表于2018-01-30 10:59 被阅读138次
    EulerProject.png
    更多问题参见https://www.jianshu.com/p/8c3ec805433d

    84、大富翁

      大富翁的标准棋盘大致如下图所示:

    Monopoly.png

      从标记有GO的方格出发,掷两个6面的骰子,并将所得的点数之和,作为本轮前进的步数。如果不附加其它规则,玩家玩过很多轮以后,落在每一格上的概率应该都接近2.5%。但是,由于G2J(入狱)、CC(宝箱卡)和CH(机会卡)的存在,这个概率分布会有所改变。
      除了落在G2J上,或者在CCCH上有可能抽到入狱卡之外,如果玩家连续3次都掷出两个一样的点数,例如玩家连续三次掷出的分别是(3,3),(1,1),(5,5),则在第三次时不会前进5+5=10步,而是直接入狱。
      游戏开始时,CCCH中的牌将被随机打乱。当一个玩家落在CCCH上时,他们从CCCH卡中的最上方取一张牌并按照牌面意思前进,并将该牌再放回牌堆的最下方。宝箱卡和机会卡都各有16张牌,因为我们只关心会影响到移动的牌,其它牌无效。宝箱卡和机会卡的牌见下面:

    • 宝箱卡 (2张牌,其他14张无效):
        回到起点GO
        进入监狱JAIL
    • 机会卡 (10张牌,其他6张无效):
        回到起点GO
        进入监狱JAIL
        移动到C1
        移动到E3
        移动到H2
        移动到R1
        移动到下一个R(铁路公司)
        移动到下一个R
        移动到下一个U(公共服务公司)
        后退三步

      这道题主要考察停在某个特定方格上的概率。显然,除了停在G2J上的可能性为0之外,停在CH格的可能性最小,因为有5/8的概率玩家会移动到另一格。这里不区分是被送进监狱还是恰好落在监狱,而且不考虑需要掷出两个相同的点数才能出狱的要求,而是假定进入监狱的第2轮就会自动出狱。
      从起点GO开始,将方格依次标记00至39,我们可以将这些两位数连接起来表示方格的序列。
      统计学上来说,3个停下概率最大的方格分别是:
        JAIL(6.24%):方格10
        E3(3.18%):方格24
        GO(3.09%):方格00。
    这三个方格可以用一个6位数字串表示为:102400
      上面的可能性是在用两个6面骰子的情况下得到的,现在改用两个4面的骰子,求出3个停下概率最大的方格构成的6位数字串。

    Python3解答
    import numpy as np
    import random
    #计算随机数
    def Comnum(num, count):#计算几个几面色子的随机数
        numlist = []
        st = 0
        while st < count:
            numlist.append(random.randint(1, num))
            st += 1
        return numlist
    
    #CH卡
    chlist = list(np.array([0, 10, 11, 24, 39, 5, 99, 99, 999, 9999] +[99999] * 6)[random.sample(range(16), 16)])#99999代表无效牌,随即洗牌
    chdict ={7: [15, 12], 22: [25, 28], 36: [5, 12]}
    #CC卡
    bxlist = list(np.array([0, 10] +[99999] * 14)[random.sample(range(16), 16)])#99999代表无效牌,随即洗牌
    bxdict = [2, 17, 33]
    
    #定义取卡放卡后的函数
    def Card(exlist):
        return exlist[1:] + [exlist[0]]#取完牌,将牌放在最下面
    
    #计数字典
    countdict = {kk : 0 for kk in range(40)}#每个数字代表一个方格
    #开始模拟
    start = 0
    jailsign = 0
    monitimes = 10000#模拟的次数
    for moni in range(monitimes):
        #开始随机数
        randomlist = Comnum(4, 2)#计算2个4面色子的随机数
        sezi = sum(randomlist)#计算前进的步数
        if randomlist[0] == randomlist[1]:
            jailsign += 1
        else:
            jailsign = 0
        if jailsign >= 3:#连续三次掷出相同的点数
            countdict[10] += 1#JAIL
            start = 10
        else:
            busu = (sezi + start) % 40
            if busu == 30:#G2J
                countdict[10] += 1#JAIL
                start = 10
            else:
                if busu in bxdict:#CC card
                    if bxlist[0] == 99999:#Stop Moving
                        countdict[busu] += 1
                        start = busu
                    else:
                        countdict[bxlist[0]] += 1
                        start = bxlist[0]
                    bxlist = Card(bxlist).copy()
                elif busu in chdict:#CH card
                    if chlist[0] == 99:#next R
                        nnum = chdict[busu][0]
                    elif chlist[0] == 999:#next U
                        nnum = chdict[busu][1]
                    elif chlist[0] == 99999:#Stop Moving
                        nnum = busu
                    elif chlist[0] == 9999:#Backward 3
                        nnum = busu - 3
                        if nnum == 33:#CC card
                            if bxlist[0] != 99999:  # Stop Moving
                                nnum = bxlist[0]
                            bxlist = Card(bxlist).copy()
                    else:
                        nnum = chlist[0]
                    countdict[nnum] += 1
                    start = nnum
                    chlist = Card(chlist).copy()
                else:
                    countdict[busu] += 1
                    start = busu
    
    #选择前n个最大的值,并且输出字符串
    def Str(exdict, N, M):
        sdict = sorted(exdict.items(), key = lambda x: x[1], reverse = True)
        ncount = 0
        strkey = ''
        while ncount < N:
            item = sdict[ncount]
    
            if len(str(item[0])) < 2:
                strkey += '0%s'%item[0]
                print('0%s :%.4f%%\n'%(item[0], exdict[item[0]] / M * 100))
            else:
                strkey += '%s' % item[0]
                print('%s :%.4f%%' % (item[0], exdict[item[0]] / M * 100))
            ncount += 1
        return strkey
    
    print('模拟完毕后,每个方格的停留次数:%s'%countdict)
    print(Str(countdict, 3, monitimes))
    答案:
    模拟完毕后,每个方格的停留次数:{0: 276, 1: 185, 2: 148, 3: 201, 4: 217, 5: 275, 6: 208, 7: 80, 8: 198, 9: 218, 10: 762, 11: 212, 12: 250, 13: 246, 14: 302, 15: 380, 16: 309, 17: 287, 18: 293, 19: 289, 20: 308, 21: 301, 22: 113, 23: 280, 24: 356, 25: 304, 26: 256, 27: 258, 28: 281, 29: 296, 30: 0, 31: 293, 32: 225, 33: 225, 34: 248, 35: 181, 36: 75, 37: 197, 38: 216, 39: 251}
    #3个停下概率最大的方格:
    10 :7.6200%
    15 :3.8000%
    24 :3.5600%
    #6位数字串:
    101524
    

    相关文章

      网友评论

        本文标题:Python3 欧拉计划 问题84 大富翁

        本文链接:https://www.haomeiwen.com/subject/ixvqzxtx.html