ドボンのローカルルール
ドボンにはさまざまなローカルルールがあるので混乱しないように最初に確認をしておく必要があります。
出せるカードが手札にない時は出せるカードを引くまで山からカードをとり続けるか、1枚だけなのか?
1枚だけのとき出せるカードを引いたときすぐに出せるのか
上がりはドボンだけか最後のカードを出したときもありなのか?
ドボン返しは出されたカードの合計なのか一番上のカードの数か?
ほかにもドボンは足し算だけでなく引き算、かけ算、割り算(なかには相加平均、相乗平均も含む)もありか?
などなど
設定をしたらファイルに保存することができるようにします。
カードが出せないとき取らなければならないカードは1枚だけにする
まず設定を管理するクラスを作成します。
1 2 3 4 5 6 7 8 |
static public class Config { // カードが出せないとき取らされるカードは1枚だけにする static public bool IsDrawCardOnlyOne = true; // そのカードが出せるときは出せる static public bool IsAllowPutDrawCard = true; } |
そして以下のようなダイアログを作成します。ダイアログ作成時にConfigクラスのデータを読み込ませて[OK]がクリックされたらダイアログのデータを設定に反映させます。
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 |
public partial class ConfigDialog : Form { public ConfigDialog() { InitializeComponent(); buttonOK.DialogResult = DialogResult.OK; buttonOK.Click += ButtonOK_Click; } private void ButtonOK_Click(object sender, EventArgs e) { if(cbIsDrawCardOnlyOne.Checked) Config.IsDrawCardOnlyOne = true; else Config.IsDrawCardOnlyOne = false; if(cbIsAllowPutDrawCard.Checked) Config.IsAllowPutDrawCard = true; else Config.IsAllowPutDrawCard = false; } private void ConfigDialog_Load(object sender, EventArgs e) { if(Config.IsDrawCardOnlyOne) cbIsDrawCardOnlyOne.Checked = true; else cbIsDrawCardOnlyOne.Checked = false; if(Config.IsAllowPutDrawCard) cbIsAllowPutDrawCard.Checked = true; else cbIsAllowPutDrawCard.Checked = false; } private void cbIsDrawCardOnlyOne_CheckedChanged(object sender, EventArgs e) { if(cbIsDrawCardOnlyOne.Checked) cbIsAllowPutDrawCard.Enabled = true; else cbIsAllowPutDrawCard.Enabled = false; } } |
PlayerクラスのOnFindCanPutNoCardメソッドはカードが出せないときに出せるカードを引くまでカードを引き続けます。これを以下のように書き換えます。
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 |
public class Player { Card OnFindCanPutNoCard(List<Card> shuffledCards, Card card) { // 実際に出されたカード Card putCard; // ない場合は1枚だけカードを取る // 追加部分 if(Config.IsDrawCardOnlyOne) { // ない場合は1枚だけカードを取る List<Card> cards = GetAblePutCards(card); if(cards.Count == 0) { Card addCard = shuffledCards[0]; shuffledCards.RemoveAt(0); Cards.Add(addCard); PlayerPanel.Invalidate(); System.Threading.Thread.Sleep(500); // 出せるカードがあったらこれを出す if(Config.IsAllowPutDrawCard && IsAblePutCards(addCard, card)) { Cards.Remove(addCard); PlayerPanel.Invalidate(); System.Threading.Thread.Sleep(500); } return addCard; } // 1枚だけカードを取り出せない場合はなにも出さない return null; } // 追加部分 終わり // ここからは以前と同じ while(true) { // 積み札がなくなったらすでに出されているカードを使う。 if(shuffledCards.Count == 0) _form1.ShuffleCard(card); Card addCard = shuffledCards[0]; shuffledCards.RemoveAt(0); Cards.Add(addCard); PlayerPanel.Invalidate(); System.Threading.Thread.Sleep(500); // 出せるカードがあったらこれを出してループから抜ける if(IsAblePutCards(addCard, card)) { Cards.Remove(addCard); PlayerPanel.Invalidate(); putCard = addCard; System.Threading.Thread.Sleep(500); break; } } return putCard; } } |
これまでOnFindCanPutNoCardメソッドはnullではない値を返してしまいたが、これからはそうとは限りません。呼び出し元のPlayer.PutCardメソッドも変更する必要があります。
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 |
public class Player { public CardEx PutCard(Card card, List<Card> shuffledCards) { // 積み札がなくなったらすでに出されているカードを使う。 if(shuffledCards.Count == 0) _form1.ShuffleCard(card); // 出せるカードを求める List<Card> canPutCards = GetAblePutCards(card); // 実際に出されたカード CardEx putCard = null; if(canPutCards.Count > 0) { putCard = (CardEx)OnFindCanPutCard(canPutCards); } else { // 出せるカードがない場合 putCard = (CardEx)OnFindCanPutNoCard(shuffledCards, card); // 戻り値がnullの場合もある。 if(putCard == null) return null; } // Qを複数枚持っているとき一緒に出すかどうか if(putCard.Number == 12) { // 省略 } if(putCard != null) putCard.player = this; return putCard; } } |
Form1クラスのRivalsTurnメソッドではライバルの動作を処理していましたが、出せるカードがない場合は1枚だけ引くという動作ではカードを出さない場合もあります。CenterCardプロパティにnullを設定すると中央のカードが消えてしまうので条件文で処理をしています。
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 |
public class Player { bool RivalsTurn(int firstRival) { firstRival = firstRival % Players.Count; if(firstRival == 0) return CheckPrevMyTurn(); // 0 は自分なのでライバルではない List<Player> rivals = Players.Skip(1).ToList(); // もし順番が反時計回りであれば順番をリバースする if(isFromBack) rivals.Reverse(); int count = rivals.Count; int start = firstRival - 1; for(int i = start; i < count; i++) { // カードを出すときにプレイヤーごとに少し止める System.Threading.Thread.Sleep(500); // Aが出されていたらスキップ(省略) // 2が出されていたときの処理(省略) Text = rivals[i].Name + "の番です"; Card card = rivals[i].PutCard(CenterCard, ShuffledCards); // Config.IsDrawCardOnlyOne == true の場合、card == nullかもしれない if(card != null) { CenterCard = card; isNotFirstCard = true; } else continue; // Queenが出されたときの処理(省略) // 上がり判定とドボン判定(省略) // Jが出された場合(省略) } // ループが終わったらあなたのターンになるのだが・・・ return CheckPrevMyTurn(); } } |
それから自分に順番が回ってきたときに出せるカードがあるかチェックしてない場合は出せるカードを引くまで自動で処理をしていましたが、この部分も書き換えます。
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 |
public partial class Form1 : Form { bool CheckPrevMyTurn() { // Aが出ているときのスキップの処理(省略) // 2が出されていたら2を出すか2のn乗枚のカードをとる処理(省略) // 自分の番だが出せるカードはあるのか? if(Config.IsDrawCardOnlyOne) { // ない場合は1枚だけカードを取る List<Card> cards = Players[0].GetAblePutCards(CenterCard); if(cards.Count == 0) { Text = "出せるカードがありません"; System.Threading.Thread.Sleep(500); Card addCard = ShuffledCards[0]; ShuffledCards.RemoveAt(0); Players[0].Cards.Add(addCard); Players[0].PlayerPanel.Invalidate(); System.Threading.Thread.Sleep(500); // 出せるカードがあったらこれを出す。ないなら何もしない if(Config.IsAllowPutDrawCard && Players[0].IsAblePutCards(addCard, CenterCard)) { Text = "出せるカードを引いたので出します。"; Players[0].Cards.Remove(addCard); Players[0].PlayerPanel.Invalidate(); CenterCard = addCard; System.Threading.Thread.Sleep(500); } return RivalsTurn(1); } else return true; } else { // ない場合は出せるカードを引くまでカードを取り続ける // else文内に入れたが、この部分は以前と変わらない if(!AddCardIfCanNotPutCard()) return true; else return RivalsTurn(1); } } } |
ConfigDialog クラスのConfigですが、インスタンスの必要がありますか?Config config = new Config();
静的メンバーだけなのでConfig config = new Config();とする必要は無いです。
ただだったらクラスまるごと静的クラスにしてしまったほうがわかりやすいかも。
ありがとうございます。
解決いたしました!!