使用Python编写24点游戏

4 投票
1 回答
8998 浏览
提问于 2025-04-18 15:17

有一个叫做24的游戏,这是一款基于数学的游戏。如果你对这个游戏不太了解,可以先看看这个链接:http://en.wikipedia.org/wiki/24_Game

简单来说,这个游戏会给你四个数字(在我的例子中,数字范围是1到9),这些数字是随机选出来的。你的任务是用这四个数字,通过加、减、乘、除这四种基本运算,组合出数字24。规则很简单,你必须使用这四个数字,而且只能用这四个数字,每个数字只能用一次。这个游戏让我很感兴趣,所以我想写一个程序来模拟这个游戏。

我的目标是用Python编写这样一个程序。基本的步骤是……

  • 生成4个随机数字
  • 检查这些数字是否能组合成24
  • 把这些数字显示给用户
  • 看看用户输入的结果是否也能得到24

我最需要帮助的地方是第2步和第4步

我会使用随机模块来生成随机整数。

import random
num1 = random.randint ( 1, 9)
num2 = random.randint ( 1, 9)
num3 = random.randint ( 1, 9)
num4 = random.randint ( 1, 9)

所以,如果可以的话,请帮我一起创建这个游戏,并且给我讲解一下!谢谢。

另外,这是我第一次在Stack Overflow上提问,所以请给我一些建议,告诉我怎么能提高提问的技巧 :)

---编辑---

谢谢大家的帮助,但我终于搞明白了。我做了一些研究,整理了这个代码(如果你们想自己试试代码的话):

>

 '''
 The 24 Game

 Given any four digits in the range 1 to 9, which may have repetitions,
 Using just the +, -, *, and / operators; and the possible use of
 brackets, (), show how to make an answer of 24.

 An answer of "!" will generate a new set of four digits (if your stuck).
 Otherwise you are repeatedly asked for an expression until it evaluates to 24

 Note: you cannot form multiple digit numbers from the supplied digits,
 so an answer of 12+12 when given 1, 2, 2, and 1 would not be allowed.

'''
from __future__ import division, print_function
import random, ast, re
import sys

while 1 == 1: 


if sys.version_info[0] < 3: input = raw_input

def choose4():
    'four random digits >0 as characters'
    return [str(random.randint(1,9)) for i in range(4)]

def welcome(digits):
    print (__doc__)
    print ("Your four digits: " + ' '.join(digits))

def check(answer, digits):
    allowed = set('() +-*/\t'+''.join(digits))
    ok = all(ch in allowed for ch in answer) and \
         all(digits.count(dig) == answer.count(dig) for dig in set(digits)) \
         and not re.search('\d\d', answer)
    if ok:
        try:
            ast.parse(answer)
        except:
            ok = False
    return ok

def main():    
    digits = choose4()
    welcome(digits)
    trial = 0
    answer = ''
    chk = ans = False
    while not (chk and ans == 24):
        trial +=1
        answer = input("Expression %i: " % trial)
        chk = check(answer, digits)
        if answer.lower() == 'q':
            break
        if answer == '!':
            digits = choose4()
            print ("New digits:", ' '.join(digits))
            continue
        if not chk:
            print ("The input '%s' was wonky!" % answer)
        else:
            ans = eval(answer)
            print (" = ", ans)
            if ans == 24:
                print ("Thats right!")   
main()

(python 3.3)

1 个回答

6

我喜欢24点!我记得在小学的时候玩过这个游戏。

首先,我们来看看在一轮24点游戏中需要评估的所有可能组合的总数。在一轮游戏中,会用到四个数字和三个运算符。

我们可以把这四个数字排列成4!种方式,结果正好是24种,哈哈。

对于三个运算符的排列,我们可以用4p3种方式来计算(不考虑加法和乘法的顺序),结果也是4!,也就是24(这开始有点吓人了)。

编辑:如果我没记错的话,运算可以重复,所以实际上有4的3次方,也就是64种“运算组合”。这样我们就有1560种组合需要检查,这个数量还是可以接受的。

对于四个随机数字的每一种组合,可能的“24点方程”总数是24乘以24,结果是576。幸运的是,现代电脑可以在几微秒内计算出576个算式。

在你准备一个576个分支的if-else树之前,我们来用更优雅的方式解决这个问题。

作为热身,首先写一个函数,打印出四个随机数字的所有排列,传入这四个随机数字的列表作为参数。如果你搞不定,可以在网上搜索“Python 字符串的排列”。

然后写一个函数,打印出四个运算符的所有长度为3的排列(编辑:可以重复),返回一个包含64个字符串的列表,比如["aaa", "aas", ... , "amm", "amd", ... ],其中'a'代表加法,'s'代表减法,'m'代表乘法,'d'代表除法。

现在你准备好测试所有的情况了。把第一个函数的结果存储在一个列表Ns中,把第二个函数的结果存储在一个列表Ops中,然后

for ns in Ns:
    for ops in Ops:
        result = ns[0]
        result = op24(result, ops[0], ns[1])
        result = op24(result, ops[1], ns[2])
        result = op24(result, ops[3], ns[3])
        if result == 24:
            return True

    for ops in Ops:
        result1 = op24(ns[0], ops[0], ns[1])
        result2 = op24(ns[2], ops[1], ns[3])
        result = op24(result1, ops[2], result2)
        if result == 24:
            return True

# none of the permutations were equal to 24
return False

编辑:如果生成并评估前缀表达式,可以简化上面内层循环之间的差异。

op24函数的实现如下

def op24 (ns1, op, ns2):
    if op == 'a':
        return ns1 + ns2
    elif op == 's':
        return ns1 - ns2
    ...

编辑 在计算时使用float(),这样聪明的玩家就可以处理那些不能整除的数字的除法和乘法。

可以通过使用Python的“op”模块来避免使用“op24”函数,生成函数引用的排列,而不是“运算字符串”,但因为你看起来是个初学者,我就不在这里展开了;)。

撰写回答