カードゲームのスピードをつくります。

スピードがどのようなゲームかはYouTubeでも動画がアップされています。ただローカルゲームもあるらしく、ここでは最初にカードを赤と黒に分けるか分けないか、場から台札にカードを重ねたときはそのつど山札からカードを補わなければならないルール(つまり山札にカードがある限り、場のカードは2枚以下になることはない)とそうではないルールが混在します。

下の動画では最初にカードを赤と黒にわけたうえで、場から台札にカードを出すときは場から出せるカードを連続で出してもかまわないと説明されています。

一方、こちらの動画ではカードを赤と黒にわけず、場から台札にカードを出したら山札から必ず出してしまった場のカードを補わなければならないと説明されています。

今回は最初にカードを赤と黒にわける、場から台札にカードを出すときは場から出せるカードを連続で出してもかまわない、ただしコンピュータは場から台札にカードを出したら山札から場のカードを補うことにします。あまりコンピュータに本気を出されると人間に勝ち目がないからです。

Cardクラスをつくる

まずCardクラスをつくりますが、これは素数大富豪で使ったものと同じものを使います。

カードを表示させてゲームらしくする C#で素数大富豪をつくる(6)

ただひとつだけプロパティを追加します。Pointプロパティです。

これでカードを移動させやすくなります。

Form1クラス

ではForm1クラスをみていくことにします。

フィールド変数と初期化

まずフィールド変数を示します。

次にコンストラクタを示します。

ここでやっていることは、ちらつきを抑えるためにダブルバッファを有効にしているのと背景をカードゲームらしく緑色にしていること、タイマー(コンピュータがカードを出すときの処理で必要)のTickイベントに対応するためのイベントハンドラを設定していることです。

ゲームスタートの処理

ゲームスタートの処理を示します。

ゲームセットであるかどうかを表わすIsGameSetフラグをクリアし、新しくカードを生成します。スピードではジョーカーは使いません。

各プレイヤーの場は4つ存在します。これをnullで初期化します。

カードを生成とシャッフル

カードを生成する処理を示します。この処理がおこなわれるときには山札はクリアされているはずなので、赤のカードはコンピュータの山札に、黒のカードはプレイヤーの山札に追加していきます。

カードを生成したらシャッフルします。プレイヤーのカードとコンピュータのカードをそれぞれシャッフルします。

カードを表示させる位置を取得する

カードを表示させるためにはカードを表示させたい位置に移動させなければなりません。各プレイヤーの山札、場、台札はどの座標にあるのか? それを取得するのが以下のメソッドです。

カードがクリックされたとき

カードがクリックされたときにそこにカードがあれば、出せるカードであれば出し、移動できるカードであるなら移動させます。

そのまえにゲームが終了していないか調べる必要があります。すでに決着がついている(コンピュータに敗北している)のにクリックしたカードが出せてしまってはおかしいです。ゲームが終了していないのであれば出すことができる場のカードがクリックされたら台札のうえに重ね、山札がクリックされた場合で場のカードで欠損している部分があればそこにカードを移動させます。

IsPointDeckPlayer1メソッドは引数(クリックされた部分の座標)が山札がある部分なのかどうかを調べるためのものです。

またIsRectangleメソッドは第一引数の座標が第二引数の矩形のなかに存在するかどうかを返します。

カードを出せるか?

CanPutNextCardメソッドはプレイヤーとコンピュータのうち、少なくとも片方がカードを出せるかどうかを調べるためのものです。このメソッドがfalseを返すということはどちらもカードを出すことができないということです。スピードのルールでは「スピード!」のかけ声とともに自分の山札のカード(ない場合は場のカード)を1枚、台札として出します。

CanPutCardメソッドは引数で渡された番号のカードを台札のうえに出せるかを調べます。

双方出すことができるカードがない場合、両者が「スピード!」のかけ声とともに台札のうえにカードを出しますが、CallSpeedメソッドはそのときの処理をしています。

カードを移動させる

PutCardFromDeckIfCanメソッドは山札がある部分がクリックされると場にカードがない部分があればそこにカードを移動させます。山札がある部分ではない部分がクリックされるとなにもおきません。

PutCardFromIntoPlayメソッドは場でカードがある部分がクリックされると、出せるカードであれば台札のうえに出します。

IsPointPutIntoCards1メソッドは引数として渡された座標(クリックされた座標)がプレイヤーの場でカードが置かれている矩形の内部であるか調べ、矩形の内部であるなら何番目のものかを返します(場には4枚カードが存在するので戻り値は0~3)。どの矩形の内部でもない場合は-1を返します。

カードを描画する

DrawDeckCardsメソッドはプレイヤー双方の山札を描画します。

DrawPutIntoPlayCardsメソッドはプレイヤー双方の場に出されているカードを描画します。

DrawLedgerCardsメソッドはプレイヤー双方の台札のカードを描画します。

DrawCardCountメソッドは各プレイヤーの残りのカードを描画します。

IsInTheGameメソッドはゲームが行なわれている最中かどうかを調べます。どちらかのプレイヤーの山札や場にカードが存在する場合はゲーム中であることになります。ただこれでは片方のカードがなくなったとき(勝負がついたとき)もtrueを返します。そこで勝者判定は別におこないます。

GetSizeSpeedTextメソッドは”SPEED!!”と画面中央に表示させるときの背景の矩形のサイズを取得します。

プレイヤーが双方ともにカードを出せない場合、中央に”SPEED!!”の文字を表示させます。

ゲーム終了の判定

どちらか、または両方が同じタイミングでカードを使い切ったとき、勝負の結果を画面中央に表示します。

現状ではコンピュータがカードを出す処理を実装していません。ただクリックすれば自分のカードを出してアガることはできます。