このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。

【6日でできるVisual Basic2022入門】⑤間違い漢字探しゲーム:コードの実装と実行

⑤間違い漢字探しゲーム:コードの実装と実行

 本章では、4×4盤の間違い漢字探しをコードで完成させます。「スタート」ボタンのクリックで出題ペア(糊/湖・話/語・録/緑・潮/朝・倍/培・崎/﨑)を抽選し、16マスを間違い文字で埋め、1マスだけ正解を配置。Timer1 を開始して経過秒を 0.00 形式で更新します。盤面は OfType+AddHandler で共通 Buttons_Click に集約。正解で Stop+記録表示、不正解は +2.00 秒加算。Random.Next、Select Case、Timer.Tick を用い、「スタート」ボタンの有効/無効切替や Enter 実行も整えます。

5.間違い漢字探しゲーム:コードの実装と実行

5.1. 実装仕様の再確認

項目仕様
盤面4×4=16マス(Button1〜Button16)
出題6組の「似た漢字」から1組を抽選し、間違い文字で全マスを埋め、1マスだけ正解文字
計時「スタート」ボタン で Timer1 開始、0.02秒刻みで秒数更新(表示は 0.00 形式)
クリック処理正解→タイマー停止・記録表示/不正解→ペナルティ +2.00 秒加算
操作性実行中は 「スタート」ボタンの無効化、終了で再度有効化(Enter=AcceptButton)

メモ:フォントにより「崎/﨑」が同じ形に見える場合があります。その場合はこのペアを一時除外するか、別ペアに差し替えてください(例:未/末 など)。

5.2. 使用データ(出題ペア)と変数

変数/定数役割
pairs配列(タプル)出題ペア(wrong:間違いで全体、right:正解で1マス)
rndRandom乱数(正解位置・出題ペアの抽選)
currentWrong / currentRightString今回の出題漢字(2種)
elapsedDouble経過秒
runningBooleanラウンド中フラグ

出題ペア(本章では6組を使用)

  • 糊/湖、話/語、録/緑、潮/朝、倍/培、崎/﨑

5.3. 処理フロー(テキスト図)

「スタート」ボタンのクリック
  ├─ 出題ペアを抽選 → currentWrong/currentRight をセット
  ├─ 16マスをすべて wrong に
  ├─ ランダムな 1 マスだけ right に
  ├─ elapsed=0 → Timer.Start → running=True → 「スタート」ボタンの無効化
  └─ 表示更新(TextHunt, TextTimer)

盤面ボタンクリック(共通ハンドラー)
  ├─ running でなければ無視
  ├─ そのボタンが right?
  │     ├─ Yes: Timer.Stop、running=False、「スタート」ボタンの有効化、記録を表示
  │     └─ No : elapsed += 2.0(ペナルティ)
  └─ TextTimer を 0.00 形式で更新

Timer1.Tick(20ms 推奨)
  ├─ elapsed += Interval/1000.0
  └─ TextTimer 更新(0.00)

5.4. 完成コード(FormKanjiHunt.vb)

前章までのコントロール名を前提:SplitContainer1(Panel1上段/Panel2下段)、TextHuntTextTimerButtonStart、盤面 Button1~Button16Timer1(Interval=20)。

Option Strict On
Imports System.Drawing
Imports System.Media

Public Class FormKanjiHunt
    ' ① 出題ペア(wrong:間違いで埋める、right:正解で1マスだけ)
    Private ReadOnly pairs As (wrong As String, right As String)() = {
        (wrong:="糊", right:="湖"),
        (wrong:="話", right:="語"),
        (wrong:="録", right:="緑"),
        (wrong:="潮", right:="朝"),
        (wrong:="倍", right:="培"),
        (wrong:="崎", right:="﨑")
    }

    ' ② ランダムはクラス共通で使い回し
    Private Shared ReadOnly rnd As New Random()

    ' ③ ラウンド状態
    Private currentWrong As String = ""
    Private currentRight As String = ""
    Private elapsed As Double = 0.0
    Private running As Boolean = False

    ' ④ フォーム初期化
    Private Sub FormKanjiHunt_Load(sender As Object, e As EventArgs) _
        Handles MyBase.Load

        ' Enter = Start
        Me.AcceptButton = ButtonStart

        ' 盤面ボタン(Panel2上の Button)に共通ハンドラーを割り当て
        For Each b In SplitContainer1.Panel2.Controls.OfType(Of Button)()
            AddHandler b.Click, AddressOf Buttons_Click
            b.TabStop = False
            b.Text = ""   ' 初回は空
        Next

        ' 表示初期化
        TextHunt.Text = ""
        TextTimer.ReadOnly = True
        TextTimer.Text = "0.00"
    End Sub

    ' ⑤ 「スタート」ボタンのクリック → ラウンド開始
    Private Sub ButtonStart_Click(sender As Object, e As EventArgs) _
        Handles ButtonStart.Click

        ' 出題ペアを抽選
        Dim p = pairs(rnd.Next(pairs.Length))
        currentWrong = p.wrong
        currentRight = p.right

        ' 探す文字を表示
        TextHunt.Text = currentRight

        ' まず全マスを「間違い」で埋める
        Dim cells = SplitContainer1.Panel2.Controls.OfType(Of Button)().ToList()
        For Each b In cells
            b.Text = currentWrong
            b.Enabled = True
            b.BackColor = SystemColors.Control
        Next

        ' ランダムな1マスだけ「正解」にする
        Dim idx = rnd.Next(cells.Count)
        cells(idx).Text = currentRight

        ' タイマー開始
        elapsed = 0.0
        TextTimer.Text = "0.00"
        Timer1.Start()
        running = True

        ' Start は実行中は無効化
        ButtonStart.Enabled = False
    End Sub

    ' ⑥ 盤面ボタン(共通ハンドラー)
    Private Sub Buttons_Click(sender As Object, e As EventArgs)
        If Not running Then Return

        Dim b = DirectCast(sender, Button)

        If b.Text = currentRight Then
            ' 正解:停止して記録表示
            Timer1.Stop()
            running = False
            ButtonStart.Enabled = True
            SystemSounds.Asterisk.Play()
            MessageBox.Show($"正解!タイム:{elapsed:0.00} 秒", "お見事")
        Else
            ' 不正解:+2秒ペナルティ(軽いフィードバック)
            elapsed += 2.0
            b.BackColor = Color.MistyRose
            SystemSounds.Beep.Play()
            TextTimer.Text = elapsed.ToString("0.00")
        End If
    End Sub

    ' ⑦ タイマーで経過表示を更新(Interval=20ms 推奨)
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) _
        Handles Timer1.Tick

        elapsed += Timer1.Interval / 1000.0
        TextTimer.Text = elapsed.ToString("0.00")
    End Sub
End Class

コードの要点(番号対応)

No.位置解説
pairs6組の出題ペアを定義。配置は (wrong, right) の順で覚えると実装が簡単。
rndRandom1回だけ生成して使い回す(毎回 New すると偏ることがある)。
状態変数今回の出題文字と経過秒、実行中フラグ。
Load盤面ボタンへ AddHandler 一括割当OfType(Of Button) で Button だけ抽出。
Start全マスを間違いで埋め、ランダム1マスだけ正解に。Start を実行中は無効化。
クリック正解→停止&記録表示。不正解→elapsed += 2.0、軽く色変化でフィードバック。
TickInterval/1000.0 を積算し、0.00 形式で描画。

Dim b = DirectCast(sender, Button) の意味

1. senderの意味

 Buttons_Clickイベントハンドラの第1引数senderは、そのイベントを発生させたオブジェクトが格納されます。
この場合は「どのボタンがクリックされたか」がsenderに入っています。

 型はObject型なので、そのままではTextBackColorといったButton特有のプロパティにアクセスできません。

2. DirectCast(sender, Button) の意味

DirectCastは、あるオブジェクトを指定した型に変換(キャスト)するためのVBの演算子です。
ここでは

Dim b = DirectCast(sender, Button)

とすることで、
sender(型はObject)を Button型に変換 し、変数bに代入しています。

5.5. VB 2022 の命令・イベント解説

要素概要本章での使いどころ
AddHandler …, AddressOf …実行時にイベントを束ねる16マスを1本の Buttons_Click で処理
Controls.OfType(Of Button)()指定型の子コントロール列挙Panel2 のボタン群へ一括処理
Random.Next(n)0〜n-1 の整数出題ペア/正解位置の抽選
Timer.Start/Stop + Tick周期的に処理を実行経過秒の更新
文字列補間 $"..."フォーマット簡潔記述記録表示 $"{elapsed:0.00}"

5.6. 実行の流れと画面イメージ

5.7. テスト観点チェックリスト

観点期待結果
正解位置のランダム性Start を繰り返すと位置が毎回変わるOK
不正解ペナルティ間違いクリックで +2.00 秒OK
タイマー精度表示が滑らかに 0.00 形式で更新OK
Start の有効/無効実行中は無効/終了で有効OK
16ボタンの共通処理どのマスでも同じロジックが実行OK

5.8. 発展(任意)

  • ベスト記録BestTime As Double? を保存し、短縮時に祝メッセージ
  • 難易度:盤面を 5×5 に、ペナルティを +1.00 / +3.00 に可変
  • 効果音SystemSounds ではなく WAV を My.Resources に置いて演出
  • 異体字対策:フォントで識別しづらいペアは除外または差し替え

まとめ

 乱数・タイマー・共通ハンドラーを組み合わせ、4×4 盤の「間違い漢字探しゲーム」が完成しました。同じ処理をボタン数だけ書かないための設計(OfTypeAddHandler)は、WinForms で大量コントロールを扱う定番テクニックです。ここからは難易度調整や演出追加、記録保存などを自由に拡張してみてください。