UNO是一種趣味性比較強的游戲, 它基于顏色和數(shù)字不斷輪流出牌, 并含有各種功能牌(大部分帶有懲罰性質), 最終出完或者剩余牌計分最低的贏得比賽.
類型簡介
-
普通牌有紅, 黃, 藍, 綠四種顏色, 每種顏色有
- 0號牌1張;
- 1-9號牌2張.
共計76張.
-
功能牌也有紅, 黃, 藍, 綠四種顏色, 每種顏色有:
- 阻擋牌(skip)2張;
- 反轉牌(reverse)2張;
- 罰兩張(draw two)2張.
共計24張.
-
萬能牌可以變色, 但分兩種:
- 變色牌(wild)4張;
- 王牌(wild four)4張.
共計8張.
數(shù)據(jù)表示
我們對于任意牌可用一對數(shù)據(jù)(也即pair
類型)來表示:
顏色: 可用枚舉類型
red, yellow, blue, green, blank
表示, 注意變色牌blank
可適用于任意顏色.-
面值: 普通牌直接面值就是數(shù)字, 后續(xù)的數(shù)字:
- 10表示阻擋牌;
- 11表示反轉牌;
- 12表示罰兩張;
- 13表示變色牌;
- 14表示王牌.
瘋狂游戲
考慮如下的自動游戲模擬, 初始有n位玩家, 每人從混洗之后的牌中分別取出7張牌, 并指定正向為初始游戲方向.
對于當前顏色為C面值為K情況, 下一可以出牌的玩家采用這樣的策略:
- 如果當前有K面值(1-12均可)的牌, 按照該玩家取牌的先后次序出一張K面值的牌;
- 如果當前沒有K面值的牌, 則從C顏色中按照該玩家取牌的先后次序出一張牌(出完功能牌才能出功能牌).
- 如果顏色和面值都不符合則出萬能牌;
- 無牌可出則從牌堆中取出牌.
如果牌堆無牌或一位玩家所有牌出完則結束. 每人手里剩下的牌進行記分, 普通牌按面值計分, 功能牌計20分, 萬能牌計50分.
洗牌與發(fā)牌
108張牌每次需要進行洗牌, 《面向算法設計的數(shù)據(jù)結構(C++語言版)》中給出了shuffle
程序可對此進行隨機洗牌. 這些牌可以存于一個長為108的數(shù)組Cards
里.
發(fā)牌其實是用棧來實現(xiàn)的, 這里可以用數(shù)組Cards
的當前下標作為棧頂.
隊列
每位玩家對各個面值維護一個隊列, 不過牌還得按照顏色另外存儲一個隊列. 由于兩個隊列的數(shù)據(jù)不能同步, 我們可以為每張牌加入標記來表示該牌是否已經打出(于是需要修改牌的數(shù)據(jù)表示讓它能包含這個新的數(shù)據(jù)域), 如果在隊列中取到一張已經打出的牌則丟棄后繼續(xù)從隊列取新元素. 而這個只用常數(shù)時間, 并不影響整體的模擬程序性能. 另外, 洗牌之后必須將這些標記重置.
實際上這里的面值隊列是隊列數(shù)組QK
, 前面面值為數(shù)字的設計可以更為方便快速得到面值為i
的隊列QK[i]
之中的數(shù)據(jù).
計數(shù)和計分
每個人維護一個計數(shù)器, 記錄手里的牌數(shù). 如果計數(shù)器為0則游戲結束. 注意這個計數(shù)器要和前面牌的標記關聯(lián)起來, 只有真正打出牌的時候才能減1.
計分的時候普通牌可以直接記分, 其他牌略作判斷即可. 注意這里不需要另起一個計分映射數(shù)組, 因為計分策略相對來說比較簡單, 只有三種分數(shù)策略而已.
不過, 計分方法會影響出牌策略. 顯然, 我們要盡可能出掉面值較高的普通牌. 另外, 我們可以根據(jù)當前情況出一張對方難以接招的牌. 當然, 這些策略都可以作為提高性問題來思考.
游戲方向
玩家的編號從0到n - 1, 正向是加1反向是減1, 我們可以不去取模, 改用判斷會更快一點. 例如在加1時可以先加1如果編號變成n則令其為0即可.
Just Play!
基本思路已經設計完畢, 那就編寫程序實現(xiàn)吧!