作者 | Dave Taylor
譯者 | wenwensnow
Bunco:一個使你的“快艇”遊戲看起來更複雜的擲骰子游戲。
我已經有段時間沒有編寫遊戲了,所以我覺得現在正是做一些這方面事情的時候。起初,我想“用指令碼編一個 Halo遊戲?”(LCTT 譯註:Halo,光暈系列遊戲),但我後來意識到這不太可能。來編一個叫 Bunco 的簡單骰子游戲吧。你也許沒有聽說過,不過你母親絕對知道 —— 當一群年輕女孩聚在當地的酒吧或者小酒館的時候,這是個很受歡迎的遊戲。
遊戲一共六輪,有三個骰子,規則很簡單。每次投三個骰子,投出的點數要和當前的輪數數字一致。如果三個骰子都和當前的輪數一致,(比如,在第三輪三個骰子都是 3),你這一輪的分數就是 21。 如果三個骰子點數都相同但和輪數數字不同,你會得到最低的 Bunco 分數,只有 5 分。如果你投出的點數兩者都不是,每一個和當前輪數相同的骰子得 1 分。
要想玩這個遊戲,它還涉及到團隊合作,每一隊(包括贏的那隊),每人付 5 美元現金,或贏家得到其他類似現金獎勵,並規定什麼樣的情況下才是贏家,例如“最多 Buncos” 或“最大點數”的情況下勝利。在這裡我會跳過這些,而只關註投骰子這一部分。
關於數學邏輯部分
在專註於程式設計這方面的事之前,我先簡單說說遊戲背後的數學邏輯。要是有一個適當重量的骰子投骰子會變得很容易,任意一個值出現機率都是 1/6。
完全隨機小提示:不確定你的骰子是否每個面都是一樣重量? 把它們扔進鹽水裡然後擲一下。YouTube 上有一些有趣的 D&D; 世界的影片向你展示了怎麼來做這個測試。
所以三個骰子點數一樣的機率有多大? 第一個骰子 100% 會有一個值 (這兒沒什麼可說的),所以很簡單。第二個則有 16.66% 的機率和第一個骰子的值一樣,接下來第三個骰子也是一樣。 但當然,總機率是三個機率相乘的結果,所以最後,三個骰子值相等的機率是 2.7%。
接下來,每個骰子和當前輪數數字相同的機率都是 16.66%。從數學角度來說:0.166 * 0.166 * 0.166 = 0.00462 。
換句話說,你有 0.46% 的可能性投出 Bunco,比 200 次中出現一次的可能性還小一點。
實際上還可以更難。如果你有 5 個骰子,投出 Mini Bunco (也可以叫做 Yahtzee “快艇”) 的機率為 0.077%,如果你想所有的骰子的值都相同,假設都是 6,那機率就是 0.00012%,那就基本上沒什麼可能了。
開始程式設計吧
和所有遊戲一樣,最難的部分是有一個能生成真正的隨機數的隨機數發生器。這一部分在 shell 指令碼中還是很難實現的,所以我需要先迴避這個問題,並假設 shell 內建的隨機數發生器就夠用了。
不過好在內建的隨機數發生器很好用。用 $RANDOM
就能得到一個 0
到 MAXINT(32767)
之間的隨機值:
$ echo $RANDOM $RANDOM $RANDOM
10252 22142 14863
為了確保產生的值一定是 1
– 6
之中的某個值,使用取餘函式:
$ echo $(( $RANDOM % 6 ))
3
$ echo $(( $RANDOM % 6 ))
0
哦!我忘了要加 1
,下麵是另一次嘗試:
$ echo $(( ( $RANDOM % 6 ) + 1 ))
6
下麵要實現投骰子這一功能。這個函式中你可以宣告一個區域性變數來儲存生成的隨機值:
rolldie()
{
local result=$1
rolled=$(( ( $RANDOM % 6 ) + 1 ))
eval $result=$rolled
}
使用 eval
確保生成的隨機數被實際儲存在變數中。這一部分也很容易:
rolldie die1
這會為第一個骰子生成一個 1
– 6
之間的隨機值儲存到 die1
中。要擲 3 個骰子,很簡單:
rolldie die1 ; rolldie die2 ; rolldie die3
現在判斷下生成的值。首先,判斷是不是 Bunco(3 個骰子值相同),然後是不是和當前輪數值也相同:
if [ $die1 -eq $die2 ] && [ $die2 -eq $die3 ] ; then
if [ $die1 -eq $round ] ; then
echo "BUNCO!"
score=25
else
echo "Mini Bunco!"
score=5
fi
這可能是所有判斷陳述句中最難的部分了,註意第一個條件陳述句中這種不常用的寫法 : [ cond1 ] && [ cond2 ]
。如果你想寫成 cond1 -a cond2
,這樣也可以。在 shell 程式設計中,解決問題的方法往往不止一種。
程式碼剩下的部分很直白,你只需要判斷每個骰子的值是不是和本輪數字相同:
if [ $die1 -eq $round ] ; then
score=1
fi
if [ $die2 -eq $round ] ; then
score=$(( $score + 1 ))
fi
if [ $die3 -eq $round ] ; then
score=$(( $score + 1 ))
fi
唯一要註意的是當出現 Bunco/Mini Bunco 就不需要再統計本輪分數了。所以整個第二部分的判斷陳述句都要寫在第一個條件陳述句的 else
中(為了判斷 3 個骰子值是否都相同)。
把所有的綜合起來,然後在命令列中輸入輪數,下麵是現在的指令碼執行後的結果:
$ sh bunco.sh 5
You rolled: 1 1 5
score = 1
$ sh bunco.sh 2
You rolled: 6 4 3
score = 0
$ sh bunco.sh 1
You rolled: 1 1 1
BUNCO!
score = 25
竟然這麼快就出現 Bunco 了? 好吧,就像我說的,shell 內建的隨機數發生器在隨機數產生這方面可能有些問題。
你可以再寫個指令碼測試一下,去執行上述指令碼幾百次,然後看看 Bunco/Mini Bunco 出現次數所佔的百分比。但是我想把這部分作為練習,留給親愛的讀者你們。不過,也許我下次會抽時間完成剩下的部分。
讓我們完成這一指令碼吧,還有分數統計和一次性執行 6 次投骰子(這次不用再在命令列中手動輸入當前輪數了)這兩個功能。這也很容易,因為只是將上面的內容整個巢狀在裡面,換句話說,就是將一個複雜的條件巢狀結構全部寫在了一個函式中:
BuncoRound()
{
# roll, display, and score a round of bunco!
# round is specified when invoked, score added to totalscore
local score=0 ; local round=$1 ; local hidescore=0
rolldie die1 ; rolldie die2 ; rolldie die3
echo Round $round. You rolled: $die1 $die2 $die3
if [ $die1 -eq $die2 ] && [ $die2 -eq $die3 ] ; then
if [ $die1 -eq $round ] ; then
echo " BUNCO!"
score=25
hidescore=1
else
echo " Mini Bunco!"
score=5
hidescore=1
fi
else
if [ $die1 -eq $round ] ; then
score=1
fi
if [ $die2 -eq $round ] ; then
score=$(( $score + 1 ))
fi
if [ $die3 -eq $round ] ; then
score=$(( $score + 1 ))
fi
fi
if [ $hidescore -eq 0 ] ; then
echo " score this round: $score"
fi
totalscore=$(( $totalscore + $score ))
}
我承認,我忍不住自己做了一點改進,包括判斷當前是 Bunco、Mini Bunco 還是其他需要計算分數的情況這一部分 (這就是 $hidescore
這一變數的作用)。
實現這個簡直是小菜一碟,只要一個迴圈就好了:
for round in {1..6} ; do
BuncoRound $round
done
這就是現在所寫的整個程式。讓我們執行一下看看結果:
$ sh bunco.sh 1
Round 1\. You rolled: 2 3 3
score this round: 0
Round 2\. You rolled: 2 6 6
score this round: 1
Round 3\. You rolled: 1 2 4
score this round: 0
Round 4\. You rolled: 2 1 4
score this round: 1
Round 5\. You rolled: 5 5 6
score this round: 2
Round 6\. You rolled: 2 1 3
score this round: 0
Game over. Your total score was 4
嗯。並不是很令人滿意,可能是因為它只是遊戲的一次完整執行。不過,你可以將指令碼執行幾百幾千次,記下“Game over”出現的位置,然後用一些快速分析工具來看看你在每 6 輪中有幾次得分超過 3 分。(要讓 3 個骰子值相同,這個機率大概在 50% 左右)。
無論怎麼說,這都不是一個複雜的遊戲,但是它是一個很有意思的小程式專案。現在,如果有一個 20 面的骰子,每一輪遊戲有好幾十輪,每輪都擲同一個骰子,情況又會發生什麼變化呢?
via: http://www.linuxjournal.com/content/shell-scripting-bunco-game
作者:Dave Taylor[2] 譯者:wenwensnow 校對:wxy
本文由 LCTT 原創編譯,Linux中國 榮譽推出