Contents
「ドボン」で一発逆転
ドボンには「「ドボン」と宣言してカードを全部いっきに出してあがることができる」というルールがあります。
ドボンできるのは自分の持っている手札の数字の合計が台札の数字とおなじときです。このとき手札のカードのスート(マーク)は関係ありません。
そこで今回はドボンできるようにします。これもPlayerクラスでやってしまいましょう。
ドボンできるかどうかを調べる
CanDobonはドボンできるかどうかを調べるメソッドです。
1 2 3 4 5 6 7 8 9 10 |
public class Player { public bool CanDobon(Card card) { if(Cards.Sum(x => x.Number) == card.Number) return true; else return false; } } |
あとはライバルのターンでドボンできるかどうかチェックしてできる場合はドボンします。
ドボンしたらゲームは終了
誰かがあがったりドボンしたらゲームは終了です(ただし暫定的処理)。
ゲームが終了したにもかかわらずカードが出せてしまってはおかしいです。そこで戻り値で区別しています。
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 |
public partial class Form1 : Form { bool RivalsTurn() { // 0 は自分なのでライバルではない List<Player> rivals = Players.Skip(1).ToList(); foreach(var player in rivals) { System.Threading.Thread.Sleep(500); CenterCard = player.PutCard(CenterCard, ShuffledCards); panelCenter.Invalidate(); if(player.Cards.Count == 0) { MessageBox.Show(player.Name + "が あがりました"); return false; } List<Player> dobons = Players.Where(x => x != player && x.CanDobon(CenterCard)).ToList(); foreach(var dobon in dobons) { MessageBox.Show(dobon.Name + "が ドボンしました"); return false; } } if(!AddCardIfCanNotPutCard()) return true; else return RivalsTurn(); } } |
自分が出したカードはドボンされるのか?
自分が出したカードもドボンされる可能性があるのでチェックする必要があります。
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 39 40 41 42 43 44 45 46 47 |
public partial class Form1 : Form { private void panelSouth_MouseDown(object sender, MouseEventArgs e) { Card card = GetClickedCard(e); if(!IsMyTurn) { MessageBox.Show("まだあなたの番ではありません"); return; } if(card == null) { panelSouth.Invalidate(); MessageBox.Show("カードがある位置をクリックしてください"); return; } if(CenterCard.Suit == card.Suit || CenterCard.Number == card.Number) { Players[0].Cards.Remove(card); CenterCard = card; panelCenter.Invalidate(); panelSouth.Invalidate(); // ドボンされる可能性があるのでチェックする List<Player> dobons = Players.Where(x => x != player && x.CanDobon(CenterCard)).ToList(); foreach(var dobon in dobons) { MessageBox.Show(dobon.Name + "が ドボンしました"); return; } if(Players[0].Cards.Count == 0) { MessageBox.Show("あなたはあがりました"); return; } RivalsTurn(); } else { MessageBox.Show("このカードは出せません"); } } } |
ドボン返し
ドボン – Wikipediaをみるとドボンには「ドボン返し」というものがあることがわかります。
ドボンによる上がりは最終的に勝利者を確定するものではない。ドボンされたプレイヤーの残った複数の手札の合計が、ドボンされたのと同じ数だった場合、ドボンを「返す」ことができる。これをドボン返しと呼びます。
ドボンがありそうな場面で、例えば手札に「2」と「6」と「8」を持っている場合、最初から「2」と「6」でドボンを返すつもりで「8」を場に出してドボンを誘う作戦をとることもできます。
ドボン返しができる場合とは
ドボン返しができるのは「ドボンされたのと同じ数だった場合」、「ドボンして出した一番上のカード」と異なるローカルルールがありますが、ここでは「ドボンされたプレイヤー」が「ドボンされたのと同じ数だった場合」にします。(プログラムの作成を容易にするため)
上記のプログラムではドボンできるときは自動的に処理をしていましたが、ドボン返しがある場合は本当にドボンできるかどうか考えないといけません。カードの番号が大きくなるとドボンやドボン返しのリスクが大きくなるのですが、ここはいつものように乱数で適当に決めます。
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 |
public partial class Form1 : Form { bool RivalsTurn() { List<Player> rivals = Players.Skip(1).ToList(); foreach(var player in rivals) { bool isFinish = false; System.Threading.Thread.Sleep(500); CenterCard = player.PutCard(CenterCard, ShuffledCards); panelCenter.Invalidate(); if(player.Cards.Count == 0) { isFinish = true; MessageBox.Show(player.Name + "が あがりました"); // あがったときもドボンされる可能性がある } // 出されたカードに他のプレイヤーはドボンできるか? // ドボンまたはドボン返し成立の場合はゲーム終了 if(DobonIfCan(player)) return false; // あがった人に誰もドボンしなかったらゲーム終了 if(isFinish) return false; } } if(!AddCardIfCanNotPutCard()) return true; else return RivalsTurn(); } } |
もしドボンできるのであればドボンするかどうか判断してドボンを決行します。
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 39 |
public partial class Form1 : Form { bool DobonIfCan(Player player) { List<Player> dobons = Players.Where(x => x != player && x.CanDobon(CenterCard)).ToList(); int dobonNumber = CenterCard.Number; foreach(var dobon in dobons) { if(dobon == Players[0]) { DialogResult dr = MessageBox.Show("ドボンできます。ドボンしますか?", "", MessageBoxButtons.YesNo); if(dr == DialogResult.Yes) { // ドボン返しはあるのか? OnDobon(dobonNumber, Players[0], player); return true; } continue; } else { // ドボンできるがしない確率は3分の1 int a = random.Next(3); if(a != 0) { MessageBox.Show(dobon.Name + "が ドボンしました"); // ドボン返しはあるのか? OnDobon(dobonNumber, dobon, player); return true; } else continue; // ドボンは見送る } } return false; } } |
OnDobonメソッドはドボンしたときにドボン返しがあるかどうか判定して結果を返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form1 : Form { void OnDobon(int dobonNumber, Player dobon, Player doboned) { if(doboned.Cards.Sum(x => x.Number) == dobonNumber) { doboned.AntiDobon(dobon); MessageBox.Show("ドボン返しで" + doboned.Name + " の勝ち、\n" + dobon.Name + " の負けです"); } else { dobon.Dobon(doboned); MessageBox.Show(dobon.Name + " の勝ち、" + doboned.Name + " の負けです"); } } } |
ドボンしたらドボンされた人のカードを引き取らなければならず、ドボン返しの場合はドボンした人がドボン返しした人のカードを引き取らなければなりません。そこで手持ちのカードの表示を変える必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Player { public void Dobon(Player doboned) { doboned.Cards.AddRange(Cards); doboned.PlayerPanel.Invalidate(); Cards.Clear(); PlayerPanel.Invalidate(); } public void AntiDobon(Player antiDoboned) { antiDoboned.Cards.AddRange(Cards); antiDoboned.PlayerPanel.Invalidate(); Cards.Clear(); PlayerPanel.Invalidate(); } } |