題目: 寫個可以讓User與電腦對玩BATNUM的程式 (比NIM簡單)
Due: 即日起七天內 (其實看完題目大約半小時就可做完:)
Purpose:
也是練習使用亂數,與了解策略遊戲(Strategy game)
(1)透過這個練習,你將更了解程式庫 rand( ) 和 srand( ) 的用途與用法,
以及更熟悉 PRNG (Pseudo Random Number Generator)與程式庫 time(0) 用途;
(2)了解策略遊戲(Strategy game)與如何在可以贏的時候做出贏的策略!
(3)這BATNUM 只要用到取餘數 %, 比 NIM 遊戲用 xor 運算的應用簡單。
Description:
類似NIM, BATNUM (BATtle of NUMbers) 也是兩人對玩的策略遊戲!(比NIM簡單)
但是只有一堆石頭,兩個玩家輪流抓,可以規定抓最後一個的贏或是輸。
規則是至少要抓一個,最多則可事先隨便規定(可由電腦亂數產生)。
棋類遊戲需要往前想很多步(建立遊戲樹),
NIM 與 BATNUM 這類的策略遊戲則只要"掐指一算"做出決策,
許多這種策略遊戲是不公平的遊戲,因為一開始輸贏就已經定案!
請自己用 google.com 查詢 BATNUM 相關資料(以及 NIM 資料 :-)
玩法(Game Rules)是:
一開始有一堆石頭,不一定幾個石頭,
然後由兩人輪流拿,每次至少要抓一個,
至多則可事先隨便規定(可由電腦亂數產生)。
可規定拿到最後一個的贏,
也可規定拿到最後一個的輸。
贏家策略(Strategy to win):
這個遊戲有個很簡單的贏家策略(拿最後的贏或輸都類似):
假設石頭總數是 n, 最多可以拿 tMax 個, 最少當然是拿一個;
Let k = n;
if(拿最後一個是輸) k = k -1;
k = k % (1 + tMax);
if(k == 0) k = 1; // 輸定了, 先拿一個拖延時間
阿就是拿走 k 個!
(注意若拿最後一個是輸要先把總數減去一再做 % 運算)
Hints:關於個檔案簡易說明請看 00BATNUM.htm
(1)可以玩玩我寫好的執行檔 batnumTC.exe
該檔案是用 Turbo C++產生的, 原始檔是 batnumTC.c 或 batnumTC.txt
另外 bat6ok.exe 也是可以與電腦對玩的執行檔案。
(2)已經會寫就自己從 0 開始寫, 不然就先看看 bat00.htm
看完就拿 bat0.c 當作初稿開始寫,
仍不知道怎沒寫? 那改拿 bat2.c 去改吧。
不過若規定拿到最後一個的是輸, 只要注意最後一步略作調整!!
(3)再不然, 看看 bat3.c 這接近完成版,
但是這時電腦是隨便拿, 也沒防呆機制。
(4)至於 bat5.c 仍沒有防呆, 但電腦會想辦法贏!
(5)如同往常,只要看不懂的都要舉手抓助教來問, 一定要想辦法弄懂!
若助教也不會請記下他/她姓名偷偷告訴我, 扣薪水:-(
(6)也可以測試這網路版的(Java) batnum.zip
java -jar batnum.zip
然後其他人只要用 telnet 工具連入該機器的 port 3388 就可玩!
自己則開另一窗 telnet 127.0.0.1 3388 就可玩!
(7) bat6ok.c 是參考解答, 請先不要偷看:-)
進階練習:
==> 學 Java 的可用 Java 寫出網路版。
(註: 我給的 betNet.zip 只有 Java class 執行檔)
//BATNUM -- BATtle of NUMbers 數字大戰
int nStone, maxTake; // 總石頭數, 最多可拿幾個?
boolean lastToWin = true; // 拿最後一個贏還是輸?
int main( ) {
//BATtle of NUMbers
hello( ); // welcome message
playAgain = true;
while(playAgain) {
prepareGame( );
userFirst = askUserFirst( );
playGame( );
playAgain = askPlayAgain( );
}
print("Bye bye\n"); return 0;
} // main
======================
void hello( ) {
// welcome message and/or game rules
}
void prepareGame( ) {
// 用亂數 生出 遊戲所需的各個 Global variables
//nStone = 用亂數取得 15 .. 31;
//maxTake = 用亂數取得 3..7 ;
//用亂數決定 lastToWin 是 true 還是 false
}
boolean askUserFirst( ) {
// 若 USER 要先拿, 就傳回 1
return (38==38); // YES / TRUE
}
boolean askPlayAgain( ) {
// 問user 並讀入答案, 若 USER 要繼續玩, 就傳回 true
return false; // NO / FALSE 表示不完了 :-)
}
void userTurn( ) {
// nTake = 問 USER 要拿幾個;
// 檢查 nTake 是否合乎規定? 若不符合則要求 user 重新輸入
// 然後當然要從 nStone 減去 nTake
}
void computerTurn( ) {
// 先寫隨便拿但要合乎規定, 就是取 1..min(maxTake, nStone) 的亂數
// 再想出可贏就會贏的策略 (很簡單 :-)
// Hint: 拿 max(1, (nStone - xxx) % (1+maxTake) ) 就會贏
// 其中 xxx 是 0 if lastToWin is true
/// xxx 是 1 if lastToWin == false
}
void playGame( ) {
// user and the computer take Turn until no more stones left
// if(userFirst) userTurn( );
// Loop until no more stone
// computerTurn( );
// if no more stone then leave the Loop;
// userTurn( );
// end Loop
// Judge the game result and print some message..
// 如何判斷誰輸誰贏? 須知道誰拿走最後一個!
// 注意拿最後一個是輸還是贏?
// (lastToWin == true 表示拿到最後一個的贏 )
} // playGame
|