正月を潰して仕事、そのあた気疲れ(?)とインフルエンザの打撃…ってな感じで1月があっという間に過ぎてしまったわけですが。「あっという間」かどうかは、過去を振り替えてみるとわかるかも、ということで、しばらくは、日記風に blog を書き綴るということで、調子を戻しましょう > 自分、うんうん。
最初はチープな画面を作ってロジックを確認を | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3982
の続きです。
- データクラスを作成する
- チープな画面を作成する
ってことで、Model と View が揃ったので、ゲームロジックを作っていきます。データ形式の持ち方はこれでいいのか?ってのを確かめるためでもあるし、ざっとゲームロジックを作ることで、それが「遊べるものかどうか?」ってのが確認できます。ええ、「遊べなそう」ってのが分かったら清く捨ててしまえばいいのです。そのために、この手のデータクラスとか、チープな画面をさっくりと作るのは大切かと。
この方法は、業務アプリでもよくやる方法で、「捨て去ってもいい時間」を使ってプロトタイプ的なものを作ります。世の中のプロトタイプだとお客に見せるために、結構手を込んだものを作る場合がありますが(プレゼンテーション的な意味があるので、それはそれで重要なのです)、自分で確認するプロトタイプ≒これが本当に動くのかどうかのプロトタイプの場合は、「捨てても惜しくない時間を割り当てます」。2,3時間というところでしょうか。長くて1日ですね。ただ、最近気づいたのは、1日でさっくりできるようになるための「実力」を付けるのは結構鍛錬がいるのではないかな、ということ。20年前のパソコン通信の頃の「この人の開発スピードってすごいな!」って程度には、やっとこさ、達することができたような気が…するんだけど、どうでしょう?いやいや、本当のところが、がっと集中して作れる程度が2,3時間ってところなんですけどね。ってことかも。
■データを作成する
さて、通常はそれらしいサンプルを作成するとこから(データクラスの操作性の確認も兼ねて)始めるわけですが、花札の場合は枚数が限られているので、データも作ってしまいます。
Card クラスに持たせてしまうのは異論がある!(私もある!)のですが、ざっと作ったということで。ゲームとしては「こいこい」を作る予定なので、点数自体には意味がないのですが、カス札とか短冊とかを区別するために必要ってことです。このあたりはユーティリティクラスを作っても同じですね。データ量が多い場合は、検索時の効率を考えて、ってのもあるのですが、このぐらいならば全件検索しても特に問題ないし。
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 | /// <summary> /// カード /// </summary> public class Card { string _id; ... static protected Dictionary< string , int > _tens; /// <summary> /// 点数を取得 /// </summary> public int Ten { get { if (Card._tens == null ) { Card._tens = new Dictionary< string , int >(); Card._tens[ "A1" ] = 20; // 松に鶴 Card._tens[ "A2" ] = 5; Card._tens[ "A3" ] = 1; Card._tens[ "A4" ] = 1; Card._tens[ "B1" ] = 10; // 梅に鶯 Card._tens[ "B2" ] = 5; Card._tens[ "B3" ] = 1; Card._tens[ "B4" ] = 1; Card._tens[ "C1" ] = 20; // 桜に幕 Card._tens[ "C2" ] = 5; Card._tens[ "C3" ] = 1; Card._tens[ "C4" ] = 1; Card._tens[ "D1" ] = 10; // 藤にホトトギス Card._tens[ "D2" ] = 5; Card._tens[ "D3" ] = 1; Card._tens[ "D4" ] = 1; Card._tens[ "E1" ] = 10; // 菖蒲に八つ橋 Card._tens[ "E2" ] = 5; Card._tens[ "E3" ] = 1; Card._tens[ "E4" ] = 1; Card._tens[ "F1" ] = 10; // 牡丹に蝶 Card._tens[ "F2" ] = 5; Card._tens[ "F3" ] = 1; Card._tens[ "F4" ] = 1; Card._tens[ "G1" ] = 10; // 萩に猪 Card._tens[ "G2" ] = 5; Card._tens[ "G3" ] = 1; Card._tens[ "G4" ] = 1; Card._tens[ "H1" ] = 20; // ススキに月 Card._tens[ "H2" ] = 10; Card._tens[ "H3" ] = 1; Card._tens[ "H4" ] = 1; Card._tens[ "I1" ] = 10; // 菊に盃 Card._tens[ "I2" ] = 5; Card._tens[ "I3" ] = 1; Card._tens[ "I4" ] = 1; Card._tens[ "J1" ] = 10; // 銀杏に鹿 Card._tens[ "J2" ] = 5; Card._tens[ "J3" ] = 1; Card._tens[ "J4" ] = 1; Card._tens[ "K1" ] = 20; // 小野道風に蛙 Card._tens[ "K2" ] = 10; Card._tens[ "K3" ] = 5; Card._tens[ "K4" ] = 1; Card._tens[ "L1" ] = 50; // 桐に鳳凰 Card._tens[ "L2" ] = 1; Card._tens[ "L3" ] = 1; Card._tens[ "L4" ] = 1; } return Card._tens[_id]; } } public override string ToString() { return _id; } } |
■役を作る
ざっくりとデータができたら、役を作ります。いわゆるカードゲームの場合は、同じパターンで作るのではないかな、と。最初は「役を計算する」部分と「点数を計算する」部分とを独立させて作っていたのですが、結局のところ「役」を使って「点数」を計算することになるので、CalcYaku と CalcTen は無関係になっていません。まあ、これはこれでよいかと。
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | /// <summary> /// 役クラス /// </summary> public class Yaku { public List<Card> GoKou; public List<Card> ShiKou; public List<Card> AmeShiKou; public List<Card> SanKou; public List<Card> InoShika; public List<Card> AkaTan; public List<Card> AoTan; public List<Card> Hanami; public List<Card> Tukimi; public List<Card> Tane; public List<Card> Tan; public List<Card> Kasu; } /// <summary> /// ゲームルールライブラリ /// </summary> public class Game { ... /// <summary> /// 役を計算する /// </summary> /// <param name="cards"></param> /// <returns></returns> public Yaku CalcYaku(List<Card> cards) { Yaku yaku = new Yaku(); // 菊に盃の有無をチェック bool I1 = cards.Find(n => n.ID == "I1" ) != null ; // 20点札をチェック var cs = cards.FindAll(n => n.Ten == 20); if (cs.Count == 5) yaku.GoKou = new List<Card>( cs ); else if ( cs.Count == 4 ) if (cs.Find(n => n.ID == "K1" ) != null ) yaku.AmeShiKou = new List<Card>( cs ); else yaku.ShiKou = new List<Card>( cs ); else if ( cs.Count == 3 ) yaku.SanKou = new List<Card>( cs ); // 花見、月見 cs = cards.FindAll(n => n.ID == "I1" || n.ID == "C1" ); if ( cs.Count == 2 ) yaku.Hanami = new List<Card>(cs); cs = cards.FindAll(n => n.ID == "I1" || n.ID == "H1" ); if (cs.Count == 2) yaku.Hanami = new List<Card>(cs); // 猪鹿蝶 cs = cards.FindAll(n => n.ID == "G1" || n.ID == "J1" || n.ID == "F1" ); if (cs.Count == 3) { yaku.InoShika = new List<Card>(cs); // タネに追加 yaku.Tane = cards.FindAll(n => n.Ten == 10); } // 赤短 cs = cards.FindAll(n => n.ID == "A2" || n.ID == "B2" || n.ID == "C2" ); if ( cs.Count == 3 ) yaku.AkaTan = new List<Card>(cs); // 青短 cs = cards.FindAll(n => n.ID == "I2" || n.ID == "J2" || n.ID == "F2" ); if ( cs.Count == 3 ) yaku.AoTan = new List<Card>(cs); if (yaku.AkaTan != null || yaku.AoTan != null ) { // タンに追加 yaku.Tan = cards.FindAll(n => n.Ten == 5); } // タネ if ( yaku.Tane == null ) { cs = cards.FindAll(n => n.Ten == 10); if ( cs.Count >= 5 ) yaku.Tane = new List<Card>(cs); } // タン if ( yaku.Tan == null ) { cs = cards.FindAll(n => n.Ten == 5); if ( cs.Count >= 5 ) yaku.Tane = new List<Card>(cs); } // カス cs = cards.FindAll(n => n.Ten == 1); if ( I1 == true && yaku.Tane.Find(n=>n.ID== "I1" ) == null ) cs.Add( cards.Find( n=>n.ID == "I1" )); if ( cs.Count >= 10 ) yaku.Kasu = new List<Card>(cs); return yaku; } /// <summary> /// 点数を計算する /// </summary> /// <param name="yaku"></param> /// <returns></returns> public int CalcTen( Yaku yaku ) { int ten = 0; // 20点札をチェック if (yaku.GoKou != null ) ten += 10; // 五光 if (yaku.SanKou != null ) ten += 8; // 四光 if (yaku.AmeShiKou != null ) ten += 7; // 雨四光 if (yaku.SanKou != null ) ten += 5; // 三光 if (yaku.Hanami != null ) ten += 5; // 花見 if (yaku.Tukimi != null ) ten += 5; // 月見 if (yaku.InoShika != null ) // 猪鹿蝶 { ten += 5; // タネ分を加算 if (yaku.Tane != null ) ten += yaku.Tane.Count - 3; } if (yaku.AkaTan != null ) ten += 5; // 赤短 if (yaku.AoTan != null ) ten += 5; // 青短 if (yaku.AoTan != null || yaku.AkaTan != null ) { // タン分を加算 if (yaku.Tan != null ) ten += yaku.Tan.Count - yaku.AkaTan.Count - yaku.AoTan.Count; } // タネ if (yaku.Tane != null && yaku.InoShika == null ) ten += yaku.Tane.Count - 4; // タン if (yaku.Tan != null && yaku.AkaTan == null && yaku.AoTan == null ) ten += yaku.Tan.Count - 4; // カス if (yaku.Kasu != null ) ten += yaku.Kasu.Count - 9; return ten; } } |
で、これを組み込んで、チープな画面を使ってテストをすると、そこそこ「遊べる」ことがわかります。昔ならばコマンドラインでぽちぽちとキーボードでテストをしていたのですが、Windows フォームが簡単にできるようになったので、これはこれでよいかと。
■お次は
- データクラスを作成する
- チープな画面を作成する
- ゲームロジックを作成する
ってところまでできたので、この度は View の部分を少しリッチにしてみます。
リッチにするところは、
- 花札の画像を使って表示する。
- 花札ゲームのアクションを作る。
ってところです。花札の画像自体は、Windows ストア アプリのゲーム画像を流用するとして、アクションの部分は、MVVM とユーザーコントロールとの兼ね合いもあるので、ちょっと試行中。
お疲れ様でした。
インフルエンザでしたか。
ついつい、日々何やっているか忘れがちですものね。
実は人生初のインフルエンザでしたyo。
いろいろ、途中と気分が飛んでしまったので、ブログはしばらくだらだらペースで書く予定ですね。