0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自分が以前作ったExcelを使用したゲームをアップデートしてみた

Posted at

はじめに

 数年前に作ったマインスイーパをアップデートして作り変えました。

 今回追加した機能は下記の通りです。
・地雷以外のマスをすべて開くとクリアになる
・クリア時に爆弾を表示して他のセルをクリックできないように変更
・爆弾を引いた時に他のセルをクリックできないように変更
・数式バーを強制的に非表示に変更
・リセットボタンをセルからボタンに変更
・爆弾の数とマスのサイズを自分で自由に設定できるように変更

 一個ずつ見ていきましょう。

1.クリア判定

 爆弾以外の全てのマスを開くと、全ての爆弾が緑になりクリアとなります。
minesweeper1.png

vb
Private Sub CheClear()
    Dim CCount As Integer       ' 開いていないセル数
    Dim idx_row As Integer      ' 行インクリメント
    Dim idx_clm As Integer      ' 列インクリメント
    
    For idx_row = 2 To (conVertical + 1)
        For idx_clm = 2 To (conHorizonal + 1)
            If Cells(idx_row, idx_clm).Interior.Color = RGB(200, 200, 200) Then
                CCount = CCount + 1
            End If
        Next
    Next
    
    ' 開いていないセル数が爆弾数以下の場合クリア
    If CCount <= conBombs Then
        For idx_row = 2 To (conVertical + 1)
            For idx_clm = 2 To (conHorizonal + 1)
                ' セルが爆弾の場合
                If Cells(idx_row, idx_clm).Value = "●" Then
                    Cells(idx_row, idx_clm).Interior.Color = RGB(150, 150, 150)
                    Cells(idx_row, idx_clm).NumberFormatLocal = ""
                    Cells(idx_row, idx_clm).Font.Color = RGB(50, 200, 50)
                End If
            Next        'idx_clm
        Next            'idx_row
            
        ' セルを編集不可に変更
        Range("B2").Resize(conVertical, conHorizonal).Locked = True
    End If
    
End Sub

 開いていないセルの数を数えて、その数が爆弾の数以下の場合クリアとしています。(もっとスマートな方法がありそうだけど……)
 クリア時はセルの編集を不可にしています。LockedというパラメータがあるのでTrueにすれば編集不可になります。リセットボタンを押した時にLockedをFalseにして制御しています。

ちなみに、クリア時と同様に爆弾を引いた時もLockedをTrueにしてセルの編集を不可にしています。

2.数式バーを非表示にする

 Excelを使用した弊害で、実はセルを複数選択することが可能になっています。
 一応、セルを複数選択した時は処理を全て抜けるようには作ってあるのですが、
minesweeper2.png
 複数選択した後の最後のマスの中身が見えてしまっています。

 正直、Excelを使っている以上、複数選択はどうしようもないのでどうしようか悩んだのですが……
minesweeper3.png
 消しちゃえ☆

 ……っていう結論に至りました。
 コードは至ってシンプル。

vb
 Application.DisplayFormulaBar = False

 ボタンを押す度にこの一文で強制的に数式バーを非表示にするだけ。簡単ですね。

3.爆弾の数とマスのサイズを変更できるようにする

 まずこの機能を実装するにあたって問題になったのがリセットボタンです。当初はリセットボタンをセルに配置していたため、マスのサイズを大きくした際にリセットボタンを巻き込んでしまっていました。そのため、リセットボタンをボタンに置き換えています。
 地味なところではリセットボタンを押した時にフォーカスをA1セルに移動するようにしています。

 爆弾の数とマスの変更画面はこんな感じです。
minesweeper4.png
 シートを分けました。
 無限にマスや爆弾を作られても困るので入力できる範囲を指定しています。マスは縦横それぞれ10~20。爆弾はマス数の合計の8割を最大にしています。(例:マスのサイズが10×10の場合、マスの合計は100なのでその8割である80個まで配置できる)

 数式バーの戻し方を注意書きで書いておいてあげるの、ちょっとしたやさしさを感じません?……感じない?あ、そう……。

 コードはこんな感じ。

vb
Private Sub Worksheet_Change(ByVal Target As Range)
    ' 二回目のイベントは処理をしない
    If ChangeFlg Then Exit Sub
    
    ' 描画停止
    Application.ScreenUpdating = False
    ChangeFlg = True
    
    Select Case Target.Address
        Case "$D$2"     ' 爆弾の数
            If IsNumeric(Target.Value) = False Then
                ' 数値ではない場合、15にして処理を抜ける
                Target.Value = 15
                GoTo continue2
            End If
            
            If Target.Value <= 1 Then
                ' 1以下の場合、1にして処理を抜ける
                Target.Value = 1
                GoTo continue2
            End If
            
            ' 小数の場合、整数にする
            ' 全角を半角に変換
            Target.Value = CInt(StrConv(Round(Target.Value), vbNarrow))
            
        Case "$D$3"     ' マス(縦)の数
            If IsNumeric(Target.Value) = False Then
                ' 数値ではない場合、10にして処理を抜ける
                Target.Value = 10
                GoTo continue2
            End If
            
            If Target.Value <= 10 Then
                ' 10以下の場合、10にして処理を抜ける
                Target.Value = 10
                GoTo continue2
            ElseIf Target.Value >= maxVertical Then
                ' 最大数以上の場合、最大数にして処理を抜ける
                Target.Value = maxVertical
                GoTo continue2
            End If
            
            ' 小数の場合、整数にする
            ' 全角を半角に変換
            Target.Value = CInt(StrConv(Round(Target.Value), vbNarrow))
            
        Case "$D$4"     ' マス(横)の数
            If IsNumeric(Target.Value) = False Then
                ' 数値ではない場合、10にして処理を抜ける
                Target.Value = 10
                GoTo continue2
            End If
            
            If Target.Value <= 10 Then
                ' 10以下の場合、10にして処理を抜ける
                Target.Value = 10
                GoTo continue2
            ElseIf Target.Value >= maxHorizonal Then
                ' 最大数以上の場合、最大数にして処理を抜ける
                Target.Value = maxHorizonal
                GoTo continue2
            End If
            
            ' 小数の場合、整数にする
            ' 全角を半角に変換
            Target.Value = CInt(StrConv(Round(Target.Value), vbNarrow))
            
    End Select
    
continue2:      'Exit Selectがないためcontinueに飛ばす
            
    ' 爆弾数が全マス数の8割を越える場合、爆弾数を調整
    If Range("$D$2").Value > (Range("$D$3").Value * Range("$D$4").Value * 0.8) Then
        Range("$D$2").Value = CInt(Range("$D$3").Value * Range("$D$4").Value * 0.8)
    End If
    
    ' 描画再開
    Application.ScreenUpdating = True
    ChangeFlg = False
    
End Sub

 簡単に言ってるけど判定文ちゃんとしたらこれくらいになるよねって感じ。
 一応、小数は切り捨てて、全角を半角にしてから、数値以外が入力された場合は最低数にしています。
 変更が反映されるタイミングはリセットボタンを押したタイミングです。数値入力後にいちいち切り替えるよりは動きがスムーズになるだろうとの考えから。ちゃんと数値にしてないとリセットボタン押した時に例外処理で落ちてしまいます。

 マスを大きくした画面がこんな感じ。
minesweeper5.png
 いい感じですね。

さいごに

 結局、右クリックで旗を立てる処理は諦めました。Excelで作る以上はどこかしら妥協しないといけないところは出てきますね。
 再三になりますが、こんなExcelを作って業務時間中に遊んではいけませんよ?間違っても次はテトリスとかリバーシを作ろうとか画策してるんじゃないよ?絶対だからね?

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?