python编程练习:24点游戏中所有数字组合的解的情况

本文深入探讨了24点游戏的算法实现,通过复杂的组合数学和编程技巧,计算了不同数字范围和运算符组合下游戏的解空间,揭示了各种牌型组合的可能性及其概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、代码

import time
from collections import Counter
import pandas as pd
from itertools import permutations
from itertools import combinations_with_replacement
from scipy.special import comb


def op_all_combs(in_list, n):
    # 13个不相同的球有放回的抽取4个
    out_list = []
    for j in list(combinations_with_replacement(in_list, n)):
        out_list.append(j)
    return out_list


def op_all_arrange(unarr_list):
    arred_list = []
    for k in unarr_list:
        arred_list.append(set(permutations(k)))
    return arred_list


def extract_list(unex_list):
    exed_list = []
    for i in unex_list:
        for j in i:
            exed_list.append(j)
    return exed_list


def mix_tuple(tup_1, tup_2):
    tup_mix = [tup_1[0], tup_2[0], tup_1[1], tup_2[1], tup_1[2], tup_2[2], tup_1[3]]
    return tup_mix


def inst_bck_2(in_list):
    # 加入一对括号,对应所有位置的情况
    out_strs = []
    poitions = [(0, 4), (2, 6), (4, 8), (0, 6), (2, 8)]
    for poition in poitions:
        str_copy = in_list[:]
        str_copy.insert(poition[0], '(')
        str_copy.insert(poition[1], ')')
        out_strs.append(''.join(str_copy))
    # 加入两对括号
    in_list.insert(0, '(')
    in_list.insert(4, ')')
    in_list.insert(6, '(')
    in_list.insert(10, ')')
    out_strs.append(''.join(in_list))
    return out_strs


def type_cvt(in_dict):
    counter_result = sorted(list(in_dict.values()), reverse=True)
    if counter_result == [4]:
        return 1
    elif counter_result == [3, 1]:
        return 16
    elif counter_result == [2, 2]:
        return 36
    elif counter_result == [2, 1, 1]:
        return 96
    elif counter_result == [1, 1, 1, 1]:
        return 256


# 区分花色和数字,任意一个牌型组合都有24种可能,取决于取牌的顺序
# 只关心数字,四种类型的牌型,是不同的。故只考虑数字和花色,不考虑取牌顺序,共有1820种可能
s_time = time.time()

"""
num_min:卡牌范围的下限
num_max: 卡牌范围的上限
syms_list:可选运算符构成的列表
syms: 本次选用的运算符
"""
num_min = 1
num_max = 13
nums = [str(n) for n in range(num_min, num_max+1)]
all_sum = int(comb(num_max*4, 4))
syms_list = [['+', '-'], ['+', '-', '*'], ['+', '-', '*', '/'], ['+', '-', '*', '/', '%'], ['+', '-', '*', '/', '//'],
             ['+', '-', '*', '/', '%', '//']]
syms = syms_list[2]


num_combs = op_all_combs(nums, 4)  # ['1', '2', '3', '4']
sym_combs = op_all_combs(syms, 3)  # ['*', '*', '*']

num_arrs = op_all_arrange(num_combs)  # 数字部分排列组合后的集合
sym_arrs = op_all_arrange(sym_combs)  # 运算符部分排列组合后的集合

num_arrs = extract_list(num_arrs)
sym_arrs = extract_list(sym_arrs)

types = [type_cvt(Counter(comb)) for comb in num_combs]

# num_fits能够算出24的数字元组构成的列表
# eva_equs是能够算出24的数字和运算符组成的命令
num_fits = {','.join(sorted(k)): [] for k in num_combs}
eva_equs = []

for num_arr in num_arrs:
    for sym_arr in sym_arrs:
        add_key = list(num_arr)
        add_key.sort()
        add_key = ','.join(add_key)
        if set(sym_arr).issubset({'+', '-'}):
            # 由数字和加法运算符得到的
            evas = ''.join(mix_tuple(num_arr, sym_arr))
            if eval(evas) == 24:
                num_fits[add_key].append(evas)
        else:
            evas = inst_bck_2(mix_tuple(num_arr, sym_arr))
            try:
                for eva in evas:
                    if eval(eva) == 24:
                        if add_key in num_fits:
                            num_fits[add_key].append(eva)
            except ZeroDivisionError:
                pass

# 打印程序运行的时间
print("Time used: {0}s.\n".format(time.time() - s_time))

out_csv = "num_combs.csv"
df = pd.DataFrame.from_dict(num_fits, orient='index')

# types记录牌组的数字类型对应的个数,aaaa型牌有1种,aaab型牌有16种...
df.insert(0, 'types', types)

# 将csv导出
df.to_csv(out_csv)

# 第一步,去除所有的none所在的行
df = df[~df[0].isin([None])]

# 第二步,计算剩下的新的df在types列的总和
row_sum = df['types'].sum()

# percent:抽到有解数字组合的概率
percent = row_sum / all_sum * 100
print('Precent is {0}%'.format(percent))

# 将计算结果写入到一个文本中
log_name = 'log.txt'
with open(log_name, 'a+') as f_obj:
    f_obj.write('\n'+str(nums)+'\n')
    f_obj.write(str(syms)+'\n')
    f_obj.write(str(percent)+'%'+'\n')

二、结果
Excel文件:储存所有数字组合对应的解的情况
2-1
txt文件:记录各个可选运算符、数字范围情况下有解的概率2-2
三、概率
若将有解定义为——从4种花色、数字范围为1~n共计4n张扑克牌中随机抽取4张牌,牌面上的数字可以通过运算符(加减乘除)得到24点。
则不同运算符和卡牌范围对应的有解概率为:3-1
3-2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Salierib

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

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

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

打赏作者

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

抵扣说明:

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

余额充值