最近碰到個(gè)需求,計(jì)算游戲得分的規(guī)則,類似這樣:
游戲人數(shù)
|
第一名獲得賭注
|
第二名獲得賭注
|
第三名獲得賭注
|
第四名獲得賭注
|
二人
|
100%
|
0%
|
—
|
—
|
二人(出現(xiàn)2個(gè)第1名時(shí))
|
50%
|
50%
|
|
|
三人
|
70%
|
30%
|
0%
|
—
|
三人(出現(xiàn)3個(gè)第1名時(shí))
|
33.3333%
|
33.3333%
|
33.3333%
|
|
三人(出現(xiàn)2個(gè)第1名時(shí))
|
50%×2
|
0%
|
|
|
......
......
這些獎(jiǎng)勵(lì)規(guī)則沒有什么規(guī)律,隨著人數(shù)增多,就越發(fā)復(fù)雜了,并且業(yè)務(wù)人員可能隨時(shí)改變這些規(guī)則。
顯然,獎(jiǎng)勵(lì)規(guī)則可以采用策略模式,定義策略接口,根據(jù)游戲人數(shù)定義不同的規(guī)則,本質(zhì)上就是利用動(dòng)態(tài)的多態(tài)調(diào)用。可以想見,還是少不了復(fù)雜的case...when語句,以及繁多的代碼。恰好最近讀《unix編程藝術(shù)》和《代碼大全2》,兩者都提到一個(gè)結(jié)論:人類閱讀復(fù)雜數(shù)據(jù)結(jié)構(gòu)遠(yuǎn)比復(fù)雜的控制流程容易,或者說數(shù)據(jù)驅(qū)動(dòng)開發(fā)是非常有價(jià)值的。《代碼大全2》聲稱這個(gè)是表驅(qū)動(dòng)法。因此,這個(gè)獎(jiǎng)勵(lì)系數(shù)的計(jì)算,能否轉(zhuǎn)化成一個(gè)查表過程呢?注意到,在游戲中,名次是根據(jù)個(gè)人的積分在所有玩家中的排位來決定,大概會(huì)有這么個(gè)排序的玩家積分?jǐn)?shù)組[100,50,3],這個(gè)數(shù)組表示3個(gè)玩家,第一名100分,第二名50分,第三名才3分。依據(jù)規(guī)則,第一名的獎(jiǎng)勵(lì)系數(shù)就是0.7,第二名就是0.3。我想到類似這樣的數(shù)組其實(shí)都有個(gè)形式表示它們的內(nèi)置結(jié)構(gòu),比如[100,50,3]數(shù)組的“結(jié)構(gòu)”是"111",代表3個(gè)位置都有一個(gè)人。將"111"作為關(guān)鍵碼去查表不就OK了?
將每個(gè)排好序的積分?jǐn)?shù)組解碼為這樣的關(guān)鍵碼,然后去查預(yù)先寫好的獎(jiǎng)勵(lì)系數(shù)表,這個(gè)獎(jiǎng)勵(lì)系數(shù)表大概類似:
@@award_rate_hash={
:"2"=>{
:"11"=>{:"1"=>1,:"2"=>0},
:"20"=>{:"1"=>0.5,:"2"=>0.5}
},
:"3"=>{
:"111"=>{:"1"=>0.7,:"2"=>0.3,:"3"=>0},
:"300"=>{:"1"=>0.33},
:"201"=>{:"1"=>0.5,:"3"=>0},
:"120"=>{:"1"=>1,:"2"=>0}
},
:"4"=>{
:"1111"=>{:"1"=>0.65,:"2"=>0.30,:"3"=>0.05,:"4"=>0},
:"4000"=>{:"1"=>0.25},
:"3001"=>{:"1"=>0.33,:"4"=>0},
:"1300"=>{:"1"=>1,:"2"=>0},
:"2020"=>{:"1"=>0.5,:"3"=>0},
:"1201"=>{:"1"=>0.7,:"2"=>0.15,:"4"=>0},
:"1120"=>{:"1"=>0.7,:"2"=>0.3,:"3"=>0},
:"2011"=>{:"1"=>0.35,:"3"=>0.3,:"4"=>0}
}
}
一個(gè)三級hash表,首先根據(jù)玩家人數(shù)查到特定的系數(shù)表,比如要查3個(gè)玩家、積分?jǐn)?shù)組是[100,50,3]的獎(jiǎng)勵(lì)系數(shù)表就是
@@award_rate_hash[:"3"],然后積分?jǐn)?shù)組[100,50,3]
解碼為:"111",繼續(xù)查,如此規(guī)則的獎(jiǎng)勵(lì)系數(shù)表就是@@award_rate_hash[:"3"][:"111"]——也就是 {:"1"=>0.7,:"2"=>0.3,:"3"=>0},那么查積分是100的玩家系數(shù)就是@@award_rate_hash[:"3"][:"111"][([100,50,3].index(100)+1
).to_s.to_sym],也就是:"1"=>0.7。[100,50,3].index(100)+1
就是積分100的玩家在數(shù)組中的名次(即1),也就是:"1"指向的結(jié)果0.7。其他玩家的查表過程與此類似,不細(xì)說了。
這樣,我們所有的獎(jiǎng)勵(lì)規(guī)則就是維護(hù)這么一張hash表,這個(gè)表看起來復(fù)雜,其實(shí)完全可以自動(dòng)生成,讓業(yè)務(wù)人員來提供樣例數(shù)據(jù),解碼樣例數(shù)據(jù)并生成這個(gè)表是很簡單的事情。積分?jǐn)?shù)組的“解碼”,我給一個(gè)Ruby版本:
#解碼數(shù)組為字符串關(guān)鍵碼
def decode_array(array)
len=array.size
trace_list=[]
result=[]
len.times do |time|
result[time]=0
trace_list[time]=false
end
array.each_with_index do |item,index|
result[index]=count_times(array,trace_list,index,len)
end
return result.join('').to_sym
end
def count_times(array,trace_list,index,len)
item=array[index]
result=0
(index..len).each do |i|
if array[i]==item and !trace_list[i]
result+=1
trace_list[i]=true
end
end
return result
end