正月を潰して仕事、そのあた気疲れ(?)とインフルエンザの打撃…ってな感じで1月があっという間に過ぎてしまったわけですが。「あっという間」かどうかは、過去を振り替えてみるとわかるかも、ということで、しばらくは、日記風に blog を書き綴るということで、調子を戻しましょう > 自分、うんうん。
最初はチープな画面を作ってロジックを確認を | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3982
の続きです。
- データクラスを作成する
- チープな画面を作成する
ってことで、Model と View が揃ったので、ゲームロジックを作っていきます。データ形式の持ち方はこれでいいのか?ってのを確かめるためでもあるし、ざっとゲームロジックを作ることで、それが「遊べるものかどうか?」ってのが確認できます。ええ、「遊べなそう」ってのが分かったら清く捨ててしまえばいいのです。そのために、この手のデータクラスとか、チープな画面をさっくりと作るのは大切かと。
この方法は、業務アプリでもよくやる方法で、「捨て去ってもいい時間」を使ってプロトタイプ的なものを作ります。世の中のプロトタイプだとお客に見せるために、結構手を込んだものを作る場合がありますが(プレゼンテーション的な意味があるので、それはそれで重要なのです)、自分で確認するプロトタイプ≒これが本当に動くのかどうかのプロトタイプの場合は、「捨てても惜しくない時間を割り当てます」。2,3時間というところでしょうか。長くて1日ですね。ただ、最近気づいたのは、1日でさっくりできるようになるための「実力」を付けるのは結構鍛錬がいるのではないかな、ということ。20年前のパソコン通信の頃の「この人の開発スピードってすごいな!」って程度には、やっとこさ、達することができたような気が…するんだけど、どうでしょう?いやいや、本当のところが、がっと集中して作れる程度が2,3時間ってところなんですけどね。ってことかも。
■データを作成する
さて、通常はそれらしいサンプルを作成するとこから(データクラスの操作性の確認も兼ねて)始めるわけですが、花札の場合は枚数が限られているので、データも作ってしまいます。
Card クラスに持たせてしまうのは異論がある!(私もある!)のですが、ざっと作ったということで。ゲームとしては「こいこい」を作る予定なので、点数自体には意味がないのですが、カス札とか短冊とかを区別するために必要ってことです。このあたりはユーティリティクラスを作っても同じですね。データ量が多い場合は、検索時の効率を考えて、ってのもあるのですが、このぐらいならば全件検索しても特に問題ないし。
/// <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 は無関係になっていません。まあ、これはこれでよいかと。
/// <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。
いろいろ、途中と気分が飛んでしまったので、ブログはしばらくだらだらペースで書く予定ですね。