24 game solver 演算法是一種遞迴式「配對再合併」的程序,它把你輸入的四個數字視為一個項目池,每次挑出其中兩個,用四種基本算術運算之一把它們結合起來,用新的值取代這對數字,然後不斷重複,直到只剩下一個項目可以拿來檢驗是否等於 24。驅動我們 24 Game Solver 工具的這套演算法,會把每一個中間值都以「已約分的整數分子除以正整數分母」的形式儲存,因此最終的比對會變成 numerator = 24 × denominator,並拒絕任何只是接近 24、而不是精確等於 24 的答案。因為減法與除法不具交換律,這套演算法會針對這兩種運算,嘗試每一對數字的兩種順序,並在除數為零時跳過除法運算。由於四個輸入值上限為 99,運算過程中的整數乘積會維持在安全整數範圍內,搜尋過程能保持精確、不需要任何溢位的變通做法。就其公開的規則集而言,這個程序是窮舉式的:當它回傳「無解」時,這個結果代表在所顯示的運算範圍內,沒有任何算式能等於 24,而不是這次執行剛好運氣不好、漏掉了答案。

24 game solver algorithm
24 game solver algorithm

配對再合併演算法如何走遍整個項目池

24 Game Solver 背後的演算法,把四個數字視為一個由項目物件組成的池子,每個項目都是一個已約分的分數,而不是原始的整數或浮點數。在每一步遞迴中,它會挑出一組無序的項目配對,用四種基本運算之一,產生這兩個項目所有合法的結合結果,把這個新的項目放回較小的池子裡,再對這個剩三個項目的較小池子繼續遞迴。它會持續這樣做,直到池子裡只剩下一個項目為止。

從 (a, b, c, d) 開始,第一步會產生一個含三個項目的池子:((a ⊕ b), c, d),其中 ⊕ 是四種運算之一。下一步會從這個三項目的池子中,再挑出另一組無序配對──((a ⊕ b) ⊕ c, d) 或 (a, (b ⊕ c) ⊕ d),或其他排列方式──然後再次遞迴。先選哪一對的不同順序,對應到不同的加括號方式,所以透過在各個遞迴分支中輪流變換第一次挑選的配對,這套演算法能走遍四個輸入值與四種基本運算所能產生的每一種二元樹結構。

加法與乘法具有交換律,所以對這兩種運算來說,演算法針對每一組無序配對只會產生一個結果。減法與除法則不具交換律,所以對這兩種運算來說,每一組配對都會產生兩個候選結果──先是 (a − b) 與 (b − a),接著在除數不為零時計算 (a ÷ b) 與 (b ÷ a)。「分母恆為正」這條規則會在每一次約分步驟中被強制執行,這樣演算法就永遠不需要去處理單一中間值上模稜兩可的正負號問題。窮舉搜尋指南中有這套配對再合併方法的完整實作說明。

為什麼已約分的分數勝過浮點數運算

最終的相等性檢查

遞迴過程中產生的每一個候選結果,都會透過把它的約分形式寫成 p / q(q 為正數),並要求 p = 24 × q 來檢驗。因為每一次約分步驟,都會把分子與分母同時除以它們的最大公因數,所以重複運算並不會累積會改變比對意義的公因數。一個只是近似 24 的值──例如由浮點數除法計算 47/3 × 24/6 所得到的 23.99999998──會在這項檢查中失敗,並被判定為不合格的候選結果。而一個以分數表示恰好等於 24 的值,例如來自一連串合法除法運算的 192/8,則會正確通過這項檢查。

為什麼二進位浮點數會漏掉合法的答案

有些牌組確實需要在中間步驟出現分數值。經典的 (3, 3, 8, 8) 組合,唯有在過程中某一步得到 8/3,接著再把其餘數字帶到最終等於 24 的結果,才能走到 24。如果一套解題器把每一個中間值都四捨五入成二進位浮點數,就可能把 8/3 變成 2.6666666666666665,進而漏掉原本能精準收斂到 24 的後續運算鏈。把中間值儲存成已約分的分數 8/3、而不是那個小數,就能保留所有後續依賴精確分子與分母的運算。根據加州大學聖塔克魯茲分校的 24 Game 程式文件4nums 上經過交叉核對的牌組清單,這種以精確分數運算的做法,正是嚴謹的 24 game 解題器所採用的標準慣例,所以這裡使用已約分的分數,是對已發布規則集的忠實實作,而不是自訂的選擇。若想更深入比較整數猜測式的捷思法,請參閱分數運算指南

如何使用 24 Game Solver 執行這套演算法

在瀏覽器中開啟 24 Game Solver。這個頁面不需要登入,完全在本機分頁中執行,每次查詢處理一組牌組。

  1. 輸入恰好四個 1 到 99 之間的整數,每個欄位一個。系統不接受開頭補零、負數,或小數輸入。
  2. 選擇 Solve。這套演算法會走遍每一組無序配對與每一種合法的結合方式,並在每一步都切換成已約分的分數,讓運算保持精確。
  3. 從內到外閱讀每一個回傳的算式。從最內層加括號的配對開始,把它算成一個分數,再一次處理一對、逐步往外推。
  4. 把最多 50 個回傳的構造,與你自己嘗試的答案做比較。這份清單會先依長度排序、再依字母順序排序,所以最短、最可信的答案會排在最前面。
  5. 如果頁面回報無解,就把這個結果視為在所公開規則下的最終判定。像次方、階乘、數字串接,或重複使用數字這類不同的規則集,屬於另一個不同的問題,可能存在這個受限解題器不會顯示出來的答案。

對於大多數牌組來說,這個過程會在遠低於一秒的時間內完成。有很多解的牌組,可能會讓頁面接近它 50 條算式的上限;設定這個上限,是為了在一個答案有很多等價形式時,讓分頁維持可讀性。

實際範例:對 3、3、8、8 執行這套演算法

牌組 (3, 3, 8, 8) 是教科書等級的案例,演算法必須用到分數中間值,因此很適合當作第一個逐步示範。在基本規則下有效的這一系列算式,會收斂成:

8 ÷ (3 − 8 ÷ 3) = 24

由內而外運算如下:

  • 最內層的配對是 8 ÷ 3,以分數表示約分為 8/3。
  • 下一個配對是 3 − 8/3,以分數表示為 (9/3 − 8/3) = 1/3。
  • 最外層的配對是 8 ÷ 1/3,也就是 8 × 3 = 24/1。
  • 最終相等性檢查:分子 = 24,分母 × 24 = 24 × 1 = 24,兩者相符。

把 (3, 3, 8, 8) 輸入這個工具並選擇 Solve,會在結果清單中回傳屬於這個系列的算式,以及一些以稍微不同的記法表達同一種算術想法、順序重排後的形式。一個只允許整數除法的解題器,永遠無法走到這條路徑,因為中間的 8/3 這一步會塌縮成一個四捨五入後的值,破壞掉後面的運算鏈。

用來測試這套演算法邊界情況的牌組

有四組已公開的基準牌組,會持續用來檢驗這套實作。以下的驗證數字並不是在這個頁面上算出來的;它們是用來檢驗這套演算法的牌組。

牌組是否有解?演算法必須證明什麼
1、2、3、4一條純乘法運算鏈能讓每個輸入恰好使用一次,並得到 24。
3、3、8、8算式中間會出現 8/3 這個分數,並在後續運算鏈中被完整保留。
1、5、5、5在整條運算鏈收斂到 24 之前,需要用到不只一個已約分的分數。
1、5、11、13窮舉搜尋證明了,在基本運算範圍內不存在能精確等於 24 的算式。

除了是否有解之外,同一組測試牌組還涵蓋輸入長度驗證、99 的整數上限、負分母的正規化處理、除法是否存在,以及 50 筆結果上限。這套實作的規約,已對照加州大學聖塔克魯茲分校的規則說明,以及 4nums 上的牌組清單進行驗證。

這套演算法會拒絕的運算

24 game solver 演算法只接受已發布規則集中定義的四種基本運算。它會拒絕其他所有變換方式,因為如果規則放得更寬鬆,上述的驗證基準就無法成立。

運算此處是否允許?原因
加法基本運算規約的一部分。
減法基本運算規約的一部分;兩種順序都會嘗試。
乘法基本運算規約的一部分。
除法基本運算規約的一部分,並附帶分母恆為正的規則。
數字串接會讓 1 與 23 組成 123,破壞「四個數字各用一次」的規則。
次方超出基本運算規約的範圍。
階乘超出基本運算規約的範圍。
開根號超出基本運算規約的範圍。
插入小數點把一個整數當成非整數處理,違反整數輸入的規約。
重複使用數字每個輸入都必須在最終算式中恰好出現一次。
把一元負號當成獨立運算含零項的減法是另一個問題,不會被獨立呼叫。

這套窄範圍的規約,與加州大學聖塔克魯茲分校的 24 Game 資源,以及 4nums 上經過交叉核對的牌組清單相符,所以這套演算法對已發布的 24 Game 保持忠實,不會悄悄擴充到涵蓋允許次方、階乘或數字串接的變體謎題。

從內到外閱讀回傳的算式

每一個回傳的算式,都會顯示完整的加括號形式,後面接著 = 24,所以答案可以被直接檢驗,而不是被當成一則未經說明的成功訊息照單全收。括號並不是裝飾用的。它們揭露了產生這個值的運算順序,移除括號可能會把原本隱含的分組方式重新排列成另一個不再等於 24 的算式。

檢查的流程是:從最內層加括號的配對開始,把它化簡成單一分數,再一次處理一對、逐步往外推,並用演算法所使用的同一條「分子等於 24 乘以分母」規則來確認最終的相等性。如果算式在這個過程中沒有精確化簡為 24,這個構造就是錯的。如果化簡結果確實是 24,這個構造就是對的,而演算法對這組牌組、在輸入欄位上方所顯示的規則集之下所做出的判定,也就得到了證實。