python 之玩轉24點數字遊戲
最近迷上了24點數字遊戲,讓四個數字在腦子裡隨意碰撞,結合,然後檢查最後的結果,然後再碰撞,結合,檢查,不斷重複…到最後總會有一種方法讓這四個數字乖乖的等於24。當然,前提是這四個數字得來自正規的24點遊戲庫,因為不是隨便四個數字都能得到24點的。
在手機上的遊戲軟體上玩了數十關之後,我突發奇想,為何不把這活交給程式做做呢?由於最近一直在學習Python,就打算用Python玩玩這個遊戲,看看結果如何。
我本著先懟出來為敬的原則(就是不考慮演算法,不考慮效率,不考慮計算時間等等,先出結果再說)自然而然想到的就是窮舉。一共四個數字,外加三個運算子(將四個數字整合成一個數字只須要三個運算子號即可,實際用到的運算子號有四個:加、減、乘、除),這些都是小整數,計算機窮舉其實也費不了多大勁。
既然要窮舉,那就要考慮到所有的情況。下面上一個“24點遊戲萬能公式”:
●代表任一運算子。我的思路是先給這四個數字一個全排列,也就是24種情況,然後每一個運算子來一個遍歷,也就是64種情況,這樣算來最多隻要迴圈24x64次就能得到結果。
思路有了,然後開始程式設計。對於運算子號,我用的是operator模組中的add,sub,mul 和 truediv 函式,因為基於Python中所有函式都是一等物件的理念,把這四個函式放進一個列表裡之後很容易實現遍歷。實現全排列則用的是 itertools 模組中的 permutations 函式。好了,廢話不多說,直接上程式:
from operator import add,sub,mul,truediv as div
from itertools import permutations
def pts_24(list_int_4):
operator_4 = [add,sub,mul,div]
ops = ['+','-','x','/']
for ls in permutations(list_int_4,4):
for oprt_1 in operator_4:
for oprt_2 in operator_4:
for oprt_3 in operator_4:
try:
result = oprt_1(ls[0],oprt_2(ls[1],oprt_3(ls[2],ls[3])))
except ZeroDivisionError: #除數是零的情況在這種全面的遍歷下似乎不可避免
pass #為了程式流暢以及輸出美觀,所以跳過
#PS:反正這種情況肯定不是我們想要的結果
if result == 24:
print('Done')
i = operator_4.index(oprt_1)
j = operator_4.index(oprt_2)
k = operator_4.index(oprt_3)
bra1='' #以下包括兩個if語句是針對運算優先順序做的輸出格式上的優化
bra2=''
ket1=''
ket2=''
if i>=1 and j<2 or i==3:
bra1 = '('
ket1 = ')'
if j>=1 and k<2 or j==3:
bra2 = '('
ket2 = ')'
return (str(ls[0])+ops[i]+bra1+str(ls[1])+ops[j]+
bra2+str(ls[2])+ops[k]+str(ls[3])+ket2+ket1)
return("These four numbers can not be calculated to 24")
while True:
str_4 = input("Please input 4 integers separated by ' ': ")
if str_4 == 'q':
break
list_4 = str_4.split()
list_int_4 = [int(i) for i in list_4]
print(pts_24(list_int_4))
程式寫好後,我先上了一組 ‘6666’ 測試了一下:
Please input 4 integers separated by ' ': 6 6 6 6
Done
6+6+6+6
果然很順利。我又開啟24點遊戲軟體,上了一組“專業測試”,也都能一一通過。至此,我這個“先懟出來為敬的版本”算是大功告成了。
Please input 4 integers separated by ' ': 4 5 7 9
Done
5-(9-4x7)
Please input 4 integers separated by ' ': 4 10 8 10
Done
4-10x(8-10)
Please input 4 integers separated by ' ': 8 8 8 6
Done
8+8x(8-6)
Please input 4 integers separated by ' ': 99 99 99 99
These four numbers can not be calculated to 24
Please input 4 integers separated by ' ': 1 1 1 1
These four numbers can not be calculated to 24
最後兩種例外情況也都確證了不能找到使他們運算得到24的結果,但是到這裡有人可能會說,慢著,你看這:(1+1+1+1)! 不就正好等於24嗎?好啊,少俠有如此眼力,我的程式自然甘拜下風,所以我就只好在程式里加上一行這個了:(滑稽)
if A==B==C==D==1 or A==B==C==D==0:
print('(A!+B!+C!+D!)! = 24') #考慮到0,每個數字後面都加了階乘
在寫這個程式的過程中,中間也出了不少問題。我程式中計算的核心程式碼行:
result = oprt_1(ls[0],oprt_2(ls[1],oprt_3(ls[2],ls[3])))
運算的優先順序是從後往前的,而不管運算子號如何,這也算是遍歷(便利)中的一點小小不足吧。但是後面用上小括號,這個問題便迎刃而解了。這其中還有很多細節上的問題,我就不一一贅述了,對程式設計師來說,文字不重要,程式碼才是最重要的。
再會!