1. 程式人生 > >python 之玩轉24點數字遊戲

python 之玩轉24點數字遊戲

最近迷上了24點數字遊戲,讓四個數字在腦子裡隨意碰撞,結合,然後檢查最後的結果,然後再碰撞,結合,檢查,不斷重複…到最後總會有一種方法讓這四個數字乖乖的等於24。當然,前提是這四個數字得來自正規的24點遊戲庫,因為不是隨便四個數字都能得到24點的。

在手機上的遊戲軟體上玩了數十關之後,我突發奇想,為何不把這活交給程式做做呢?由於最近一直在學習Python,就打算用Python玩玩這個遊戲,看看結果如何。

我本著先懟出來為敬的原則(就是不考慮演算法,不考慮效率,不考慮計算時間等等,先出結果再說)自然而然想到的就是窮舉。一共四個數字,外加三個運算子(將四個數字整合成一個數字只須要三個運算子號即可,實際用到的運算子號有四個:加、減、乘、除),這些都是小整數,計算機窮舉其實也費不了多大勁。

既然要窮舉,那就要考慮到所有的情況。下面上一個“24點遊戲萬能公式”:
A B C D =

24 A●B●C●D = 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])))

運算的優先順序是從後往前的,而不管運算子號如何,這也算是遍歷(便利)中的一點小小不足吧。但是後面用上小括號,這個問題便迎刃而解了。這其中還有很多細節上的問題,我就不一一贅述了,對程式設計師來說,文字不重要,程式碼才是最重要的。

再會!