トランプゲームである大富豪のプログラムを書きましょう。
トランプのカードは、4種類のスート(スペード、ハート、ダイヤ、クラブ)と13のランク(A, 2, 3, 4, 5, 6, 7, 8, 9, J, Q, K) の組み合わせです。またジョーカーもカードです。ひと組のトランプは、全53枚(4スート13ランク+ジョーカー1枚)のカードです。
1枚のカードを表現してください。クラス、オブジェクトなど、使用する言語でのユーザー定義型を作ってください。その表現をもとに、以下のような機能を実装してください。
- 文字列表現ができる(人が見て分かるよう、コンソールなどに表示できる)
- 2枚のトランプを比べて、同じスートか調べられる
- 2枚のトランプを比べて、同じランクか調べられる
大富豪では、前のプレイヤーよりも強い手を出さないといけません。カードの強弱判定を実装してください。まずは、カード1枚だけの手を考えます。
大富豪では3が一番弱く、4, 5, ... 10, J, Q, K, A と強くなり、2が一番強くなります。ただしジョーカーは他のどのカードよりも強いです。
- 2枚のカードを比べて、どちらが強いか判定する
大富豪では同時に2枚以上の手を作って出すことができます。このような手も比較できるよう、手の強弱の判定を実装してください。ここでは以下のルールとします。
- 異なるスートで同じランクのカード、2枚以上
- 同じスートで連続するランクのカード、3枚以上
- ジョーカーを任意のカードとして使える(このときはジョーカーの強さはそのカードと同じになる)
先の問題ではカードをクラスやオブジェクトで表現しました。こんどは、カードをできるだけプリミティブな方法で表現してください。整数、浮動小数点数、配列、文字列、シンボルなど、使用する言語に合わせて工夫してください。
そのうえで、複数枚の手を比較できる機能を実現してください。
大富豪は以下のようにゲームを進めます。(最初に手札を配ったり、手札がなくなって上がったりする部分は省略しています。)
- 親が最初の手を場に出す
- 次のプレイヤーが、場にある手より強い手を出すか、パスする
- 各プレイヤーが順番に手を出すかパスしていく
- 他のプレイヤー全員がパスし、再び場にあるカードを出したプレイヤーまで順番が回ってきたらそのプレイヤーは親になる
- 新しい親が、1から始める
この流れをプログラムで実装してください。
各プレイヤーがどの手を出すか(あるいはパスするか)は、外部から指定できるようにしてください。外部からの指定は、コンソールから入力する、指定するメソッド(API)を提供する、別のプログラムを呼び出す、Web APIで操作するなど、いろいろな考え方ができます。好きな方法を選んでください。
判断が難しければ、APIを提供するようにするのをおすすめします。たとえば、以下のようなテストを書き、テストから呼び出しているメソッドをAPIとして実装していくという進め方ができます。
dfg_test.py:
def test_ゲームを進める():
game = DaiFuGoGame()
player1 = Player()
player2 = Player()
player3 = Player()
game.add_player(plyer1)
game.add_player(plyer2)
game.add_player(plyer3)
# 親が手を出す
assert game.oya == player1
assert player1.tefuda == ['S3', 'D5', 'HK', 'CA']
player1.play(['D5'])
assert game.ba == ['D5']
# 次のプレイヤーが手を出す
assert game.current_player == player2
player2.play(['H8'])
assert game.ba == ['H8']
# 続く
ただしこのサンプルはあくまで一例です。ゲームやプレイヤーやカードを表す方法はたくさん考えられるので、各ペアで相談しながら、できるだけ「小さなステップ」で進めながら、プログラムの構造を成長させてください。
大富豪にはたくさんの特殊な扱いの手や、ローカルルールがあります。そうした機能を実現してみましょう。
同じランクのカード4枚の手を出すと、革命が起こり、カードの強弱が逆転します。
- 手が革命を起こす手かどうか判定する
- 革命が起きたときの強弱の判定を実装する
上がりの手として禁止されているものがいくつかあります。手が禁止上がりの手かどうか判定してください。
- 一番強いランク(2)上がりは禁止
- ジョーカー上がりは禁止
- 一番弱いランク(3)上がりは禁止
- 複数枚の手で、上記を含む手は禁止