七並べゲームにはいくつかのローカルルールが存在します。人と七並べをしていて「えっ、そんなルールがあったの?!」と驚かされることもあります。こういうルールはやる前に確認しておきましょう。
AとKは隣り合っているとみなす。スペードの7からKまでが場に出ている時にはスペードのAを出すことが許されるというルールもあります。また7からAまでが出ている時にはスペードのKを場に出すことが許される。
スペードの7からKまでが場に出されたことでスペードのAを出すことが許されるようになった場合、これまで同様、6,5,4というカードの出し方が許されるかどうかという問題があります。
許されるかどうかはローカルルールによって異なります。許すというルールの方が一般的ですが、許さないルールもあります。いわゆる「トンネルルール」です。
今回はトンネルルールを適用します。
どうすればよいのか?
出せるカードを取得するGetCanTakeoutメソッドを作成しましたが、AやKがすでに出されている場合は、これを一部変更すれば使えそうです。ではさっそくやってみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { List<Card> GetCanTakeout() { List<Card> retCards = new List<Card>(); // それぞれのマークについて調べる retCards.AddRange(GetCanTakeout(CardMark.spade)); retCards.AddRange(GetCanTakeout(CardMark.hart)); retCards.AddRange(GetCanTakeout(CardMark.dia)); retCards.AddRange(GetCanTakeout(CardMark.club)); return retCards; } } |
処理が若干ややこしくなりそうなので、それぞれのマークについて調べることにしました。
以下はマークを指定して、それぞれについて出すことができるカードを調べるメソッドです。
変更しないといけないときはAとKがすでに置かれているときです。両方とも置かれていない場合は従来の方法で取得します。Aのみが置かれているときはKしかおけません。逆にKしか置かれていないときはAしかおけません。
もしAとKの両方が置かれている場合は、テーブルに置かれていないカードを取得して、その最大値と最小値でつぎに出すことができるカードを調べます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
public partial class Form1 : Form { List<Card> GetCanTakeout(CardMark mark) { List<Card> retCards = new List<Card>(); List<Card> tableCards = cards.Where(x => x.Mark == mark && x.isExists).ToList(); int max = tableCards.Max(x => x.Number); int min = tableCards.Min(x => x.Number); if(min != 1 && max != 13) { retCards.Add(GetCard(mark, max + 1)); retCards.Add(GetCard(mark, min - 1)); } else if(min == 1 && max == 13) { List<Card> nonCards = cards.Where(x => x.Mark == mark && !x.isExists).ToList(); if(nonCards.Count == 0) return retCards; if(nonCards.Max(x=> x.Number) < 7) retCards.Add(GetCard(mark, nonCards.Min(x => x.Number))); else retCards.Add(GetCard(mark, nonCards.Max(x => x.Number))); } else if(max == 13) { retCards.Add(GetCard(mark, 1)); } else if(min == 1) { retCards.Add(GetCard(mark, 13)); } return retCards; } } |
あとは変更する部分は特にありませんが、残りの枚数を表示するようにしました。
まずステータスバーに残り枚数を表示させるToolStripStatusLabelを作成します。外観とToolStripStatusLabelの名前は以下のとおりです。
<デザイナ>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public partial class Form1 : Form { // 残りのカードの枚数を表示させる void ShowPlayerInfo(int player) { int cardCount = playersCards[player].Count; string str = String.Format("カード残り{0}枚", cardCount); if(player == 0) StatusLabelPlayerinfo0.Text = str; if(player == 1) StatusLabelPlayerinfo1.Text = str; if(player == 2) StatusLabelPlayerinfo2.Text = str; if(player == 3) StatusLabelPlayerinfo3.Text = str; } } |
残りの枚数を表示させるタイミングはカードの残数が変わったときです。
まずゲーム開始時にカードの残数が決まります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public partial class Form1 : Form { void GameStart() { ranking = 1; isAgari = false; // ゲームスタート前の段階なのでだれもカードは持っていない。 // 全プレイヤーのカードをリセットする playersCards[0].Clear(); playersCards[1].Clear(); playersCards[2].Clear(); playersCards[3].Clear(); foreach(Card card in cards) card.isExists = false; Invalidate(); // テーブル上のカードをクリア // カードを配って7があれば出す HandoutCards(); Takeout7(); // ゲーム開始時における各プレイヤーのカードの枚数が確定した // この4行を追加(ゲーム開始時の残りカードを表示させる) ShowPlayerInfo(0); ShowPlayerInfo(1); ShowPlayerInfo(2); ShowPlayerInfo(3); // まずは自分の手番でゲームスタート IsMyTurn = true; // 以降は変更なし } } |
自分と他のライバルがカードを出したときに残数が変化するので表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
public partial class Form1 : Form { private void Form1_MouseClick(object sender, MouseEventArgs e) { if(!IsMyTurn) return; // クリックされたカードを出す処理(省略) // カードを出し終わったら残りの枚数を表示する ShowPlayerInfo(0); if(!IsMyTurn) { OnRivalsTurn(); } } void RivalTurn(int rivalID) { // ライバルがカードを出す処理(省略) // カードを出し終わったら残りの枚数を表示する ShowPlayerInfo(rivalID); } } |
adminさん、お疲れ様です。
GetCanTakeoutメソッドの引数ない物と、引数が有るメソッドはメソッド名こそ同一ですが、それぞれ別の物で作成しているという、認識であっていますでしょうか?
はい。C#では同じメソッド名で引数が異なるものをつくることができます。
GetCanTakeout()は出せるカードを求めるメソッドですが、一度にやってしまうのは難しいので、最初に引数ありの同名のメソッドでそれぞれのスート(トランプに使われるマークのこと。スペードとかハートとか)で出せるカードを調べて、その結果をまとめて取得しています。
承知いたしました。
ありがとうございます!!