文章作者 : darker2020
●
預備知識 :
1. 標準輸入輸出 : std::cin、 std::cout的用法。
2. 迴圈敘述、條件判斷、流程控制敘述的用法。
3. break和continue敘述句的使用。
4. 使用者自訂函數 (user-defined function)
推薦資源 : 台大李博士的教學影片,看完1~12章後就差不多能看懂這篇文章了。但還要學習列舉型別的用法。
5. 如何使用列舉(enumeration)。(也可以使用陣列,但我比較喜歡列舉...)
也可以使用陣列代替列舉,但陣列的話要學的東西會比前面1~4還要多,我這篇文章的讀者取向並不是有經驗的人,畢竟他們也不會想看我的文章吧QQ
6. 知道猜拳遊戲(rock paper scissors)的基本遊戲規則。不討論一些特別的玩法。
Q.需要使用哪些變數來儲存我們需要的資訊 ?
<enum>//建立在main外
objectType {rock, paper, scissors};
<int>//建立在main內
gameCount : 儲存總共(total)進行的遊戲回合數量。
winnerCount1 : 儲存1號玩家(player 1)的勝利場數。
winnerCount2 : 儲存2號玩家(player 2)的勝利場數。
gameWinner : 儲存遊戲的勝利者是誰。
<char>//建立在main內
select1 : 玩家1號的選擇。
select2 : 玩家2號的選擇。
<objectType>//建立在main內
player1 : 玩家1號所選擇的enumerator。
player2 : 玩家2號所選擇的enumerator。
Q.需要哪些自訂函數來分割程式 ?
coutRules : 用來顯示出遊戲規則和操作說明等等的訊息。
checkSelection : 檢查玩家的輸入是否是正確的,有效應為r, p 和 s,大小寫沒關係。
getPlayer : 依照玩家的輸入傳回對應的物件類型。(enumeraion type並不能直接讀取)。
afterResult : 輸出玩家的選項和最終是誰獲得了這回合的勝利。
coutObject : 這個函數會被afterResult給呼叫,用來印出玩家的選擇。
winningPlayer : 判斷是哪個物件(兩個玩家選擇所對應的物件類型) 獲得了勝利並回傳勝利的物件。
gameResult : 到遊戲完全結束後,印出最終結果(總場次,每個玩家獲勝的次數)。
一. 每個自訂函數的原型(function prototypes)
void coutRules();//自行決定要不要有,或打在main函數內
bool checkSelection(char userSelect);
objectType getPlayer(char userSelect);
void afterResult(objectType play1, objectType play2, int &win);
void coutObject(objectType userObject);
obejectType winningPlayer(objectType play1, objectType play2);
void gameResult(int gameCount, int winnerCount1, int winnerCount2);
//自行決定要不要有,或打在main函數內
二. checkSelection函數的內容
如果選項是 R、r、P、p、S、s則是正確的選擇。否則,選擇是無效的。
使用switch語句來檢查。
bool checkSelection(char userSelect)
{
switch(userSelect)
{
case 'R':
case 'r':
case 'P':
case 'p':
case 'S':
case 's':
return true;
default:
return false;
}
}
三. getPlayer函數的內容
因為列舉型別無法直接讀取,所以這個函數會把選擇(R、r、P、p、S、s)依照對應的物件傳回。
若不想使用switch語句,也可以使用if的語句來代替。
objectType getPlayer(char userSelcet)
{
objectType mora; //mora是猜拳的英文。
switch(userSelect)
{
case 'R':
case 'r' :
mora = rock;
break;
case 'P':
case 'p':
mora = paper;
break;
case 'S':
case 's':
mora = scissors;
break;
}
return mora;
}
四. afterResult函數的內容
這個函數主要負責判斷是平手還是有誰勝出。輸出玩家的選擇和這一回合的勝利者。
void afterResult(objectType play1, objectType play2, int &win)
{
objectType winObject;
if(play1 == play2){
win = 0;
cout << "由於兩個玩家的選擇相同,";
cout << " 這場遊戲平手。" << endl;
}
else{
winObject = winningPlayer(play1, play2);
cout << "玩家1 選擇 ";
coutObject(play1);
cout << " 然後 玩家2 選擇 ";
coutObject(play2);
cout << "。 ";
if(play1 == winObject{
win = 1;
}
else if(play2 == winObject){
win = 2;
}
cout << "玩家 " << win << " 獲得了這回合遊戲的勝利。 " << endl;
}
}
五. coutObject函數的內容
因為列舉型別沒辦法被直接印出來,所以要寫一個函數來額外印出。
一樣,所有的switch語句都可以改寫為if語句,但判斷條件多的話還是用switch比較好。
void coutObject(objectType userObject)
{
switch(userObject)
{
case Rock:
cout << "石頭";
break;
case Paper:
cout << "布";
break;
case Scissors:
cout << "剪刀";
break;
}
}
六. winningPlayer函數的內容
決定誰是遊戲的勝利者。
obejectType winningPlayer(objectType play1, objectType play2)
{
if ((play1 == Rock && play2 == Scissors)
|| (play2 == Rock && play1 == Scissors))
return Rock;
else if((play1 == Rock && play2 == Paper)
||(play2 == Rock && play1 == Paper))
return Paper;
else
return Scissors;
}
七.main函數的內容
我就不把主程式的程式碼貼出來了,這部分可以自己決定甚至修改。
當然,所有函數也可以改寫在主程式內,只是會變成很長。我不是很喜歡這種風格。
1. 首先 gameCount、winnerCount1、winnerCount2 請記得初始化為0,才能開始計算。
2. 因為遊戲場次不會只有一場,所以記得用while(true)來一直不斷循環,可以讓使用者在遊戲結束後輸入某個按鍵來break出循環區塊。
3. 記得使用 checkSelection 函數來判斷使用者輸入的數值到底是不是有效的,如果不是,則讓使用者重新輸入一次。
4. 把getPlayer函數的物件回傳給player1、player2。
5. afterResult判斷遊戲的勝利者是誰,記得讓gameCount、和勝利者的Count次數+1。
6. 若使用者不想再繼續的話則跳出while,然後印出步驟一的三個統計值告訴玩家資訊。
到這裡就結束了,希望對你有幫助。
如果沒有的話,真的很對不起浪費了你的時間QQ
**補充
1. 我們可以有一點同理心,想想,如果玩家是個邊緣人,這種雙人遊戲難道對他不是太殘忍了嗎?所以我們應該要有個功能給單人玩家,讓他可以跟電腦對戰。
最簡單的方法就是使用亂數,可以自己去想想看。絕對不是我懶得打了。
2. 一般的cmder介面很醜,大概不會有人想玩,所以可以學著寫寫看一個GUI介面,做成一個真正可用的軟體。
SFML自己去看吧,我也是菜雞,抱歉。
3. 如果你在黑框介面或程式編輯器中使用繁體中文會變成亂碼的話該怎麼辦。
請把你的編輯器編碼調成utf8,終端機的也要,但請不要用chcp 65001......你終端機關閉他下次就恢復了,請去登錄編輯程式那裡改。
4. 一直玩下去,終端機都是滿滿的文字看了很不舒服怎麼辦 ?
請使用 system("cls"); system("pause"); 這兩個方法,自己試試看。