模拟两人猜拳游戏

模拟两个人猜拳,出石头剪刀布。第一轮大家随机出拳,存储模拟结果,并计算玩家 1 的胜率。改进玩家 1 的出拳策略之后,看对其胜率是否有影响。

主要思路:设计一个策略集合,放置石头剪刀布三种策略。再分别设计玩家 1 和玩家 2 的策略,每次随机从策略集合中取一种策略。最后设计比赛规则,将玩家的两种策略进行比较,输出一轮比赛结果,并存储在比赛结果列表中。可以将比赛循环多次,在结果列表中计算玩家 1 的胜利次数,以此计算玩家 1 的胜率。

# 首先导入两个库,随机库用来随机取策略,collections 库用来生成一个值是列表属性的默认字典,用来存储比赛结果

import random
import collections

def finger_play(n): # 参数 n 控制比赛的轮数
    stratergy = ['paper', 'rock', 'scissors']
    res = collections.defaultdict(list)
    for i in range(1, n+1):
        s1 = random.choice(stratergy)
        s2 = random.choice(stratergy)
        if stratergy.index(s1) == stratergy.index(s2) + 1 or stratergy.index(s1) == stratergy.index(s2) - 2:
            res['player1'].append('lose')
            print('player1: %s, palyer2: %s, player2 win'%(s1,s2))
        elif stratergy.index(s1) == stratergy.index(s2) - 1 or stratergy.index(s1) == stratergy.index(s2) + 2:
            res['player1'].append('win')
            print('player1: %s, palyer2: %s, player1 win'%(s1,s2))
        else:
            res['player1'].append('tied')
            print('player1: %s, palyer2: %s, this round is tied'%(s1,s2))
    print(res, len(res['player1']))
    winning_percentage = res['player1'].count('win') / n
    print("player1's winning percentage is: ", winning_percentage)
    return res

这里也可以简单的用 0,1,2 来表示石头剪刀布的策略,输出时做转换就行,这样在进行判断时就没必要取下标,直接用值进行加减计算即可

另外,比赛结果的判断语句也可以简写为

        if stratergy.index(s1) - stratergy.index(s2) in (1, -2):
            res['player1'].append('lose')
            print('player1: %s, palyer2: %s, player2 win'%(s1,s2))
        elif stratergy.index(s1) == stratergy.index(s2):
            res['player1'].append('tied')
            print('player1: %s, palyer2: %s, this round is tied'%(s1,s2))
        else:
            res['player1'].append('win')
            print('player1: %s, palyer2: %s, player1 win'%(s1,s2))

以上是简单的随机出拳游戏,真实情况人们可能会根据上一轮猜拳的结果来决定当前轮的出拳策略,例如我们可以让玩家 2 随机出拳,玩家 1 认为玩家 2 会重复上一轮出拳的策略,因此当前轮出拳的策略都要赢过玩家 2 上一轮的出拳策略。这种情况我们只要取消玩家 1 的随机出拳策略,而改为在每一次比赛结果出来后给玩家 1 的策略重新赋值,使得更新后的玩家 1 策略为玩家 2 当前策略的前一个策略即可。

import random
import collections
def finger_play(n):
    stratergy = ['paper', 'rock', 'scissors']
    res = collections.defaultdict(list)
    s1 = random.choice(stratergy)
    for i in range(1,n+1):
        s2 = random.choice(stratergy)
        if stratergy.index(s1) - stratergy.index(s2) in (1, -2):
            res['player1'].append('lose')
            print('player1: %s, palyer2: %s, player2 win'%(s1,s2))
            tems1 = stratergy.index(s2) - 1
            s1 = stratergy[tems1] # 当前局失败,更新玩家 1 的策略为玩家 2 当前策略的前一个策略
        elif stratergy.index(s1) == stratergy.index(s2):
            res['player1'].append('tied')
            print('player1: %s, palyer2: %s, this round is tied'%(s1,s2))
            tems1 = stratergy.index(s2) - 1
            s1 = stratergy[tems1] # 平局时玩家 1 的策略选择当前策略的前一个策略
        else:
            res['player1'].append('win')
            print('player1: %s, palyer2: %s, player1 win'%(s1,s2))
            s1 = s1 #当前比赛结果获胜,因此下一轮比赛玩家 1 依然保持该策略
    print(res, len(res['player1']))
    winning_percentage = res['player1'].count('win') / n
    print("player1's winning percentage is: ", winning_percentage)
    return res

我们可以尝试进行 100,1000,10000,100000 轮,结果会发现,在 100 轮的时候,比赛结果会波动比较大,但是当到 1000 轮了,比赛结果基本稳定在 0.33 左右了,如果到十万轮的话,比赛结果几乎就是在 33.3%。这也说明了,只要有人是随机出拳,那么不管采用什么策略,对手的胜率大概就是 1/3,因此猜拳游戏是一个很公平的游戏。

我们可以写一个循环来依次增加比赛轮数,看看胜率如何变化。为了简洁起见,在多次调用的时候我们省略掉了其他的输入内容,每次只输出胜率,最后的返回值也改成胜率 winning_percentage

def game_many():
    rate = []
    i = 10
    while i in range(10,1000001):
        rate.append(finger_play(i))
        i *= 10
        print(rate)

if __name__ == '__main__':
    game_many()

多次运行之后发现,在 10,100 这些次数时,胜率还会有所波动,但是到 10 万次的时候,基本就是 33 的胜率没啥变化了

player1's winning percentage is:  0.2
[0.2]
player1's winning percentage is:  0.3
[0.2, 0.3]
player1's winning percentage is:  0.34
[0.2, 0.3, 0.34]
player1's winning percentage is:  0.3361
[0.2, 0.3, 0.34, 0.3361]
player1's winning percentage is:  0.33018
[0.2, 0.3, 0.34, 0.3361, 0.33018]
player1's winning percentage is:  0.333628
[0.2, 0.3, 0.34, 0.3361, 0.33018, 0.333628]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值