设计和实现尼姆游戏(人机对战)
实验目的
- 理解尼姆游戏规则
- 了解多个函数的定义与调用
- 理解并熟练运行while循环
- 理解带else子句的循环结构执行流程
- 理解循环语句的break语句的作用
- 了解使用循环和异常处理结构对用户输入进行约束的用法
- 养成时刻注意各级代码缩进级别的习惯
- 实验内容
实验内容
- 尼姆游戏是一个著名的游戏,有很多变种玩法。两个玩家轮流从一堆物品中拿走一部分。在每一步中,玩家可以自由选择拿走多少物品,但是必须至少拿走一个并且最多只能拿走一半物品,然后轮到下一个玩家。拿走最后一个物品的玩家输掉游戏。
- 在聪明模式中,计算机每次拿走一定数量的物品使得堆的大小是2的幂次方减1—也就是3,7,15,31,63等。如果有一定数量的剩余物品,计算就随机拿走一些。
- 编写程序,模拟聪明版及非聪明版的尼姆游戏。并进行两种的比较及分析。给出聪明版比非聪明版的胜算结论。
n | 目的数 | 操作数x | | n | 目的数 | 操作数x |
---|
1 | 1 | 失败 | | 17 | 15 | 2 |
2 | 1 | 1 | | 18 | 15 | 3 |
3 | * | ran | | 19 | 15 | 4 |
4 | 3 | 1 | | 20 | 15 | 5 |
5 | 3 | 2 | | 21 | 15 | 6 |
6 | 3 | 3 | | 22 | 15 | 7 |
7 | * | ran | | 23 | 15 | 8 |
8 | 7 | 1 | | 24 | 15 | 9 |
9 | 7 | 2 | | 25 | 15 | 10 |
10 | 7 | 3 | | 26 | 15 | 11 |
11 | 7 | 4 | | 27 | 15 | 12 |
12 | 7 | 5 | | 28 | 15 | 13 |
13 | 7 | 6 | | 29 | 15 | 14 |
14 | 7 | 7 | | 30 | 15 | 15 |
15 | * | ran | | 31 | * | ran |
16 | 15 | 1 | | 32 | 31 | 1 |
'''模拟聪明版尼姆游戏
一人进行“聪明操作”
另一人随机生成数'''
import math
import random
def smart(n):
logn = int(math.log(n, 2))
if n == math.pow(2, logn + 1) - 1:
return random.randint(1,int(n/2))
return n - int(math.pow(2, logn)) + 1
def playn(n):
if n <= 3:
return 1
else:
return random.randint(1, int(n/2))
sumnum = int(input("请输入总和:"))
while sumnum > 0:
tmp = sumnum
player_smart = smart(sumnum)
sumnum = sumnum - player_smart
tmp2 = sumnum
if not sumnum:
print("player_smart失败")
player_random = playn(sumnum)
sumnum = sumnum - player_random
if not sumnum:
print("player_random失败")
print("原本总和{3},聪明玩家出数{1},聪明玩家出数后{4},随机玩家出数{2},当前剩余{0}".format(sumnum, player_smart, player_random,tmp,tmp2))
一方采取聪明算法时,获胜概率远远大于随机出数
请输入总和:123
原本总和123,聪明玩家出数60,聪明玩家出数后63,随机玩家出数7,当前剩余56
原本总和56,聪明玩家出数25,聪明玩家出数后31,随机玩家出数8,当前剩余23
原本总和23,聪明玩家出数8,聪明玩家出数后15,随机玩家出数1,当前剩余14
原本总和14,聪明玩家出数7,聪明玩家出数后7,随机玩家出数3,当前剩余4
原本总和4,聪明玩家出数1,聪明玩家出数后3,随机玩家出数1,当前剩余2
player_random失败
原本总和2,聪明玩家出数1,聪明玩家出数后1,随机玩家出数1,当前剩余0
请输入总和:263
原本总和263,聪明玩家出数8,聪明玩家出数后255,随机玩家出数94,当前剩余161
原本总和161,聪明玩家出数34,聪明玩家出数后127,随机玩家出数21,当前剩余106
原本总和106,聪明玩家出数43,聪明玩家出数后63,随机玩家出数26,当前剩余37
原本总和37,聪明玩家出数6,聪明玩家出数后31,随机玩家出数10,当前剩余21
原本总和21,聪明玩家出数6,聪明玩家出数后15,随机玩家出数7,当前剩余8
原本总和8,聪明玩家出数1,聪明玩家出数后7,随机玩家出数3,当前剩余4
原本总和4,聪明玩家出数1,聪明玩家出数后3,随机玩家出数1,当前剩余2
player_random失败
原本总和2,聪明玩家出数1,聪明玩家出数后1,随机玩家出数1,当前剩余0
请输入总和:1025
原本总和1025,聪明玩家出数2,聪明玩家出数后1023,随机玩家出数122,当前剩余901
原本总和901,聪明玩家出数390,聪明玩家出数后511,随机玩家出数216,当前剩余295
原本总和295,聪明玩家出数40,聪明玩家出数后255,随机玩家出数29,当前剩余226
原本总和226,聪明玩家出数99,聪明玩家出数后127,随机玩家出数32,当前剩余95
原本总和95,聪明玩家出数32,聪明玩家出数后63,随机玩家出数27,当前剩余36
原本总和36,聪明玩家出数5,聪明玩家出数后31,随机玩家出数2,当前剩余29
原本总和29,聪明玩家出数14,聪明玩家出数后15,随机玩家出数2,当前剩余13
原本总和13,聪明玩家出数6,聪明玩家出数后7,随机玩家出数2,当前剩余5
原本总和5,聪明玩家出数2,聪明玩家出数后3,随机玩家出数1,当前剩余2
player_random失败
原本总和2,聪明玩家出数1,聪明玩家出数后1,随机玩家出数1,当前剩余0
'''常规方法'''
import random
def playn(n):
if n <=3:
return 1
else:
return random.randint(1, int(n/2))
sumnum = int(input("请输入总和"))
while sumnum > 0:
tmp = sumnum
player1 = playn(sumnum)
sumnum = sumnum - player1
if not sumnum:
print("player1失败")
player2 = playn(sumnum)
sumnum = sumnum - player2
if not sumnum:
print("player2失败")
print("原本总和{3}当前剩余{0},玩家1出数{1},玩家2出数{2}".format(sumnum, player1, player2,tmp))
双方都随机出数时,获胜概率是相等的
请输入总和123
原本总和123当前剩余51,玩家1出数34,玩家2出数38
原本总和51当前剩余29,玩家1出数13,玩家2出数9
原本总和29当前剩余20,玩家1出数6,玩家2出数3
原本总和20当前剩余8,玩家1出数4,玩家2出数8
原本总和8当前剩余5,玩家1出数1,玩家2出数2
原本总和5当前剩余2,玩家1出数2,玩家2出数1
player2失败
原本总和2当前剩余0,玩家1出数1,玩家2出数1
请输入总和100
原本总和100当前剩余56,玩家1出数14,玩家2出数30
原本总和56当前剩余28,玩家1出数18,玩家2出数10
原本总和28当前剩余22,玩家1出数5,玩家2出数1
原本总和22当前剩余9,玩家1出数11,玩家2出数2
原本总和9当前剩余3,玩家1出数3,玩家2出数3
原本总和3当前剩余1,玩家1出数1,玩家2出数1
player1失败
原本总和1当前剩余-1,玩家1出数1,玩家2出数1