cw19911008 发表于 前天 17:08

学Python第15天,一个计算24点的程序,有不足的地方请请大家斧正

import easygui as eg

list1 = eg.multenterbox(msg='请输入四个10以内的正整数', title='输入框', fields=['第一个数','第二个数','第三个数','第四个数'])
a , b , c , d = list1 , list1 , list1 , list1

def tf(a,b,c,d):
    from itertools import permutations, product
    import re

    nums =
    ops = ['+', '-', '*', '/']

    brackets = [
      "(({0} {4} {1}) {5} {2}) {6} {3}",
      "({0} {4} ({1} {5} {2})) {6} {3}",
      "({0} {4} {1}) {5} ({2} {6} {3})",
      "{0} {4} (({1} {5} {2}) {6} {3})",
      "{0} {4} ({1} {5} ({2} {6} {3}))"
    ]

    for num_perm in permutations(nums):
      for op_perm in product(ops, repeat=3):
            for bracket in brackets:
                expr = bracket.format(num_perm, num_perm, num_perm, num_perm,
                                    op_perm, op_perm, op_perm)
                try:
                  # 安全计算表达式值
                  result = eval(expr)
                  # 检查结果是否为24(考虑浮点误差)
                  if abs(result - 24) < 1e-6:
                        # 优化表达式显示:移除多余括号和浮点转换
                        expr = re.sub(r'\.0\b', '', expr)# 移除整数后的.0
                        return expr
                except ZeroDivisionError:
                  continue
   
    return "无解"

x = tf(a,b,c,d)

eg.msgbox(f'结果为:{x}',title = '24点')

FishC 发表于 前天 17:10

您好!看到您的24点计算程序,有一些地方需要修正。我来帮您指出问题并提供改进版本。

主要问题:
- fields= 缺少字段列表,导致输入框无法正常工作。
- 变量赋值错误: a, b, c, d = list1, list1, list1, list1 会让所有变量都引用整个列表,而不是单个元素。
- 函数 tf 内部未正确定义 nums 和 ops,且括号模式处理有误。
- 输入是字符串,需要转换为数字后再计算。
- 使用 eval 有安全风险,但鉴于这是学习项目,我们可以暂时接受,但建议注意。

修正后的代码:

import easygui as eg
from itertools import permutations, product
import re

# 获取输入并转换为整数
fields = ['数字1', '数字2', '数字3', '数字4']
list1 = eg.multenterbox(msg='请输入四个10以内的正整数', title='输入框', fields=fields)
# 检查输入是否有效
if list1 is None or any(not num.isdigit() for num in list1):
    eg.msgbox('输入无效,请确保输入正整数!', title='错误')
    exit()
a, b, c, d = map(int, list1)# 转换为整数

def tf(a, b, c, d):
    nums =
    ops = ['+', '-', '*', '/']
    # 定义常见的括号模式
    brackets = [
      '({0} {4} {1}) {5} ({2} {6} {3})',
      '(({0} {4} {1}) {5} {2}) {6} {3}',
      '({0} {4} ({1} {5} {2})) {6} {3}',
      '{0} {4} ({1} {5} ({2} {6} {3}))',
      '{0} {4} (({1} {5} {2}) {6} {3})'
    ]
   
    for num_perm in permutations(nums):
      for op_perm in product(ops, repeat=3):
            for bracket in brackets:
                # 构建表达式字符串
                expr = bracket.format(num_perm, num_perm, num_perm, num_perm,
                                    op_perm, op_perm, op_perm)
                try:
                  result = eval(expr)
                  if abs(result - 24) < 1e-6:
                        expr_clean = re.sub(r'\.0\b', '', expr)# 移除整数后的.0
                        return expr_clean
                except ZeroDivisionError:
                  continue
    return "无解"

x = tf(a, b, c, d)
eg.msgbox(f'结果为:{x}', title='24点')


关键改进点:
- 使用 fields=['数字1', '数字2', '数字3', '数字4'] 来定义输入字段。
- 通过 map(int, list1) 将输入转换为整数。
- 在函数内部正确定义 nums 和 ops。
- 添加了输入验证,确保用户输入的是数字。
- 优化了括号模式,覆盖更多表达式组合。

这个版本应该能正常工作,但请注意 eval 的使用风险。如果您有更多问题,欢迎继续问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

不二如是 发表于 前天 17:49

15天能写出这种级别代码,很棒啦{:13_413:}

目前:穷举所有排列×运算×括号模板冗余大、重复多~

可以不改,要是改为“递归合并两数”的24点标准解法:

每次从集合里选两数做运算,放回结果,直到只剩一个数是否为24。
天然覆盖所有括号形态,避免模板爆炸;

同时通过只对有序/无序对做必要运算来剪枝(如对+、*的交换律去重)。

参考:

import easygui as eg
from fractions import Fraction
from functools import lru_cache
import itertools

def ask_numbers():
    while True:
      fields = ['第一个数','第二个数','第三个数','第四个数']
      resp = eg.multenterbox(msg='请输入四个1~10的正整数', title='输入框', fields=fields)
      if resp is None:
            return None# 用户取消
      try:
            nums =
            if len(nums) != 4 or any(n < 1 or n > 10 for n in nums):
                eg.msgbox('必须是4个1~10的正整数。', '输入有误')
                continue
            return nums
      except:
            eg.msgbox('请输入有效的整数。', '输入有误')

def format_expr(expr: str) -> str:
    # 去除形如"24/1"这类无意义格式不在此做,保持表达式原意;无需去 .0(我们不用浮点)
    return expr

def enumerate_results(nums, find_all=True):
    # 将int转为Fraction并同时携带表达式字符串
    start = tuple( (Fraction(n), str(n)) for n in nums )

    @lru_cache(None)
    def solve(state):
      # state: tuple of (Fraction, expr_str) 的序列,但cache里不能存对象,存值和串
      pairs = list(zip(state[::2], state))# 无用,只为类型提示;下面直接用索引
      results = set()# expr strings that evaluate to 24

      L = len(state)//2# 我们把state编码成(value, expr)交错扁平化存放

      # 还原为列表[(val, expr), ...]
      arr = [(state, state) for i in range(L)]

      if L == 1:
            val, expr = arr
            if val == Fraction(24, 1):
                results.add(expr)
            return tuple(sorted(results))# cache要求可哈希

      # 选择两数 i<j
      for i in range(L):
            for j in range(i+1, L):
                (a, ea) = arr
                (b, eb) = arr

                # 其余元素
                rest = for k in range(L) if k != i and k != j]

                candidates = []

                # 加法与乘法(交换律:只做一遍)
                candidates.append( (a+b, f"({ea}+{eb})") )
                candidates.append( (a*b, f"({ea}*{eb})") )

                # 减法和除法(考虑顺序)
                candidates.append( (a-b, f"({ea}-{eb})") )
                candidates.append( (b-a, f"({eb}-{ea})") )
                if b != 0:
                  candidates.append( (a/b, f"({ea}/{eb})") )
                if a != 0:
                  candidates.append( (b/a, f"({eb}/{ea})") )

                # 递归
                for (val, ex) in candidates:
                  new_arr = rest + [(val, ex)]
                  # 扁平化为 cache key
                  new_state = []
                  # 为提升剪枝效果,对值表达式做轻微排序:仅对交换律运算前已控制,不再额外排序表达式,排序按值大小
                  for (v, e) in sorted(new_arr, key=lambda x: (x, len(x))):
                        new_state.extend()
                  new_state = tuple(new_state)

                  sub = solve(new_state)
                  if sub:
                        results.update(sub)
                        if not find_all and results:
                            return tuple(sorted(results))
      return tuple(sorted(results))

    # 枚举输入的所有排列(避免相同数字导致重复,用set去重)
    all_exprs = set()
    for perm in set(itertools.permutations(start, 4)):
      # 扁平化为 (v1,e1,v2,e2,...) 作为初态
      init = []
      for (v, e) in perm:
            init.extend()
      sols = solve(tuple(init))
      all_exprs.update(sols)

      if not find_all and all_exprs:
            break

    # 美化与去重
    clean = sorted(set(format_expr(s) for s in all_exprs))
    return clean

def main():
    nums = ask_numbers()
    if nums is None:
      return

    # 询问模式:找到一个就停 or 列出全部
    choice = eg.buttonbox("选择求解模式:", "24点", choices=["快速找到一个", "列出全部解"])
    find_all = (choice == "列出全部解")

    sols = enumerate_results(nums, find_all=find_all)

    if not sols:
      eg.msgbox('无解', '24点')
    else:
      if find_all:
            # 多解时分行显示
            eg.textbox("找到的解:", "24点", "\n".join(sols))
      else:
            eg.msgbox(f"结果:{sols}", '24点')

if __name__ == "__main__":
    main()
页: [1]
查看完整版本: 学Python第15天,一个计算24点的程序,有不足的地方请请大家斧正