Python實(shí)現(xiàn)快速計(jì)算24點(diǎn)游戲的示例代碼
24 點(diǎn)游戲規(guī)則
有4個(gè)范圍在 [1,9] 的數(shù)字,通過「加、減、乘、除」四則運(yùn)算能夠獲得24,認(rèn)為有解。
4個(gè)范圍在 [1,9] 的數(shù)字能夠產(chǎn)生495種可能,其中404中組合情況都是有解的,有解概率高達(dá)81.62%。
下面我們用python來驗(yàn)證它,首先計(jì)算組合數(shù):
from scipy.special import comb comb(9, 4, repetition=True)
495.0
可以看到python計(jì)算出9個(gè)數(shù)字有重復(fù)的組合情況數(shù)是495。
下面我們需要一個(gè)方法,判斷4個(gè)數(shù)字能否組合成為24點(diǎn),這里我采用回溯算法進(jìn)行計(jì)算。
回溯算法計(jì)算思路
首先從4個(gè)數(shù)字中選擇2個(gè)數(shù)字,然后再選擇一種運(yùn)算操作,然后用得到的結(jié)果取代選出的2個(gè)數(shù)字。然后在剩下的3個(gè)數(shù)字中,進(jìn)行同樣的操作。依次類推,最終計(jì)算到只剩一個(gè)數(shù)字,看結(jié)果是否為24即可。
開始編碼:
from operator import add, mul, sub, truediv ops = [add, mul, sub, truediv] def judgePoint24(nums) -> bool: if not nums: return False n = len(nums) if n == 1: return round(nums[0], 3) == 24 for i, j in permutations(range(n), 2): # 選2個(gè)數(shù)字 x, y = nums[i], nums[j] newNums = [] # 選擇加減乘除 4 種運(yùn)算操作之一,用得到的結(jié)果取代選出的 2 個(gè)數(shù)字 for k, z in enumerate(nums): if k != i and k != j: newNums.append(z) for k in range(4): if k < 2 and i > j: # 加法和乘法滿足交換律,跳過第二種順序 continue if k == 3 and round(y, 3) == 0: # 除法運(yùn)算除數(shù)不能為0 continue newNums.append(ops[k](x, y)) if judgePoint24(newNums): return True newNums.pop() return False
然后我們遍歷所有的組合進(jìn)行判斷:
from scipy.special import comb ???????total = int(comb(9, 4, repetition=True)) cnt = sum(judgePoint24(nums) for nums in combinations_with_replacement(range(1, 10), 4)) print(f'{cnt}/{total}={cnt/total:.2%}')
最終一秒內(nèi)計(jì)算出結(jié)果:
生成表達(dá)式
下面我們加大難度,要求在求解時(shí),能夠同時(shí)返回可行的表達(dá)式。暴力遍歷固然可以實(shí)現(xiàn),但是耗時(shí)太長(zhǎng),能否在這種回溯算法的基礎(chǔ)上實(shí)現(xiàn)呢?
我的思路是加個(gè)變量記錄每次的選擇,最終再通過一定的技巧進(jìn)行還原,最終編碼:
from operator import add, mul, sub, truediv from itertools import permutations, combinations_with_replacement from collections import defaultdict def judgePoint24(nums) -> bool: ops = [add, mul, sub, truediv] op_char = "+*-/" record = [] def solve(nums) -> bool: if not nums: return False n = len(nums) if n == 1: return round(nums[0], 3) == 24 for i, j in permutations(range(n), 2): # 選2個(gè)數(shù)字 x, y = nums[i], nums[j] newNums = [] # 選擇加減乘除 4 種運(yùn)算操作之一,用得到的結(jié)果取代選出的 2 個(gè)數(shù)字 # 先添加未選擇的數(shù)字 newNums = [z for k, z in enumerate(nums) if k not in (i, j)] for k in range(4): if k < 2 and i > j: # 加法和乘法滿足交換律,跳過第二種順序 continue if k == 3 and (round(y, 3) == 0): # 除法運(yùn)算除數(shù)不能為0 continue v = ops[k](x, y) newNums.append(v) record.append(([round(x, 3), round(y, 3)], op_char[k], round(v, 3))) if solve(newNums): return True newNums.pop() record.pop() return False flag = solve(nums) if not flag: return False, "" cache = defaultdict(list) for ns, op, v in record: for i in range(2): if cache[ns[i]]: ns[i] = "("+cache[ns[i]].pop()+")" a, b = ns cache[v].append(f"{a}{op}") return flag, cache[24][0]+"=24"
然后開始遍歷:
total = cnt = 0 for nums in combinations_with_replacement(range(1, 10), 4): total += 1 r, expression = judgePoint24(nums) if r: print(expression, end="\t") cnt += 1 if cnt % 8 == 0: print() print() print(f'{cnt}/{total}={cnt/total:.2%}')
最終結(jié)果:
可以看到,我們已經(jīng)得到了404個(gè)24點(diǎn)的有效解表達(dá)式。
到此這篇關(guān)于Python實(shí)現(xiàn)快速計(jì)算24點(diǎn)游戲的示例代碼的文章就介紹到這了,更多相關(guān)Python計(jì)算24點(diǎn)游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
opencv 獲取rtsp流媒體視頻的實(shí)現(xiàn)方法
這篇文章主要介紹了opencv 獲取rtsp流媒體視頻的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08python保存log日志,實(shí)現(xiàn)用log日志畫圖
今天小編就為大家分享一篇python保存log日志,實(shí)現(xiàn)用log日志來畫圖,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12對(duì)比分析BN和dropout在預(yù)測(cè)和訓(xùn)練時(shí)區(qū)別
這篇文章主要為大家介紹了對(duì)比分析BN和dropout在預(yù)測(cè)和訓(xùn)練時(shí)區(qū)別,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05Python爬取破解無線網(wǎng)絡(luò)wifi密碼過程解析
這篇文章主要介紹了Python爬取破解無線網(wǎng)絡(luò)密碼過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09