Contents
囲まれているカードは矩形か?
前回はプレイヤーによって出されたカードに隣り合うもののうち、まだテーブルに出されていないカード群を取得する方法を考えました。カード群を取得することができたので、今回はこれが矩形になっているか調べます。
どうやれば矩形になっていると判断することができるのでしょうか? 以下のように考えました。
カード群をマークごとにわけてそれぞれの最大値と最小値を調べます。最大値と最小値が取得できなかった場合を除いて、マークごとの最大値と最小値が一致しなかった場合は囲まれているけど、矩形にはなっていないと判断します。
またこれだけではカード群が矩形であると断定することはできません。たとえばこのようなものは不可です。出されていないカードの最大値と最小値が一致しているだけでは矩形にならない場合があるのです。下の図ではハートの5があるため矩形になっていません。
そこで矩形ができるのではないかと思われるときは、実際につくられる矩形の面積を計算しています。これがカード群の枚数と一致すれば「カードは四角く囲まれている」=「カードの死」と断定することができます。
そのために作成したのがIsDeadThisBlockメソッドです。これは前回のGetNorthTenvironmentCard メソッド、GetSouthTenvironmentCard メソッド、GetEastTenvironmentCard メソッド、GetWestTenvironmentCard メソッドで取得したカード群が矩形になっているかどうかを調べます。
カードが死んでいるか判定するIsDeadThisBlockメソッド
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
public partial class Form1 : Form { bool IsDeadThisBlock(List<Card> cards1) { List<Card> spadeCards = cards1.Where(x => x.Mark == CardMark.spade).ToList(); List<Card> hartCards = cards1.Where(x => x.Mark == CardMark.hart).ToList(); List<Card> diaCards = cards1.Where(x => x.Mark == CardMark.dia).ToList(); List<Card> clubCards = cards1.Where(x => x.Mark == CardMark.club).ToList(); int min = 0, max = 0; int rowCount = 0; bool ret = true; if(spadeCards.Count != 0) { rowCount++; min = spadeCards.Min(x => x.Number); max = spadeCards.Max(x => x.Number); } if(hartCards.Count != 0) { rowCount++; if(min != 0 && min != hartCards.Min(x => x.Number)) return false; else min = hartCards.Min(x => x.Number); if(max != 0 && max != hartCards.Max(x => x.Number)) return false; else max = hartCards.Max(x => x.Number); } if(diaCards.Count != 0) { rowCount++; if(min != 0 && min != diaCards.Min(x => x.Number)) return false; else min = diaCards.Min(x => x.Number); if(max != 0 && max != diaCards.Max(x => x.Number)) return false; else max = diaCards.Max(x => x.Number); } if(clubCards.Count != 0) { rowCount++; if(min != 0 && min != clubCards.Min(x => x.Number)) return false; else min = clubCards.Min(x => x.Number); if(max != 0 && max != clubCards.Max(x => x.Number)) return false; else max = clubCards.Max(x => x.Number); } if(rowCount == 0) ret = false; int width = max - min + 1; if(width * rowCount == cards1.Count) ret = true; else ret = false; return ret; } } |
殺されたカードのリストを取得するGetDeadCardメソッド
カードの生き死にが判定できたら、あとはこれを表示するだけです。
まずは殺されたカードのリストを取得するメソッドを作成しました。カードを一度に殺せる数には制限(ローカルルールでいろいろある)があります。今回は12枚にしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public partial class Form1 : Form { List<Card> GetDeadCard(Card card) { List<Card> deadCards = new List<Card>(); if(IsDeadThisBlock(GetEastTenvironmentCard(card))) deadCards.AddRange(GetEastTenvironmentCard(card)); if(IsDeadThisBlock(GetWestTenvironmentCard(card))) deadCards.AddRange(GetWestTenvironmentCard(card)); if(IsDeadThisBlock(GetNorthTenvironmentCard(card))) deadCards.AddRange(GetNorthTenvironmentCard(card)); if(IsDeadThisBlock(GetSouthTenvironmentCard(card))) deadCards.AddRange(GetSouthTenvironmentCard(card)); deadCards = deadCards.Distinct().ToList(); if(deadCards.Count > 12) deadCards.Clear(); return deadCards; } } |
殺されたカード情報を示すShowIfDeadメソッド
殺されたカードのリストが取得できたら、必要に応じてこれを表示させます。第一引数は出されたカード、第二引数は出したプレイヤーの識別番号です。カードが殺されたときだけメッセージボックスを表示させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public partial class Form1 : Form { void ShowIfDead(Card card, int i) { List<Card> deadCards = GetDeadCard(card); if(deadCards.Count > 0) { string str = ""; str = String.Format("{0} により{1}枚殺されました。", i, deadCards.Count); MessageBox.Show(str); } } } |
ShowIfDeadメソッドを自分と相手がカードを出したあと実行すれば結果が表示されます。
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 |
public partial class Form1 : Form { void RivalTurn(int rivalID) { var rivalCards = playersCards[rivalID]; List<Card> canCards = rivalCards.Intersect(GetCanPutCards()).ToList(); if(canCards.Count != 0) { int next = random.Next(0, canCards.Count); Card nextCard = canCards[next]; rivalCards.Remove(nextCard); nextCard.isExists = true; Rectangle rectInvalidate = new Rectangle(nextCard.Point, Card.Size); Invalidate(rectInvalidate); ShowIfDead(nextCard, rivalID); // カードが出されたあとに呼び出す } else { RivalPass(rivalID); } ShowPlayerInfo(rivalID); } } |
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 { private void Form1_MouseClick(object sender, MouseEventArgs e) { if(!IsMyTurn) return; if(playersCards == null) return; Card card = GetClickedCard(e); if(card == null) return; if(!CanThisPutCard(card)) { MessageBox.Show("このカードは出せません!", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } IsMyTurn = false; var myCards = playersCards[0]; myCards.Remove(card); card.isExists = true; Invalidate(); ShowIfDead(card, 0); // カードが出されたあとに呼び出す ShowPlayerInfo(0); if(!IsMyTurn) { OnRivalsTurn(); } } } |