模拟两个人猜拳,出石头剪刀布。第一轮大家随机出拳,存储模拟结果,并计算玩家 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]