Python破解24點遊戲,從此打撲克就沒輸過

2021-10-06 13:18:02 字數 3597 閱讀 9713

24點遊戲

對於任意給定的四張撲克牌,計算是否有贏得24點遊戲的方法(即使用加、減、乘、除四則運算湊成24的方法);如果有的話,列出所有可能的方法。

在大小王以外的52張牌中,任意抽取其中4張牌。

如果通過加、減、乘、除四則運算(可加括號)的方法,將抽到的4張牌算成24,則為勝利;每張牌都必須使用,且只能使用一次。

第一種解法

依據遊戲規則,我們可以想到如下解決思路:使用列舉的方法,將所有的計算方法都列舉出來,將四張撲克牌的數字代入到所有的計算方法中得出結果,如果結果為24則為解。

由此,我們得到了第一種解法。

在具體實現中:將所有可能的四則運算組合和所有可能的括號組合合併在一起,由此生成所有可能的算式組合。計算某乙個牌組時,先計算所有該牌組所有可能的組合方式,並將所有的組合方式帶入所有可能的算式組合求解。

import itertools

​ class cardgaming:

def __init__(self):

self.formula_list = list() # 儲存所有可能的算式

for marks in itertools.product(["+", "-", "*", "/"], repeat=3):

for bracket in ["%s%s%s", "(%s)%s%s", "(%s%s)%s",

"%s(%s)%s",

"%s(%s%s)", "(%s)%s(%s)", "%s%s(%s)"]:

​ def solve(self, card_probability):

answer =

for card_order in set(itertools.permutations(card_probability, 4)): # 遍歷所有可能的不同卡牌順序(最多24種可能)

for formula in self.formula_list: # 遍歷所有可能的算式(448種可能)

final_formula = formula.format(*card_order)

try:

if round(eval(final_formula), 3) == 24:

except zerodivisionerror:

continue

return answer

​ if __name__ == "__main__":

print(cardgaming().solve((3, 3, 8, 8))) # 輸出: 8/(3-8/3)

當前**在計算每乙個牌組的答案時,都需要遍歷4^3*7=448種算式和最多a44=24種卡牌順序,即處理最多448*24=10752種可能性。使用這個解法計算所有可能的撲克牌組合(共計13^4=28561種解法),需要1906秒(i7 7700,8gb)。

第二種解法

在第一種解法中,計算每乙個牌組的答案時,處理的可能性中有很多重複的情況,例如「a+b-c+d」、「d-c+b+a」、「d+a-c+b「等。這就極大地拖累了我們的運算速度。

但是,要在第一種解法的基礎上來合併這些不同的情況,需要同時考慮符號、括號和卡牌順序,十分複雜。

因此,我們可以從另外乙個角度來解決這個問題。

通過觀察我們可以發現,無論什麼算式,本質上都是按著一定的順序,對4張撲克牌的數值進行三次運算;而每一次運算,都是從尚未用過的撲克牌以及之前的運算結果中選擇2個進行運算。所以,我們可以將所有算式歸納為:

從4張牌中任意抽取2個進行任意運算,將未抽取的2張牌和運算結果組合成包含3個數值的新列表;在新列表中任意抽取2個進行任意運算,將未抽取的1張牌和運算結果組成包含2個數值的新列表;對新列表中的2個數值進行任意運算得出結果,如果結果為24則為解。

由此,我們得到了第二種演算法。在具體實現中,我們主要注意如下幾點:

def solve(card_probability):

card_probability = list(card_probability) # 生成臨時列表

answer =

for combine_1 in set(itertools.combinations(card_probability, 2)): # 在臨時列表的4個數中任意抽取2個數

for answer_1 in all_maybe_count_answer(combine_1[0], combine_1[1]):

card_list_1 = copy.deepcopy(card_probability)

card_list_1.remove(combine_1[0]) # 從臨時列表移除抽到的數1

card_list_1.remove(combine_1[1]) # 從臨時列表移除抽到的數2

for combine_2 in set(itertools.combinations(card_list_1, 2)): # 在臨時列表的3個數中任意抽取2個數

for answer_2 in all_maybe_count_answer(combine_2[0], combine_2[1]):

card_list_2 = copy.deepcopy(card_list_1)

card_list_2.remove(combine_2[0]) # 從臨時列表移除抽到的數1

card_list_2.remove(combine_2[1]) # 從臨時列表移除抽到的數2

for combine_3 in set(itertools.combinations(card_list_2, 2)): # 抽取臨時列表剩下的2個數

for answer_3 in all_maybe_count_answer(combine_3[0], combine_3[1]):

if round(answer_3, 3) == 24:

answer_2, combine_3, answer_3)) # 生成完整算式

return answer

​ ​if __name__ == "__main__":

start_time = time.time()

for cards in list(itertools.product([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], repeat=4)):

solve(cards)

其中all_maybe_count_answer函式計算兩個引數進行四則運算的所有可能結果;total_formula函式依據中間變數生成完整計算公式)

執行結果:

這種接法在第一次四則運算時,有種c24=6抽取結果,有6種運算結果(減法和除法因順序不同有2個結果);在第二次四則運算時,有種c23=3抽取結果,有6種運算結果;在第三次四則運算時,有c22=1種抽取結果,有6種運算結果。

因此,這種演算法在求乙個撲克牌組的解時,僅需要考慮c24*6*c23*6*c22*6=3888種可能性。使用這個解法計算所有可能的撲克牌組合,需要136秒(i7 7700,8gb),比第一種解法快了10倍以上。

完整原始碼:

Python實現撲克24點小遊戲 ,從此我就沒輸過

ps注意 很多人學python過程中會遇到各種煩惱問題,沒有人解答容易放棄。為此小編建了個python全棧免費答疑.裙 七衣衣九七七巴而五 數字的諧音 轉換下可以找到了,不懂的問題有老司機解決裡面還有最新python實戰教程免非下,一起相互監督共同進步!一 設計思路 由於設計到了表示式,很自然的想到...

Python實現24點遊戲

24點遊戲是經典的紙牌益智遊戲。我的思路是把這4個數分成2部分,前兩個數一起,後兩個數一起,先計算除前兩個數所有可能的結果和後兩個數所有可能的結果。最後將它們的結果互相計算,結果與24比較,如果等於24則成功。建立使用者類,整個遊戲的體系就是建立乙個使用者類來儲存使用者的資訊,如姓名,生命值,分數等...

用python寫24點遊戲

思路 通過暴力方法破解 即全排列 利用字尾表示式來去除括號的麻煩 對零這個特殊數字的處理 再字尾轉中綴表示式 輸入4個 1 13 之間的數字 definput while true try a,b,c,d map int,input 請輸入 1 13 之間的四個數字 空格分開 split for i...