ジョーカーに関するローカルルール
これまではジョーカーは使いませんでした。ジョーカーを使う場合、これもローカルルールがいくつかあります。
出せるカードがない場合、ジョーカーを代用する
(ジョーカーはすべてのカードの代わりになる)
ジョーカーは単独では使用できない
場に出ているカードから1つ違ったカードを持っている場合であれば、ジョーカーと併せて1つ違った数字のカードとの2枚を一緒に出さないといけません。この場合、ジョーカーはいつでも使えるカードではなくなります。
またジョーカーが出された場合、その位置に本来置かれるべきカードを持っているプレイヤーは、そのカードを場に出し、代わりにジョーカーを手札に加えなければならないというルールもあります。
そのときジョーカーは強制的に取らされるというルールと、辞退することができるルールがあります。
ローカルルールがたくさんあるとややこしいです。
今回作成するプログラムのルール
ここではいきなり難しくすると大変(あと間を持たせることができない)なのでジョーカーは単体で出す、ジョーカーのうけとりは「拒否できない」というルールにします。あとでジョーカーは次に出せるカードとセットで出さなければならない、ジョーカーをもらうかどうかは任意というルールでもつくってみることにします。
ジョーカーを表示させる
カードの種類は以下のように定義されています。
1 2 3 4 5 6 7 8 9 |
public enum CardMark { none = -1, joker = 0, spade = 1, hart = 2, dia = 3, club = 4, } |
まずはカードを配るときにジョーカーをいれる必要があります。それからカードを生成するときにジョーカーもつくる必要があります。
以下はカードを生成するためのクラスです。カードの絵柄を取得するメソッドを少し変更しています。
これでジョーカーをつくることができます。またスペードのAは他のカードと違う絵柄もあったので、これを使うことにします。
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 |
class Card { Bitmap _bitmap = null; // カードの絵柄はクラス外からも取得できるようにした public Bitmap Bitmap { get { if(_bitmap == null) _bitmap = GetBitmap(); return _bitmap; } } Bitmap GetBitmap() { Rectangle rect = new Rectangle(Point, Size); Bitmap bitmap = new Bitmap(Size.Width, Size.Height); var image = Properties.Resources.cardimage; int x, y = 0; x = 0; if(Mark == CardMark.spade) { y = 1800; x = 382 * (Number - 1); } if(Mark == CardMark.hart) { y = 1200; x = 382 * (Number - 1); } if(Mark == CardMark.dia) { y = 600; x = 382 * (Number - 1); } if(Mark == CardMark.club) { y = 0; x = 382 * (Number - 1); } // 追加部分 ジョーカー if(Mark == CardMark.joker) { y = 2400; x = 0; } // 追加部分 裏 if(Mark == CardMark.none) { y = 2400; x = 382 * 2; } // 追加部分 スペードのエース if(Mark == CardMark.spade && Number == 1) { y = 2400; x = 382 * 1; } Rectangle srcRect = new Rectangle(new Point(x, y), new Size(354, 490)); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawImage(image, new Rectangle(0, 0, Size.Width, Size.Height), srcRect, GraphicsUnit.Pixel); graphics.Dispose(); return bitmap; } } |
これはジョーカーを使うためのメソッドです。引数はどのカードの代わりに使うかです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Card { public void UseJoker(CardMark mark, int number) { Colum = number - 1; if(mark == CardMark.spade) Row = 0; if(mark == CardMark.hart) Row = 1; if(mark == CardMark.dia) Row = 2; if(mark == CardMark.club) Row = 3; int x = (size.Width + 10) * Colum + 20; int y = (size.Height + 10) * Row + 30; Point = new Point(x, y); } } |
カードを生成するときにジョーカーも生成します。他のマークには番号がありますが、ジョーカーには番号はありません。とりあえず1を設定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Form1 : Form { void Init() { for(int i = 1; i <= 13; i++) cards.Add(new Card(CardMark.spade, i)); for(int i = 1; i <= 13; i++) cards.Add(new Card(CardMark.hart, i)); for(int i = 1; i <= 13; i++) cards.Add(new Card(CardMark.dia, i)); for(int i = 1; i <= 13; i++) cards.Add(new Card(CardMark.club, i)); cards.Add(new Card(CardMark.joker, 1)); } } |
ライバルの動作に関するメソッド
もし相手が出せるカードはないけどジョーカーを持っているのであれば、それを使います。
ジョーカーが使用する場合、どのカードの代わりに使うのかを考える必要があります。乱数で適当に決めています。
それからジョーカーしか持っていないのであれば、そのプレイヤーは負けです。
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 |
public partial class Form1 : Form { void RivalTurn(int rivalID) { var rivalCards = playersCards[rivalID]; List<Card> canCards = rivalCards.Intersect(GetCanTakeout()).ToList(); if(canCards.Count != 0) { // 持っているカードを普通に出す // 省略 } else { // ジョーカーしかもっていないのであれば失格 if(rivalCards.Count == 1 && rivalCards[0].Mark == CardMark.joker) { string str = String.Format("ジョーカーしかもっていない {0} は失格です", rivalID); MessageBox.Show(str, "報告", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); // 失格の表示をさせるための処理 passCounts[rivalID] = PASS_MAX + 1; ShowPlayerInfo(rivalID); return; } // ジョーカーをもっているのであれば出す if(rivalCards.Any(x => x.Mark == CardMark.joker)) { Card jokerCard = rivalCards.First(x => x.Mark == CardMark.joker); rivalCards.Remove(jokerCard); // どのカードの代わりに出すか? int next = random.Next(0, GetCanTakeout().Count); Card nextCard = GetCanTakeout()[next]; jokerCard.UseJoker(nextCard.Mark, nextCard.Number); jokerCard.isExists = true; Rectangle rectInvalidate = new Rectangle(jokerCard.Point, Card.Size); Invalidate(rectInvalidate); OnUseJoker(jokerCard, nextCard); } 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 |
class Card { public void UseJoker(CardMark mark, int number) { Colum = number - 1; if(mark == CardMark.spade) Row = 0; if(mark == CardMark.hart) Row = 1; if(mark == CardMark.dia) Row = 2; if(mark == CardMark.club) Row = 3; int x = (size.Width + 10) * Colum + 20; int y = (size.Height + 10) * Row + 30; Point = new Point(x, y); } } |
ジョーカーが使用された場合、ジョーカーのかわりに出されているカードを持っているプレイヤーはそれを出さなければなりません。OnUseJokerはカードの持ち主を探してカードをださせてジョーカーを受け取らせます。
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 |
public partial class Form1 : Form { void OnUseJoker(Card jokerCard, Card card) { MessageBox.Show("ジョーカーが使用されました"); // カードの持ち主を探す List<Card> player1 = null; foreach(var player in playersCards) { if(player.Any(x => x == card)) { player1 = player; break; } } if(player1 != null) { player1.Remove(card); player1.Add(jokerCard); card.isExists = true; jokerCard.isExists = false; Rectangle rectInvalidate = new Rectangle(card.Point, Card.Size); Invalidate(rectInvalidate); } } } |
次回は自分の動作に関するメソッドを考えます。