消えてしまった時間が消えてしまわないように足跡を残す

正月を潰して仕事、そのあた気疲れ(?)とインフルエンザの打撃…ってな感じで1月があっという間に過ぎてしまったわけですが。「あっという間」かどうかは、過去を振り替えてみるとわかるかも、ということで、しばらくは、日記風に blog を書き綴るということで、調子を戻しましょう > 自分、うんうん。

最初はチープな画面を作ってロジックを確認を | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3982

の続きです。

  1. データクラスを作成する
  2. チープな画面を作成する

ってことで、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 フォームが簡単にできるようになったので、これはこれでよいかと。

■お次は

  1. データクラスを作成する
  2. チープな画面を作成する
  3. ゲームロジックを作成する

ってところまでできたので、この度は View の部分を少しリッチにしてみます。
リッチにするところは、

  1. 花札の画像を使って表示する。
  2. 花札ゲームのアクションを作る。

ってところです。花札の画像自体は、Windows ストア アプリのゲーム画像を流用するとして、アクションの部分は、MVVM とユーザーコントロールとの兼ね合いもあるので、ちょっと試行中。

カテゴリー: 雑談 パーマリンク

消えてしまった時間が消えてしまわないように足跡を残す への2件のフィードバック

  1. konica のコメント:

    お疲れ様でした。
    インフルエンザでしたか。
    ついつい、日々何やっているか忘れがちですものね。

    • masuda のコメント:

      実は人生初のインフルエンザでしたyo。
      いろいろ、途中と気分が飛んでしまったので、ブログはしばらくだらだらペースで書く予定ですね。

コメントは停止中です。