最初はチープな画面を作ってロジックを確認を

今更ながら年始の雑文で穴埋めを | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3978

の続き。

ロジックの確認のために、下記のようなチープな画面を作成する。

この手のロジックをチェックするのは、UnitTest を使うのがいいのですが、今回は UI のチェックも兼ねるので、Windows フォームを使っています。最初は、いきなり Windows ストア アプリにしようかと思ったのですが、UI のコーディングがバインドと混ざってややこしくなるので、フォームアプリで作成ということで。

フォームに書いたコードは使い捨てになるので、できるだけ簡潔に…と云いますか、フォームでもWindows ストア アプリでもそれなりに動くようにしたいので(コードレベルでは無理なので、ロジックの手続きレベルで)、ロジックの呼び出しテストも兼ねて。

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
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
 
        _board.Player1.EventSelCard += Player1_EventSelCard;
 
        listBox1.Sorted = true;
        listBox2.Sorted = true;
        listBox3.Sorted = true;
        listBox4.Sorted = true;
        listBox5.Sorted = true;
 
    }
 
    /// <summary>
    /// 2枚から選択する
    /// </summary>
    /// <param name="c1"></param>
    /// <param name="c2"></param>
    /// <returns></returns>
    Card Player1_EventSelCard(Card c1, Card c2)
    {
 
        string msg = string.Format(
            "{0} と {1} があります。{2} を選択しますか?",
            c1.ID, c2.ID, c1.ID);
        var btn = MessageBox.Show(msg, "", MessageBoxButtons.YesNo);
        if (btn == System.Windows.Forms.DialogResult.Yes)
        {
            return c1;
        }
        else
        {
            return c2;
        }
    }
 
    GameBoard _board = new GameBoard();
    Player _curPlayer;
    /// <summary>
    /// 山から1枚取得
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        Card c = _board.Yama.GetCard();
        _board.Ba.PutCard(c);
        // 画面の更新
        ScrUpdate();
    }
 
    /// <summary>
    /// マッチしたカードを場から取得
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button2_Click(object sender, EventArgs e)
    {
        var lst = _board.Game.MatchBa(_board.Ba, _board.Ba.PlayerCard, _curPlayer);
        _board.Ba.GetCard(lst);
        _curPlayer.GetCard(lst);
        // 画面の更新
        ScrUpdate();
    }
 
    /// <summary>
    /// 花札を配る
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button5_Click(object sender, EventArgs e)
    {
        // 花札を配る
        _board.Reset();
        _curPlayer = _board.Player1;
        // 画面の更新
        ScrUpdate();
    }
 
    /// <summary>
    /// player1のカードを場に出す
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button3_Click(object sender, EventArgs e)
    {
        if (listBox2.SelectedIndex == -1)
            return;
 
        var c = (Card)listBox2.SelectedItem;
        _board.Player1.IntoBa(c);
        _board.Ba.PutCard(c);
        _curPlayer = _board.Player1;
        // 画面の更新
        ScrUpdate();
    }
 
    /// <summary>
    /// player2のカードを場に出す
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button4_Click(object sender, EventArgs e)
    {
 
        if (listBox4.SelectedIndex == -1)
            return;
 
        var c = (Card)listBox4.SelectedItem;
        _board.Player2.IntoBa(c);
        _board.Ba.PutCard(c);
        _curPlayer = _board.Player2;
        // 画面の更新
        ScrUpdate();
    }
 
    /// <summary>
    /// 画面の更新
    /// </summary>
    void ScrUpdate()
    {
        listBox1.Items.Clear();
        listBox2.Items.Clear();
        listBox3.Items.Clear();
        listBox4.Items.Clear();
        listBox5.Items.Clear();
        listBox1.Items.AddRange(_board.Ba.Cards.ToArray());
        listBox2.Items.AddRange(_board.Player1.MyCards.ToArray());
        listBox3.Items.AddRange(_board.Player1.TakenCards.ToArray());
        listBox4.Items.AddRange(_board.Player2.MyCards.ToArray());
        listBox5.Items.AddRange(_board.Player2.TakenCards.ToArray());
 
        label7.Text = _board.Ba.PlayerCard.ToString();
    }
}

画面のロジックは基本はユーザーからのイベントドリブンで、ユーザーがなんらかの選択をした時に発生します。昔は業務ロジックと画面からのイベントを分離させるために、「イベントごとに関数を作る」ってなことをやってたりしますが、煩雑なので、最近はパスですね。ですが、NUnit などの自動テストを有効に働かせるためには、画面のほうに業務ロジックを入れないようにするのがベター…なのですが、いまのところこれといった定番がありません。
業務アプリのような簡単な(?)画面の場合には、MVVM か MVC で分離させて、業務ロジックを NUnit でテストして、くっつけた上でアプリ上で再テストって手順がよいのですが、ゲームの場合はどうなんでしょうね?ってのが、今の私の(解消しなければいけない)疑問点です。

そんな訳で、ユーザーがアクションをするボタンの類と、画面更新 ScrUpdate という簡単な組み合わせにしています。このボタンイベントのところが長くなったら、適宜ロジックのほうへ移行ってな雰囲気で組み立てるとよいかと。

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