2022/10/10 引き分けを判断する
まずは質問に答えよう
括弧の種類
[] 大括弧(角括弧が正式名称)
大括弧は、配列のx,y座標を指定するときに使います。
iBordaArray[1,1] = 0;は、配列のx座標1とy座標1の場所に0を入れなさいという意味
{} 中括弧(波括弧が正式名称)
波括弧はプログラム命令の処理のかたまりを示します。if文で条件が成立したときの複数の処理とか一つの関数の中の処理命令群など。
() 小括弧(丸括弧が正式名称)
関数に引数を渡す、または受け取る場合に用います。oDoc.setBord(x, y);など。
※関数が引数を必要としていない場合は()となります。getJudgment()など。
先週までは。。。
先週までは、ドキュメント側に勝敗を判断する関数を作っていました。
今週は、その続きで「引き分け」を判断する部分を追加します。
/// <summary>
/// 戻り値 0:判断不可 1:○の勝ち 2:✕の勝ち 3:引き分け
/// </summary>
/// <returns></returns>
public int getJudgment()
{
int iReturnValue = -1;
//縦横斜め揃っているか?
//ななめを検索
if (iBordArray[0, 0] == iBordArray[1, 1] &&
iBordArray[1, 1] == iBordArray[2, 2])
{
if (iBordArray[0, 0] != 0)
{
iReturnValue = iBordArray[0, 0];
}
}
if (iBordArray[2, 0] == iBordArray[1, 1] &&
iBordArray[1, 1] == iBordArray[0, 2])
{
if (iBordArray[2, 0] != 0)
{
iReturnValue = iBordArray[2, 0];
}
}
//縦を検索
for (int x = 0; x < 3; x++)
{
if (iBordArray[x, 0] == iBordArray[x, 1] &&
iBordArray[x, 1] == iBordArray[x, 2])
{
if (iBordArray[x, 0] != 0)
{
iReturnValue = iBordArray[x, 0];
}
}
}
//横を検索
for (int y = 0; y < 3; y++)
{
if (iBordArray[0, y] == iBordArray[1, y] &&
iBordArray[1, y] == iBordArray[2, y])
{
if (iBordArray[0, y] != 0)
{
iReturnValue = iBordArray[0, y];
}
}
}
★★★★★★★★★★★★★★★★★★★★★★★★★
★ここに引き分けを判断するプログラムを追記します★
★★★★★★★★★★★★★★★★★★★★★★★★★
return iReturnValue;
}
今日の新しい命令 foreach文
foreach (int iCell in iBordArray)
{
}
配列などたくさんの値が入っている入れ物から、一つずつ値を取り出してくれる繰り返し文
上記の例だと、
iBordArrayからひとつづつint型の値をiCellに取り出してくれます。
引き分けとは、どういう状態か?
つまり、iBordArrayの中に0が一つもない状態をいいます。
これをif文で判断するように書くと、
if(iBordArray[0, 0] == 0 ||
iBordArray[0, 1] == 0 ||
iBordArray[0, 2] == 0 ||
iBordArray[1, 0] == 0 ||
iBordArray[1, 1] == 0 ||
iBordArray[1, 2] == 0 ||
iBordArray[2, 0] == 0 ||
iBordArray[2, 1] == 0 ||
iBordArray[2, 2] == 0 )
{
//0が一つでもあった
iReturnValue = 0;
}
else
{
//0は一つもなかった
iReturnValue = 3;
}
となります。3✕3のマス目なのでこの程度で済んでいますが、20✕20のマス目だったら、恐ろしいことになりますね。
これをforeach文を使って、プログラムを書いてみましょう。
プログラムする内容を文章で書いてみた
0が一つもなかったらtrueに変化するbool型の変数
bSpaceFlg(空白を示す0が一つでもあればtrueになる変数)
を用意して考えます。
最初にbSpaceFlgを用意してfalseを入れておきます。
iBordArrayの要素の一つでも0があればbSpaceFlgをtrueにします。
foreach文のループが終わって、
bSpaceFlgがtrueになっていたら空白があった(試合続行 iReturnValueに0を入れる)
bSpaceFlgがfalseのままだったら空白がなかったことになり引き分け(iReturnValueに3を入れる)となります。
文章の部分をプログラムにしてみる
bSpaceFlgの準備
bool bSpaceFlg = false;
iBordArrayの要素の一つでも0があればbSpaceFlgをtrueにします
foreach (int iCell in iBordArray)
{
if (iCell == 0)
{
//空欄あり
bSpaceFlg = true;
}
}
foreach文のループが終わって、bSpaceFlgがtrueになっていたら空白があった(試合続行 iReturnValueに0を入れる)bSpaceFlgがfalseのままだったら空白がなかったことになり引き分け(iReturnValueに3を入れる)となります。
if(bSpaceFlg == true)
{
//空欄あり
iReturnValue = 0;//判断不可を入れる
}
else
{
//空欄なし
iReturnValue = 3;//引き分けを入れる
}
実行して引き分けになるかやってみましょう!
バグはないか?
バグとして発見できたもの
ここの内容は実習で行います。
勝負がついた後の処理
勝敗(引き分け)が付いたらボードをきれいにして次のゲームを開始する
次のゲームを開始するには、ボードをきれいにする(すべて空白にして、〇の順番から始める)ことが必要です。
ボードをきれいにするには、
- ドキュメント側に覚えているiBordArrayをすべて0にして、
- ビュー側のiBordArrayの内容を表現してくれている箇所を再利用する
こととなります。
ドキュメント側でiBordArrayの内容を0にすると同時に順番を〇にしている箇所はすでにある。
public Document()
{
//ボードをクリア
//内容が1の時は○,2の時は✕を意味しています
iBordArray = new int[3, 3] { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
//最初は○からスタート
bMaruBatu = true;
}
しかし、このクラス名と同じ関数名はコンストラクタといい、特別な意味合いがあり、何度も再利用できません。この中のコードを別の関数にお引越しし、コンストラクタからも呼び出して、さらにビュークラスからも呼び出せるようにしましょう。
public Document()
{
//お引越し先を呼び出す
InitDoc();
}
/// <summary>
/// ボードの状態を記憶している配列をクリア、順番を〇にする
/// </summary>
public void InitDoc()
{
//内容が1の時は○,2の時は✕を意味しています
iBordArray = new int[3, 3] { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
//最初は○からスタート
bMaruBatu = true;
}
これで、InitDoc()関数がビュークラスから呼び出せるようになりました。
勝敗が決まった後に呼び出してあげましょう。
//判断する
int iJd = oDoc.getJudgment();
if(iJd == 1)
{
MessageBox.Show("〇の勝ち");
oDoc.InitDoc();
}
else if (iJd == 2)
{
MessageBox.Show("✕の勝ち");
oDoc.InitDoc();
}
else if (iJd == 3)
{
MessageBox.Show("引き分け");
oDoc.InitDoc();
}
ビュー側のiBordArrayの内容を表現してくれている箇所も関数化
//最新のボードの内容を画面に反映
if (iaBord[0, 0] == 1)
{
lbl_0_0.Text = "〇";
}
else if (iaBord[0, 0] == 2)
{
lbl_0_0.Text = "×";
}
else
{
lbl_0_0.Text = "";
}
if (iaBord[0, 1] == 1)
{
lbl_0_1.Text = "〇";
}
else if (iaBord[0, 1] == 2)
{
lbl_0_1.Text = "×";
}
else
{
lbl_0_1.Text = "";
}
[0,3]から[2,2]の処理まで書かれている
この部分を関数化してみましょう。
勝敗が付き、ドキュメントの内容を初期化した直後に今作成した関数を呼び出すと、すべて空白になるハズですね。
//判断する
int iJd = oDoc.getJudgment();
if (iJd == 1)
{
MessageBox.Show("〇の勝ち");
oDoc.InitDoc();
UpdateBord();
}
else if (iJd == 2)
{
MessageBox.Show("✕の勝ち");
oDoc.InitDoc();
UpdateBord();
}
else if (iJd == 3)
{
MessageBox.Show("引き分け");
oDoc.InitDoc();
UpdateBord();
}
やってみましょう。
Discussion