Python實現24點遊戲
24點遊戲是一款老少咸宜的益智遊戲,遊戲的玩法是給出任意四個數字,透過加減乘除四則運算,計算出24。
網上有很多24點遊戲演算法,找出解法並不難,但是難在如何合適地加括號和去除等價的重複表示式上。
1. 目標和要求
我們的目標是給定任意N個正整數(N > 1),找到能夠將這N個數透過四則運算計算得出24的全部表示式,並且只在必要的時候加上括號以及去除等價的重複表示式。
首先,我們要明確什麼是合適的括號?就是指在不影響計算結果的前提下,能不加括號儘量不加括號,比如:
(15 + 8) + 7 -6 = 24 應寫作 15 + 8 + 7 -6 = 24
其次,什麼是等價的重複表示式呢?就是完全相同的表示式,或者是在加法交換率和乘法交換率的作用下,完全等價的表示式。比如:
10 + 12 + 7 - 5 = 24 等價於 10 - 5 +7 + 12 = 24
15 * 8 / (1 + 4) = 24 等價於 15 / (4 + 1) * 8 = 24
(3 + 1) * (2 + 4) = 24 等價於 (1 + 3) * (4 + 2) = 24
2. 演算法
2.1. 求全部解演算法
我採用的演算法是降低維度的演算法,即把多維問題降低到二維來解決。
比如,給定四個數字[1, 2, 3, 4],這是一個四維問題,我們首先要將其轉換為二維問題。具體的辦法是,先將四個數字其中的兩個數字取出,然後將這兩個數字轉化為所能組成的全部表示式。
我們首先取出[1, 2],考慮到加法交換率和乘法交換率的前提下,共有6種可能的不等價表示式,即1+2, 1-2, 1*2, 1/2, 2-1, 2/1,則四維問題就可以轉化為多組三維問題,即['1+2', 3, 4],['1-2', 3, 4],['1*2', 3, 4], ['1/2', 3, 4], ['2-1', 3, 4], ['2/1', 3, 4]。
然後我們窮盡每一種取出兩個數的組合,使用排列組合公式即C(4, 2),所以將四維問題轉化為三維問題共有C(4, 2) * 6 = 36種組合。
下一步是重複這一過程,將三維問題繼續轉化為二維問題,同理,每一個三維問題都可轉化為等價的二維問題,共有C(3, 2) * 6 = 18種組合。
所以,四維問題可轉化為36 * 18 = 648種二維問題,每個二維問題又有6種組合方式,所以,全部的表示式個數為648 * 6 = 3888個。
2.2. 加括號演算法
在每一次二維組合成新表示式的時候,我們根據原有的兩個表示式的各自的運算子號和兩個表示式之間的運算子號的關係來判斷是否需要新增括號。
比如,a、b兩個表示式要組成新的表示式,總共會有如下幾種情況:
如果是a + b,則完全不需要加括號;
如果是a * b或者a / b,若a、b自身的運算子號是加號或減號,則應加括號,如,a = a1 + a2,b為數字,則a * b = (a1 + a2) * b;
如果是a - b,若b為加號或減號,則b應加括號,如,b = b1 - b2,a = a1 + b2,則 a - b = a1 + a2 - (b1 - b2),但值得注意的是,a1 + a2 - (b1 - b2) 其實等價於 a1 + a2 - b1 + b2,這種情況在其他的組合中其實已經存在。因此,可以無需再考慮括號問題;
如果是a / b,若b的符號是乘號或除號,原本理應也要加括號,但其實這種情況與上一種情況類似,我們出於計算簡便考慮,可以不再考慮括號問題。
2.3. 去除等價表示式
對於一個表示式,a + b - c + d 與如下表示式均是等價的:
a + d + b - c
b + a + d -c
b - c + a + d
我們可以在任何一個表示式前再加一個加號,然後使用正規表示式對錶達式進行切割成如下狀態:['+a', '+b', '-c', '+d']。
然後對其進行排序後再組合成字串得到:
a + b + d - c
我們將這樣的表示式稱為標準表示式,凡是透過這樣的處理方法得到的標準表示式是相同的,我們均認為是等價表示式,只保留一個標準表示式即可。
乘法交換率也是同樣的轉換方法。
3. 程式碼
演算法講完了,具體的程式碼實現如下:
# coding: utf-8from __future__ import divisionfrom itertools import combinationsimport reclass Solver: # 需要達成的目標結果值 target = 24 # 四則運算子號定義,其中,a -- b = b - a,a // b = b / a ops = ['+', '-', '*', '/', '--', '//'] # precise_mode為精準模式,若開啟,則減號及除號後開啟括號 def __init__(self, precise_mode=False): self.precise_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 = [] # 如果維數大於2,則選出兩個表示式組合成一個,從而降低一個維度,透過遞迴降低到二維 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.precise_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] # 對錶達式列表進行分組,返回列表,[[[n1, n2], [n3, n4]], [[n1, n3], [n2, n4]], ...] @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] ] auto_input = Trueif auto_input: from numpy import random 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)
作者:沒文化的查哥
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4550/viewspace-2816141/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JS實現24點遊戲JS遊戲
- 實現24點遊戲-窮舉法遊戲
- leetcode 679. 24 Game(遊戲24點)LeetCodeGAM遊戲
- 24點遊戲探秘系列7: 24點無解局面清單 (轉)遊戲
- 24點遊戲探秘系列6:用機率統計的眼光看24點遊戲 (轉)遊戲
- python實現撲克遊戲 - 抽鬼牌 和 21點Python遊戲
- Python秒算24點,行還是不行?Python
- C++實現http下載 && 24點計算編碼風格C++HTTP
- python例項:解決經典撲克牌遊戲 -- 四張牌湊24點 (一)Python遊戲
- python例項:解決經典撲克牌遊戲 -- 四張牌湊24點 (二)Python遊戲
- VR虛擬現實遊戲所體現的亮點分析VR遊戲
- python實現簡單猜單詞遊戲Python遊戲
- Python實現三子棋小遊戲Python遊戲
- Python程式碼實現“FlappyBird”小遊戲PythonAPP遊戲
- 只用lambda演算實現FizzBuzz遊戲(Python版)遊戲Python
- 暴力搜尋演算法的典型應用——24點遊戲演算法遊戲
- JAVAEE_Servlet_24_HttpSession實現原理JavaServletHTTPSession
- python實現的簡單點對點(p2p)聊天Python
- 曲線點抽稀演算法- Python 實現演算法Python
- python指令碼實現開心消消樂的遊戲Python指令碼遊戲
- 24點 Pascal大暴力程式
- 如何實現7*24小時慢直播應用?
- Base24編碼以及解碼的實現
- 親自動手實現Python+pygame中國象棋遊戲PythonGAM遊戲
- 利用python實現簡易版的貪吃蛇遊戲(面向python小白)Python遊戲
- 在虛擬現實中解謎,PSVR遊戲《Statik》將於4月24日正式發售VR遊戲
- 24. 平衡二叉樹,及其程式碼實現二叉樹
- Python:遊戲:300行程式碼實現俄羅斯方塊Python遊戲行程
- Python實現超級瑪麗遊戲系列教程01瑪麗登場Python遊戲
- js實現翻牌遊戲JS遊戲
- 遊戲侵蝕現實:產業的成熟,讓遊戲技術跨入現實遊戲產業
- webpack4.X 實戰(三):企業SPA 24點總結(上)Web
- 【經驗分享】Python實現UI自動化難點問題PythonUI
- Python寫個“點球大戰”小遊戲Python遊戲
- Python3+Pygame實現的射擊遊戲,很流暢,有音效PythonGAM遊戲
- python實現超級瑪麗小遊戲(動圖演示+原始碼分享)Python遊戲原始碼
- PHP+Redis 有序集合實現 24 小時排行榜實時更新PHPRedis
- 實驗| Pyecharts實現散點圖Echarts