利用Python模拟多人石头剪刀布

以下介绍的这个程序,用Python较为简单地模拟出多人石头剪刀布的所有情况以及输赢结果。

子函数编写

在编写主程序前,对需要使用到的几个函数先进行编写。

判断输赢的函数check()

在这里我们用 ‘a’ 表示石头,‘b’ 表示剪刀,‘c’ 表示布。
提供的参数是一个字典,键是出手势的人(用1、2、3等数字表示),值是手势(用a、b、c表示)。
如果出现了三种手势或只出现一种,则很显然是平局。
如果出现了两种手势,那么判断输赢。
最后返回所有获胜的人的号码列表。
代码如下:

# Check.py

def check(check_list):
    '''a代表石头,b代表剪刀,c代表布,判断获胜的选手'''
    result = list(check_list.values())
    # 如果石头剪刀布都出现或只出现一个,就是平局
    if len(set(result)) == 3 or len(set(result)) == 1:
        return None

    winners = []

    # 石头对剪刀,石头赢
    if set(result) == {'a','b'}:
        # 找出所有出石头的人
        for k,v in check_list.items():
            if v == 'a':
                winners.append(k)

    # 石头对布,布赢
    if set(result) == {'a','c'}:
        # 找出所有出布的人
        for k,v in check_list.items():
            if v == 'c':
                winners.append(k)

    # 剪刀对布,剪刀赢
    if set(result) == {'b','c'}:
        # 找出所有出剪刀的人
        for k,v in check_list.items():
            if v == 'b':
                winners.append(k)

    return winners

列举所有情况的函数

原理:为了快速且正确的列举所有排列情况(这里其实就是a、b、c三个字母),我利用所有的三进制数来一一对应。有一个初始列表[‘a’,‘b’,‘c’],每一个三进制数的数位只有0、1、2,正好对应列表中a、b、c的索引。
例:三个人玩石头剪刀布:
三进制数12(即012)代表abc,即第一个人出石头,第二个人出剪刀,第三个人出布。
又如:5个人玩石头剪刀布:
三进制数12022代表bcacc,即第一个人出剪刀,第三个人出石头,剩下的人出布。

补齐数码的函数code()

这个函数解决的问题是数码不够的情况。
例如:5个人玩石头剪刀布,
三进制数是121,数码不足五位,需要补齐至00121。
函数接受一个三进制数,返回一个列表,每一项是一个数字(以字符串的形式),这个数字是0、1、2中的一个。
代码如下:

# Create_situation.py

def code(num,length):
    '''补齐数字,将num补齐至length位,例如将1补齐至三位变成001'''
    num = str(num)
    # 如果位数相同,以列表形式返回数字
    if len(num) == length:
        return list(num)
    # 如果位数不同,就在前面一直补0,直到补齐
    elif len(num) < length:
        while True:
            num = '0' + num
            if len(num) == length:
                break
    return list(num)

三进制数与十进制数的转换

因为三进制数较难列举,因此我们列举简单的十进制数,并使用函数将其转换为三进制数。
其中的原理和十进制与二进制的转换非常类似,感兴趣的读者可以查看我的另一篇文章《Python 二进制与十进制的研究》。
Python 二进制与十进制的研究
代码如下(三进制转十进制的函数在后续的程序中没有用到,只是我用来测试程序的):

# Change.py
def three_to_ten(num):
    '''将三进制数转换为十进制数'''
    # 主要原理:(abcde)3 = a*3**4 + b*3**3 + c*3**2 + d*3**1 + e*3**0
    nums = list(str(num))
    nums.reverse()
    result = 0

    for i in range(0,len(nums)):
        # 每个数位乘上3的次方
        delta = int(nums[i]) * (3 ** i)
        result += delta

    return result


def ten_to_three(num):
    '''把十进制数转换成三进制数'''
    # 主要原理:原数字一直除3,得到的余数反写
    results = []

    division = num

    if division == 0:
        return 0
    
    # 反复除三,记录商和余数
    while division != 0:
        results.append(division % 3)
        division = division // 3

    results.reverse()
    result = ''
    for nums in results:
        # 获得最终的结果
        result += str(nums)
    return int(result)

排列所有的情况create_situation()

前期的准备工作做好后,这个排列情况的函数不难编写出。
函数接收的参数是玩石头剪刀布人的数量。
如果有重复的就舍去,没有重复的就写入列表。
最后返回的列表是所有情况(用字典表示,例如{1:‘a’,2:‘a’,3,‘a’})
代码如下:

# Create_situation.py

from Change import ten_to_three, three_to_ten
def create_situation(num):
    '''提供有多少人玩石头剪刀布,返回所有情况'''
    # 用三进制数来列举每个人出石头、剪刀或布的情况
    list_1 = ['a','b','c']
    situation = {}
    situations = []
    nums = 3 ** num # 情况的数量

    for i in range(0,nums):
        i_1 = ten_to_three(i) # 将每个十进制数转为三进制数
        i_2 = code(i_1,num) # 补齐位数
        situation = {}
        for y in range(1,len(i_2)+1):
            # 根据三进制数位数0、1、2决定a,b,c
            situation[y] = list_1[int(i_2[y-1])] 
            # 重复的情况要舍去
            if situation in situations:
                continue
            else:
                situations.append(situation) # 加入列表
    return situations

主程序

运用input()函数获得玩石头剪刀布的人数,然后获得所有的情况,判断输赢或平局,然后对应打印出来。
代码如下:

# Main.py---提供玩石头剪刀布的人数,列举所有情况及获胜情况
# TonyLu  2024.4.13-2024.4.14

from Create_situation import create_situation as c_s
from Check import check

num = input('有几个人玩石头剪刀布?') # 获得人数
print('开始列举。a表示石头,b表示剪刀,c表示布')

list_1 = c_s(int(num))

results = {}
for i in list_1:
    winners = check(i) # 判断输赢
    if winners == None:
        winners = '平局'
    print(f'{i}          {winners}') # 打印结果

运行成果

注意:由于程序中出现了调用其他文件的函数,请务必把几个子程序和主程序放在同一个文件夹里。
在这里插入图片描述
接下来看一下主程序的运行成果。

2个人玩
在这里插入图片描述
在这里插入图片描述
备注:最后一张图片是五个人玩,由于放不下,只取了一部分。

总结

通过几个函数,我们成功模拟了多人玩石头剪刀布的情况。
程序调试的时间不长,如有错误请帮忙指出,谢谢!

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拖泥鹿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值