Python算法之24点游戏
问题:输入任意的四个数字,这四个数字的取值范围:1~13,这个四个数经过任意的加、减、乘、除四则运算的结果是24,并输出这四个数所有的运算结果为24的可能计算方式组合。
例如,输入1,2,6,4
输出:4*6/(2-1)=26
(2-1)*4*6=24
(2+6)*(4-1)=24
((2-1)*6)*4=24
代码:from itertools import combinations import re from numpy import random class Solver: # 目标值 target = 24 # 四则运算符 ops = ["+", "-", "*", "/", "--", "//"] def __init__(self, precise_mode=False): self.preprecise_mode = precise_mode def solution(self, nums): result = [] groups = self.dimensionality_reduction(self.format(nums)) for group in groups: for op in self.ops: exp = self.assemble(group[0], group[1], op)["exp"] if self.check(exp, self.target) and exp not in result: result.append(exp) return [exp + "=" + str(self.target) for exp in result] # 降维 def dimensionality_reduction(self, nums): result = [] if len(nums) > 2: for group in self.group(nums, 2): for op in self.ops: new_group = [self.assemble(group[0][0], group[0][1], op)] + group[1] result += self.dimensionality_reduction(new_group) else: result = [nums] return result # 将两个表达式组合成一个 def assemble(self, exp1, exp2, op): if op == "--" or op == "//": return self.assemble(exp2, exp1, op[0]) if op in r"*/": exp1 = self.add_parenthesis(exp1) exp2 = self.add_parenthesis(exp2) if self.preprecise_mode: if op == "-": exp2 = self.add_parenthesis(exp2) elif op == "/": exp2 = self.add_parenthesis(exp2, True) exp = self.convert(exp1["exp"] + op + exp2["exp"], op) return {"op": op, "exp": exp} # 根据需要为表达式添加相应的括号 @staticmethod def add_parenthesis(exp, is_necessary=False): if (is_necessary and not exp["exp"].isdigit()) or exp["op"] in r"+-": result = { "exp": "(" + exp["exp"] + ")", "op": exp["op"] } else: result = exp return result @staticmethod def check(exp, target, precision=0.0001): try: return abs(eval(exp) - target) < precision except ZeroDivisionError: return False #将表达式各项重新排序为等价的表达式 @staticmethod def convert(exp, op): if op in r"+-": pattern = r"([+-](((.+)|d+)[*/]((.+)|d+)|d+))" exp = "+" + exp else: pattern = r"([*/]((.+?)|d+))" exp="*"+exp result = "".join(sorted(i[0] for i in re.findall(pattern, exp))) if len(result) != len(exp): result = exp return result[1:] # 将输入的数字格式化为字典 @staticmethod def format(nums): return [{"op": " ", "exp": str(num)} for num in nums] @staticmethod def group(exp_list, counter): # 生成以下标号为元素的列表 index_list = [i for i in range(len(exp_list))] # 以下标号列表取出不重复的组合 combination = list(combinations(index_list, counter)) for group1 in combination: group2 = list(set(index_list) - set(group1)) yield [ [exp_list[g1] for g1 in group1], [exp_list[g2] for g2 in group2] ] if __name__ == "__main__": auto_input = False if auto_input: customer_input = random.randint(1, 20, size=4) else: customer_input = list() customer_input.append(input("请输入第一个数字:")) customer_input.append(input("请输入第二个数字:")) customer_input.append(input("请输入第三个数字:")) customer_input.append(input("请输入第四个数字:")) task = Solver() answer = task.solution(customer_input) if len(answer) == 0: print("No solutions") else: for a in answer: print(a)