實習目標 |
練習設計規劃物件系統
練習 bottom-up 的物件實作方式 |
---|---|
步驟一 |
接龍這個撲克牌遊戲簡易的說明如下:
這是一個四個人玩的撲克牌遊戲, 一開始每個人發 13 張牌, 規定拿到黑桃七 (Spade 7) 的人要先出黑桃七, 接下來順時鐘方向輪流出牌直到所有牌都出完為止。 |
步驟二 |
由上面的描述中我們可以找到一些必要的物件,
例如:
它們的靜態關係大致如下圖所示: 你喜歡的話, 也可以把手上的牌用一個容器物件把它組合起來, 每個人蓋在桌面的牌也可以用一個容器物件把它組織起來。 |
步驟三 | Card 類別
首先我們挑 Card 類別來實作, 每一張牌有不同的花色 (Spade, Heart, Diamond, Club), 以及不同的點數 (1, 2, 3, ..., 13), 應該要設計資料欄位來存放這兩個屬性。 為了讓程式製作起來比較清楚, 我們選擇用 enum 敘述來定義四種花色 (Spade, Heart, Diamond, Club), 並且定義適當的建構元 它的界面我們暫時先不詳細設計, 慢慢地再加上來 |
步驟四 | CardDeck 類別 接下來我們來定義洗牌和發牌用的牌堆 CardDeck, 很明顯地這個類別需要記錄所有 52 張牌, 在建構元中作出所有的 52 張牌, 需要提供洗牌的服務 shuffle(), 以及發牌的服務 deal()。 由於我們的遊戲一開始就把所有的牌都發完, 所以這個 CardDeck 物件可能發完牌就不需要了。 我們可以替這個類別加上 display(ostream &) 的功能, 如此我們可以用下列程式來測試, 當然在替 CardDeck 類別加上 display() 界面時, 你也會想到該替 Card 類別也加上一個 display(ostream &) 的界面。(請注意我們很早就開始寫測試程式囉!! 你現在對 C++ 的語法還不熟悉, 程式可以寫一點就測試一點, 不要等到通通寫完了再一起測, 一團亂就不好了) void main() { srand(time(0)); CardDeck cardDeck; cout << "Before shuffling\n"; cardDeck.display(cout); cout << endl; cout << "After shuffling\n"; cardDeck.shuffle(); cardDeck.display(cout); }範例程式 測試結果如下: Before shuffling S1 S2 S3 S4 S5 S6 S7 S8 S9 ST SJ SQ SK H1 H2 H3 H4 H5 H6 H7 H8 H9 HT HJ HQ HK D1 D2 D3 D4 D5 D6 D7 D8 D9 DT DJ DQ DK C1 C2 C3 C4 C5 C6 C7 C8 C9 CT CJ CQ CK After shuffling D1 ST D5 C9 CK D9 SQ S5 H4 C6 DK D3 CJ C3 S2 C7 H2 S6 HJ C4 D7 H5 C5 S7 H6 CT S8 H1 S3 DQ DJ H8 HK H7 HT H3 CQ SK H9 D4 D2 S9 C8 DT HQ S4 S1 D8 C2 SJ D6 C1 如此我們知道我們的洗牌應該是成功的, 接下來應該是發牌的動作 deal(Player []), 由於 Player 類別還沒有開始撰寫, 而且 deal() 函式基本上就是一個簡單的迴圈, 所以可以先設計 Player 類別 在設計這個類別的時候你也許會有一個疑問, 平常我們在發牌的時候不是應該由四個人裡頭一個人作為莊家, 由他來洗牌和發牌嗎? 為什麼在這個程式裡我把洗牌發牌設計成 CardDeck 類別的功能呢? 很怪吧! 至少和實際世界裡玩牌的流程好像有一點不太一樣, 那為什麼會有這樣子的設計呢?? 其實會有這樣的設計是從實作面衍生出來的, 如果你讓 CardDeck 物件的主要功能和實際玩牌時一模一樣, 那麼它的功能應該只是一個容器, 最主要就是記錄有哪些牌, 順序是什麼而已, 所有洗牌發牌的動作應該都設計到 Dealer 物件裡面, 這樣子會有兩個我們不喜歡的現象發生:
所以我們才會有像上述這樣的設計, 而且你可以這樣想, 如果在實際玩牌的時候有一個洗牌機可以幫你洗牌, 這樣子不是大家都比較愉快一些, 也比較不怕莊家欺騙, 不是嗎? 這個 CardDeck 就是這樣一個聰明的洗牌機 (有看過麻將的洗牌機吧!!) |
步驟五 | Player 類別的基本功能包括:
void main() { srand(time(0)); CardDeck cardDeck; cardDeck.shuffle(); int i; Player *player[4]; for (i=0; i<4; i++) player[i] = new Player(i); // 參數 i 為 player 的 ID cardDeck.deal(player); for (i=0; i<4; i++) player[i]->display(cout); }範例程式 測試結果如下: Player 0:C1 CQ H5 CK DQ S1 ST SJ H6 DK D1 C4 C3 Player 1:H9 D3 C5 S2 SQ H3 C2 DJ HT S6 S3 HQ H8 Player 2:SK HJ S4 D8 H1 S5 S8 DT D2 D7 HK CT C7 Player 3:C8 H7 CJ S7 S9 H4 D5 D4 C6 H2 D9 D6 C9現在每個 Player 手上都有 13 張牌了, 下一個實習中我們開始來看看該怎樣來出牌了 |
步驟六 | 請將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來儲存在 cyber 上你的帳號內, 後面的實習課程可能需要使用這裡所完成的程式 |
回
C++ 物件導向程式設計課程
首頁
製作日期: 04/27/2004
by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw
TEL: 02 24622192x6615
海洋大學
電機資訊學院
資訊工程系
Lagoon