ドボンのローカルルールのなかにはこのようなものもあります。
Contents
加減乗除した値でもドボンできる
手持ちのカードが2枚の時のみ、その2枚のカードの数値を加減乗除した値であがることができる。たとえば、「2」と「6」があったときには、2+6で「8」、6-2で「4」、6×2で「12」、6÷2で「3」と、4種類の数字に対してあがることができる。これは、ドボン返しする側も同様である。
ネタ元は ドボン – Wikipedia
ではそのように作りかえましょう。
まず設定に関するクラスを変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class ConfigObject { public void CopyToFile() { IsSpecialDobonTwo = Config.IsSpecialDobonTwo; // その他のフィールド変数に関する処理は省略 } public void CopyFromFile() { Config.IsSpecialDobonTwo = IsSpecialDobonTwo; // その他のフィールド変数に関する処理は省略 } // カードの数値を加減乗除した値であがることができる(ただし2枚のときのみ) public bool IsSpecialDobonTwo = true; // その他のフィールド変数は省略 } |
1 2 3 4 5 6 7 |
static public class Config { // カードの数値を加減乗除した値であがることができる(ただし2枚のときのみ) static public bool IsSpecialDobonTwo = 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 28 29 30 31 32 33 34 35 36 |
public partial class ConfigDialog : Form { public ConfigDialog() { InitializeComponent(); buttonOK.DialogResult = DialogResult.OK; buttonOK.Click += ButtonOK_Click; } private void ConfigDialog_Load(object sender, EventArgs e) { if(Config.IsSpecialDobonTwo) cbIsSpecialDobonTwo.Checked = true; else cbIsSpecialDobonTwo.Checked = false; // その他の処理は前回と同じなので省略 } private void ButtonOK_Click(object sender, EventArgs e) { if(cbIsSpecialDobonTwo.Checked) Config.IsSpecialDobonTwo = true; else Config.IsSpecialDobonTwo = false; // その他の処理は前回と同じなので省略 } private void cbIsDrawCardOnlyOne_CheckedChanged(object sender, EventArgs e) { // このイベントハンドラの処理は前回と同じなので省略 } } |
Player.CanDobonメソッドの変更
ドボンできるかどうかをチェックするメソッドがあったので、これに変更を加えればよいですね。
ドボンできるかどうかをチェックするメソッドは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; } } |
これを以下のように変更します。
カードが2枚だけに限定されているので、どちらが大きいかを調べます(引き算と割り算で問題になる)。割り算の場合、割り切れるかどうかも調べる必要があります。
なぜドボンが成立するのか
それからなぜドボンが成立するのか説明がほしいところです。ドボンしたプレイヤーが持っているカードとドボンできた理由も一緒に取得できるように変更します。
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 |
public class Player { public bool CanDobon(Card card, ref string reason) { if(Config.IsSpecialDobonTwo && Cards.Count == 2) { int big = 0; int small = 0; if(Cards[0].Number > Cards[1].Number) { big = Cards[0].Number; small = Cards[1].Number; } else { big = Cards[1].Number; small = Cards[0].Number; } if(card.Number == big - small) return true; if(card.Number == Cards[0].Number * Cards[1].Number) return true; if(card.Number == big / small && big % small == 0) return true; } if(Cards.Sum(x => x.Number) == card.Number) return true; else return false; } } |
DobonIfCanメソッドの変更
引数を変更したので呼び出し元も変更する必要があります。といっても1箇所だけですが・・・。
DobonIfCanメソッドは引数であるプレイヤーに対してドボンできるかどうか、できる場合はドボンするかどうかも含めて判定するメソッドでした。
以前のDobonIfCanメソッドは
1 |
Players.Where(x => x.CanDobon(CenterCard)); |
としてドボンできるプレーヤーを最初に集めて処理をしていたのですが、ドボンできるプレーヤーが複数いる場合、ドボンできる理由が違ってくるので処理内容を変更しています。プレーヤー全員に対してドボンできるかどうか確認するようにしています。ただし自分が出したカードにはドボンできません。
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 { bool DobonIfCan(Player player) { int dobonNumber = CenterCard.Number; string reason = ""; foreach(var dobon in Players) { // 自分が出したカードにはドボンできない if(((CardEx)CenterCard).player == dobon) continue; if(dobon.CanDobon(CenterCard, ref reason)) { if(dobon == Players[0]) { DialogResult dr = MessageBox.Show("ドボンできます。ドボンしますか?\n" + reason, "", MessageBoxButtons.YesNo); if(dr == DialogResult.Yes) { // ドボン返しはあるのか? OnDobon(dobonNumber, Players[0], player); return true; } continue; } else { // コンピュータがドボンを辞退する確率は5分の1 int a = random.Next(5); if(a != 0) { dobon.CanDobon(CenterCard, ref reason); MessageBox.Show(dobon.Name + "が ドボンしました\n" + reason); // ドボン返しはあるのか? OnDobon(dobonNumber, dobon, player); return true; } else continue; // ドボンは見送る } } } return false; } } |
相加相乗平均でもあがれる?
3枚以上の場合:以下のパターンが考えられる(集団や地域により、認められないパターンもある)。なお、これらのパターンは、手持ちの札が2枚の場合のあがりでも適用される。
それから3枚以上の場合でもかけ算でドボンできるルールもあるそうです。ドボン – Wikipediaによると
持ち札を全て掛け合わせた合計 (例)A、A、2、3 → 1×1×2×3=「6」であがり。
持ち札の相加平均 (例)6、9、Q、K → (6+9+12+13)/4=「10」であがり。
持ち札の相乗平均 (例)2、9、12 → 2×9×12=216であり、この3乗根は6であるため、「6」であがり。
このようなものも認めるルールがあるとのことです。相乗平均って(絶句)、ゲームの最中に持っているカードを全部掛け合わせた数を計算して、そのN乗根を計算するなんて・・・相当な計算力が必要ですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
static public class Config { // 3枚以上でも持ち札を全て掛け合わせた合計でドボンできる static public bool IsAllowDobonMultiplication = true; // 持ち札の相加平均でドボンできる static public bool IsAllowDobonAverage = true; // 持ち札の相乗平均でドボンできる static public bool IsAllowDobonGeometricalAverage = 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 28 29 30 31 |
public class ConfigObject { public void CopyToFile() { IsAllowDobonMultiplication = Config.IsAllowDobonMultiplication; IsAllowDobonAverage = Config.IsAllowDobonAverage; IsAllowDobonGeometricalAverage = Config.IsAllowDobonGeometricalAverage; // その他の処理は上と同じ } public void CopyFromFile() { Config.IsAllowDobonMultiplication = IsAllowDobonMultiplication; Config.IsAllowDobonAverage = IsAllowDobonAverage; Config.IsAllowDobonGeometricalAverage = IsAllowDobonGeometricalAverage; // その他の処理は上と同じ } // 3枚以上でも持ち札を全て掛け合わせた合計でドボンできる public bool IsAllowDobonMultiplication = true; // 持ち札の相加平均でドボンできる public bool IsAllowDobonAverage = true; // 持ち札の相乗平均でドボンできる public bool IsAllowDobonGeometricalAverage = true; // その他のフィールド変数は省略 } |
これは設定のダイアログに関するクラスです。新しくフィールド変数とロード時と[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 45 46 47 48 49 50 51 52 53 54 55 |
public partial class ConfigDialog : Form { public ConfigDialog() { InitializeComponent(); buttonOK.DialogResult = DialogResult.OK; buttonOK.Click += ButtonOK_Click; } private void ConfigDialog_Load(object sender, EventArgs e) { if(Config.IsAllowDobonMultiplication) cbIsAllowDobonMultiplication.Checked = true; else cbIsAllowDobonMultiplication.Checked = false; if(Config.IsAllowDobonAverage) cbIsAllowDobonAverage.Checked = true; else cbIsAllowDobonAverage.Checked = false; if(Config.IsAllowDobonGeometricalAverage) cbIsAllowDobonGeometricalAverage.Checked = true; else cbIsAllowDobonGeometricalAverage.Checked = false; // それ以外は上に示したコードとと同じ } private void ButtonOK_Click(object sender, EventArgs e) { if(cbIsAllowDobonMultiplication.Checked) Config.IsAllowDobonMultiplication = true; else Config.IsAllowDobonMultiplication = false; if(cbIsAllowDobonAverage.Checked) Config.IsAllowDobonAverage = true; else Config.IsAllowDobonAverage = false; if(cbIsAllowDobonGeometricalAverage.Checked) Config.IsAllowDobonGeometricalAverage = true; else Config.IsAllowDobonGeometricalAverage = false; // それ以外は上に示したコードとと同じ } private void cbIsDrawCardOnlyOne_CheckedChanged(object sender, EventArgs e) { // 以前のものと変わらず } } |
あとはCanDobonメソッドに加筆修正を加えてできあがりです。
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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
public class Player { public bool CanDobon(Card card, ref string reason) { StringBuilder cardsStringBuilder = new StringBuilder(); foreach(Card card1 in Cards) { cardsStringBuilder.Append(card1.GetCardString() + ","); } if(Config.IsSpecialDobonTwo && Cards.Count == 2) { int big = 0; int small = 0; if(Cards[0].Number > Cards[1].Number) { big = Cards[0].Number; small = Cards[1].Number; } else { big = Cards[1].Number; small = Cards[0].Number; } if(card.Number == big - small) { reason = String.Format("{0}: {1}", "2枚の差", cardsStringBuilder.ToString()); return true; } if(card.Number == Cards[0].Number * Cards[1].Number) { reason = String.Format("{0}: {1}", "2枚の積", cardsStringBuilder.ToString()); return true; } if(card.Number == big / small && big % small == 0) { reason = String.Format("{0}: {1}", "2枚の商", cardsStringBuilder.ToString()); return true; } } if(Config.IsAllowDobonMultiplication) { int i = 1; foreach(Card card1 in Cards) { i *= card1.Number; } if(card.Number == i) { reason = String.Format("{0}: {1}", "手札の積", cardsStringBuilder.ToString()); return true; } } if(Config.IsAllowDobonAverage) { int sum = 0; foreach(Card card1 in Cards) { sum += card1.Number; } if(sum % Cards.Count == 0 && sum / Cards.Count == card.Number) { reason = String.Format("{0}: {1}", "手札の相加平均", cardsStringBuilder.ToString()); return true; } } if(Config.IsAllowDobonGeometricalAverage) { int i = 1; foreach(Card card1 in Cards) { i *= card1.Number; } double d = Math.Pow(i, 1.0 / Cards.Count); if(d == (int)d && d == card.Number) { reason = String.Format("{0}: {1}", "手札の相乗平均", cardsStringBuilder.ToString()); return true; } } if(Cards.Sum(x => x.Number) == card.Number) { reason = String.Format("{0}: {1}", "通常のドボン", cardsStringBuilder.ToString()); return true; } else { reason = "不成立"; return false; } } } |