『Excelでリバーシを作ろう!!　マクロ、VBAを1から学ぶ』サンプル(7)　【三目並べ：6. 勝敗を判定する】

この記事は **『Excelでリバーシを作ろう!!　マクロ、VBAを1から学ぶ』** のサンプルです。

前：【三目並べ：5. コードにコメントを入れる】
https://qiita.com/sano192/items/d8f124a61211efc86085

次：【三目並べ：7. テストする】
https://qiita.com/sano192/items/89a59afd45c5659e3574

Excelのマクロ(VBA)で「三目並べ」「マインスイーパー」「リバーシ」を作る解説本です！
プログラミングが全くわからない人でも大丈夫！　丁寧な解説と図でしっかり理解しながら楽しくプログラミングを学ぶ事ができます！
**値段：300円(Kindle Unlimited対象)**

**【kindle】**

https://www.amazon.co.jp/dp/B09XLM42MW

**【booth(pdf】**

https://sano192.booth.pm/items/3785312

勝敗判定の処理を書きます。
勝敗(または引き分け)がつくのは以下の場合です。
(1)黒石または白石が縦、横、斜めのどれかに3つ連続で並ぶ
(2)勝敗がつかずに全てのマスが埋まる
　
石を置くたびにこれら条件を満たしているか判定し、勝ち、負け、引き分けを表示します。
が、この条件と処理をセルをクリックしたときの処理に直接書くとコードが煩雑になります。
　
そこで「関数」を使って勝敗判定を行う部分を別に書きます。
　
関数は決まった処理を書いておくと、処理結果によって値を返してくれる、という機能です。返してもらった値は確認したり変数に受け取ったりすることができます。
　
ここで作る関数では勝敗の状況によって以下を返すようにします。
・「黒」の勝ち→「1」
・「白」の勝ち→「2」
・「引き分け」→「3」
関数を処理し、「1」が返ってきたら黒が勝ったのだな、ということがわかる、というわけです。
　
関数の書き方は以下です。
　
Function 関数名()
　
    ～処理内容～
　
End Function
　
今回は勝敗判定なので関数の名前を「Judge」としましょう。
　
Private Sub Worksheet_SelectionChange～End Subの後に以下のように書いてください。

```vb:
Function Judge()

End Function
```

function Judgeまで書いてEnterを押すとエクセルが残りを自動補完してくれます。
　
ここに関数の処理内容を書いていきます。
(1)黒石または白石が縦、横、斜めのどれかに3つ連続で並ぶ
縦、横、斜めの選び方は8通りあります。その全てについて「●」または「○」になっているかを条件分岐で判定します。
例えば(左上,左中,左下)が全て「●」になっている場合、セル(B2),セル(B3),セル(B4)が全て「●」になっているわけです。これをIfを使って確認します。

```vb:
If Cells(2, 2) = "●" And Cells(2, 3) = "●" And Cells(2, 4) = "●" Then
```

もしこの条件を満たしているなら黒の勝ちです。
黒が勝った場合、この関数は「1」を返します。
　
値を返すときは以下のように書きます。
　
関数名 = 返す値
　
黒が勝っている場合は以下のようになります。

```vb:
Judge = 1
```

まとめると、(左上,左中,左下)が全て「●」で黒の勝ち→「1」を返したい場合は以下のように書きます。


```vb:
If Cells(2, 2) = "●" And Cells(2, 3) = "●" And Cells(2, 4) = "●" Then

    Judge = 1

End If
```

逆に白が勝った場合は「2」を返します。
以下のようになります。

```vb:
If Cells(2, 2) = "○" And Cells(2, 3) = "○" And Cells(2, 4) = "○" Then

    Judge = 2

End If
```

これを縦3通り、横3通り、斜め2通りの全8通りの組み合わせ、「●」「○」に分けて書けば勝敗の判定ができます。
少々大変ですが頑張りましょう。

```vb:
If Cells(2, 2) = "●" And Cells(2, 3) = "●" And Cells(2, 4) = "●" Then
    Judge = 1
ElseIf Cells(3, 2) = "●" And Cells(3, 3) = "●" And Cells(3, 4) = "●" Then
    Judge = 1
ElseIf Cells(4, 2) = "●" And Cells(4, 3) = "●" And Cells(4, 4) = "●" Then
    Judge = 1
ElseIf Cells(2, 2) = "●" And Cells(3, 2) = "●" And Cells(4, 2) = "●" Then
    Judge = 1
ElseIf Cells(2, 3) = "●" And Cells(3, 3) = "●" And Cells(4, 3) = "●" Then
    Judge = 1
ElseIf Cells(2, 4) = "●" And Cells(3, 4) = "●" And Cells(4, 4) = "●" Then
    Judge = 1
ElseIf Cells(2, 2) = "●" And Cells(3, 3) = "●" And Cells(4, 4) = "●" Then
    Judge = 1
ElseIf Cells(2, 4) = "●" And Cells(3, 3) = "●" And Cells(4, 2) = "●" Then
    Judge = 1

ElseIf Cells(2, 2) = "○" And Cells(2, 3) = "○" And Cells(2, 4) = "○" Then
    Judge = 2
ElseIf Cells(3, 2) = "○" And Cells(3, 3) = "○" And Cells(3, 4) = "○" Then
    Judge = 2
ElseIf Cells(4, 2) = "○" And Cells(4, 3) = "○" And Cells(4, 4) = "○" Then
    Judge = 2
ElseIf Cells(2, 2) = "○" And Cells(3, 2) = "○" And Cells(4, 2) = "○" Then
    Judge = 2
ElseIf Cells(2, 3) = "○" And Cells(3, 3) = "○" And Cells(4, 3) = "○" Then
    Judge = 2
ElseIf Cells(2, 4) = "○" And Cells(3, 4) = "○" And Cells(4, 4) = "○" Then
    Judge = 2
ElseIf Cells(2, 2) = "○" And Cells(3, 3) = "○" And Cells(4, 4) = "○" Then
    Judge = 2
ElseIf Cells(2, 4) = "○" And Cells(3, 3) = "○" And Cells(4, 2) = "○" Then
    Judge = 2
End If
```

もしJudge=1　または　2であれば処理を終了します。
「または」という条件は「Or」を使います。
　
関数を途中終了するときは
　
Exit Function
　
と書きます。

```vb:
If Judge = 1 Or Judge = 2 Then

    Exit Function

End If
```

もしJudge=1または2でなければ勝敗はついていないので処理続行です。
　
(2)勝敗がつかずに全てのマスが埋まる
「勝敗がつかずに全てのマスが埋まる」とはつまり引き分けということです。
こちらの処理はセル(B2)~セル(D4)の全てに「○」か「●」が埋まっているか確認するということです。
言い換えると「セル(B2)~セル(D4)に一つでも空白のマスがあれば埋まっていない」と判断できます。
　
この処理を行うため、「ループ」という処理を行います。
ループは同じような処理を何回も行う時に使います。
書き方は以下です。
　
For 変数名 = 開始 To 終了
　
    ～処理内容～
　    
Next 変数名
　
Forの処理がどのようなものか確認するため、簡単なコードを書いてみましょう。
Function Judge~End Functionの次の行に、以下のように書いてください。
※ForもIf同様、中身のインデントをTabキーで下げるようにしてください。

```vb:
Sub Test()

    For i = 1 To 5
        MsgBox i
    Next i

End Sub
```

これを実行します。実行するときはSub～End Subの間のどこかにカーソルを合わせて、左上の「▶」マークをクリックします。
![29.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700383/91b9afb1-ae6c-d285-4151-b85247712a05.png)
「1」「2」「3」「4」「5」という順番でメッセージボックスが出てきたと思います。
これはi=1,2,3,...という順番で代入され、「iをメッセージボックスに表示する」という処理が行われたためです。
　
このようにForを使うと変数へ順番に値を代入しながら処理が出来ます。
　
引き分けの判定は行番号=2,3,4、列番号=2,3,4という順番で(行番号,列番号)が一つでも空白のものがあるか？　を判定すればOKです。
　
Forを行の処理と列の処理で2つ書きます。
行番号を格納する変数をGyou
列番号を格納する処理をRetu
としましょう。
これもDim Gyou,Retuと書いて宣言しておきます。
　
「セル(Gyou,Retu)が空白であるか？」という判定をIfで行います。一つでも空白のものがあれば引き分けでなく、勝負はついていないので続行です。この場合は「4」を返しましょう。
　
以上をコードにすると以下のようになります。Function Judge~End Functionの最後に書いてください。


```vb:
Dim Gyou,Retu

For Gyou = 2 To 4
    For Retu = 2 To 4

        If Cells(Gyou, Retu) = "" Then
            Judge = 4
        End If

    Next Retu
Next Gyou
```

Forが2つあって複雑そうに見えますが、このコードでは
Gyou=2,Retu=2
↓
Gyou=2,Retu=3
↓
Gyou=2,Retu=4
↓
Gyou=3,Retu=2
↓
Gyou=3,Retu=3
↓
…
↓
Gyou=4,Retu=4
という順番で格納して処理を行います。これで盤面の全てのマスについて「空白があるか？」を確認できます。
　
For関連のエラーとしてよくあるのは「Next」を書き忘れる、「Nextの後に書いた変数名がForで指定したものと違う」ということがあります。エラーが出たら確認しましょう。
　
ここまでの処理でJudgeが「4」になっていなければ「全てのマスが埋まっている」かつ「「●」または「○」が3つ並んでいない」ということになります。
つまり「引き分け」です。この場合は「3」を返しましょう。


```vb:
If Judge <> 4 Then
    Judge = 3
End If
```

これで勝敗判定処理が出来ました。
・「黒」の勝ち→「1」を返す
・「白」の勝ち→「2」を返す
・「引き分け」→「3」を返す
・勝敗がついていない→「4」を返す
　
Functionの中身をまとめます。

```vb:
Function Judge()

    If Cells(2, 2) = "●" And Cells(2, 3) = "●" And Cells(2, 4) = "●" Then
        Judge = 1
    ElseIf Cells(3, 2) = "●" And Cells(3, 3) = "●" And Cells(3, 4) = "●" Then
        Judge = 1
    ElseIf Cells(4, 2) = "●" And Cells(4, 3) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 2) = "●" And Cells(3, 2) = "●" And Cells(4, 2) = "●" Then
        Judge = 1
    ElseIf Cells(2, 3) = "●" And Cells(3, 3) = "●" And Cells(4, 3) = "●" Then
        Judge = 1
    ElseIf Cells(2, 4) = "●" And Cells(3, 4) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 2) = "●" And Cells(3, 3) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 4) = "●" And Cells(3, 3) = "●" And Cells(4, 2) = "●" Then
        Judge = 1

    ElseIf Cells(2, 2) = "○" And Cells(2, 3) = "○" And Cells(2, 4) = "○" Then
        Judge = 2
    ElseIf Cells(3, 2) = "○" And Cells(3, 3) = "○" And Cells(3, 4) = "○" Then
        Judge = 2
    ElseIf Cells(4, 2) = "○" And Cells(4, 3) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 2) = "○" And Cells(3, 2) = "○" And Cells(4, 2) = "○" Then
        Judge = 2
    ElseIf Cells(2, 3) = "○" And Cells(3, 3) = "○" And Cells(4, 3) = "○" Then
        Judge = 2
    ElseIf Cells(2, 4) = "○" And Cells(3, 4) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 2) = "○" And Cells(3, 3) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 4) = "○" And Cells(3, 3) = "○" And Cells(4, 2) = "○" Then
        Judge = 2

    End If

    If Judge = 1 Or Judge = 2 Then

        Exit Function

    End If

    Dim Gyou, Retu

    For Gyou = 2 To 4
        For Retu = 2 To 4

            If Cells(Gyou, Retu) = "" Then
                Judge = 4
            End If

        Next Retu
    Next Gyou

    If Judge <> 4 Then
        Judge = 3
    End If

End Function
```

この関数を石を置くたびに使います。Private Sub Worksheet_SelectionChange~End Subの方へ戻りましょう。
ここからの内容はPrivate Sub Worksheet_SelectionChange～End Subの中に書いてください。
　
関数を使うことを「関数を呼び出す」と言います
Judgeを呼び出して帰ってきた値(黒勝ち=1,白勝ち=2,引き分け=3,勝敗未=4)を変数Resultに入れます。
　
まずResultを変数として宣言します。Gyou,Retuを宣言したところにResultをくっつけましょう。

```vb:
Dim Gyou, Retu, Result
```

End Subの直前に以下のように書いてください。

```vb:
Result = Judge
```

これでJudgeの結果をResultに格納できました。
　
・「黒」の勝ち→「1」
・「白」の勝ち→「2」
・「引き分け」→「3」
セル(F2)に結果を入力します。

```vb:
If Result = 1 Then
    Cells(2, 6) = "黒の勝ち"

ElseIf Result = 2 Then
    Cells(2, 6) = "白の勝ち"

ElseIf Result = 3 Then
    Cells(2, 6) = "引き分け"

End If
```

ここまで書けたらテストします。
・黒が3つ並んだら「黒の勝ち」と表示されるか？
・白が3つ並んだら「白の勝ち」と表示されるか？
・引き分けになったら「引き分け」と表示されるか？
・勝敗がついていないのに「勝ち」や「引き分け」が表示されることはないか？
　
なにか上手く行かなかったりエラーが出たりする人は次にコードの全体を載せているので自分の書いたものと見比べてみてください。

【ここまでのコード】

```vb:
'ゲーム開始の処理
Sub GameStart()

    Range("B2", "D4").ClearContents
    Cells(2, 6) = "黒番"

End Sub

'セルをクリックしたときの処理
Private Sub Worksheet_SelectionChange(ByVal Target As Range)

'    変数の宣言
    Dim Gyou, Retu, Result

'    クリックしたセルの行番号 , 列番号
    Gyou = Target.Row
    Retu = Target.Column

'    クリックしたセルが盤面の範囲内なら
    If 2 <= Gyou And Gyou <= 4 And 2 <= Retu And Retu <= 4 Then

'        セルが空白なら
        If Cells(Gyou, Retu) <> "" Then
'            処理を途中終了
            Exit Sub

        End If

'        黒番なら
        If Cells(2, 6) = "黒番" Then
            Cells(Gyou, Retu) = "●"
            Cells(2, 6) = "白番"

'        白番なら
        ElseIf Cells(2, 6) = "白番" Then
            Cells(Gyou, Retu) = "○"
            Cells(2, 6) = "黒番"

        End If

    End If

    Result = Judge

    If Result = 1 Then
        Cells(2, 6) = "黒の勝ち"

    ElseIf Result = 2 Then
        Cells(2, 6) = "白の勝ち"

    ElseIf Result = 3 Then
        Cells(2, 6) = "引き分け"

    End If

End Sub

'勝敗を判定する関数
Function Judge()

'    黒が3つ並んでいるか
    If Cells(2, 2) = "●" And Cells(2, 3) = "●" And Cells(2, 4) = "●" Then
        Judge = 1
    ElseIf Cells(3, 2) = "●" And Cells(3, 3) = "●" And Cells(3, 4) = "●" Then
        Judge = 1
    ElseIf Cells(4, 2) = "●" And Cells(4, 3) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 2) = "●" And Cells(3, 2) = "●" And Cells(4, 2) = "●" Then
        Judge = 1
    ElseIf Cells(2, 3) = "●" And Cells(3, 3) = "●" And Cells(4, 3) = "●" Then
        Judge = 1
    ElseIf Cells(2, 4) = "●" And Cells(3, 4) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 2) = "●" And Cells(3, 3) = "●" And Cells(4, 4) = "●" Then
        Judge = 1
    ElseIf Cells(2, 4) = "●" And Cells(3, 3) = "●" And Cells(4, 2) = "●" Then
        Judge = 1

'    白が3つ並んでいるか
    ElseIf Cells(2, 2) = "○" And Cells(2, 3) = "○" And Cells(2, 4) = "○" Then
        Judge = 2
    ElseIf Cells(3, 2) = "○" And Cells(3, 3) = "○" And Cells(3, 4) = "○" Then
        Judge = 2
    ElseIf Cells(4, 2) = "○" And Cells(4, 3) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 2) = "○" And Cells(3, 2) = "○" And Cells(4, 2) = "○" Then
        Judge = 2
    ElseIf Cells(2, 3) = "○" And Cells(3, 3) = "○" And Cells(4, 3) = "○" Then
        Judge = 2
    ElseIf Cells(2, 4) = "○" And Cells(3, 4) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 2) = "○" And Cells(3, 3) = "○" And Cells(4, 4) = "○" Then
        Judge = 2
    ElseIf Cells(2, 4) = "○" And Cells(3, 3) = "○" And Cells(4, 2) = "○" Then
        Judge = 2

    End If

'    黒または白の勝ちの場合
    If Judge = 1 Or Judge = 2 Then

'        途中終了
        Exit Function

    End If

    Dim Gyou, Retu

'    空白マスがあるか確認する
    For Gyou = 2 To 4
        For Retu = 2 To 4

            If Cells(Gyou, Retu) = "" Then
                Judge = 4
            End If

        Next Retu
    Next Gyou

'    全てのマスが埋まっている場合
    If Judge <> 4 Then
        Judge = 3
    End If

End Function
```

前：【三目並べ：5. コードにコメントを入れる】
https://qiita.com/sano192/items/d8f124a61211efc86085

次：【三目並べ：7. テストする】
https://qiita.com/sano192/items/89a59afd45c5659e3574