このページで解説している内容は、以下の 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マス) |
rnd | Random | 乱数(正解位置・出題ペアの抽選) |
currentWrong / currentRight | String | 今回の出題漢字(2種) |
elapsed | Double | 経過秒 |
running | Boolean | ラウンド中フラグ |
出題ペア(本章では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下段)、TextHunt、TextTimer、ButtonStart、盤面Button1~Button16、Timer1(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. | 位置 | 解説 |
|---|---|---|
| ① | pairs | 6組の出題ペアを定義。配置は (wrong, right) の順で覚えると実装が簡単。 |
| ② | rnd | Random は1回だけ生成して使い回す(毎回 New すると偏ることがある)。 |
| ③ | 状態変数 | 今回の出題文字と経過秒、実行中フラグ。 |
| ④ | Load | 盤面ボタンへ AddHandler 一括割当。OfType(Of Button) で Button だけ抽出。 |
| ⑤ | Start | 全マスを間違いで埋め、ランダム1マスだけ正解に。Start を実行中は無効化。 |
| ⑥ | クリック | 正解→停止&記録表示。不正解→elapsed += 2.0、軽く色変化でフィードバック。 |
| ⑦ | Tick | Interval/1000.0 を積算し、0.00 形式で描画。 |
Dim b = DirectCast(sender, Button) の意味
1. senderの意味
Buttons_Clickイベントハンドラの第1引数senderは、そのイベントを発生させたオブジェクトが格納されます。
この場合は「どのボタンがクリックされたか」がsenderに入っています。
型はObject型なので、そのままではTextやBackColorといった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 盤の「間違い漢字探しゲーム」が完成しました。同じ処理をボタン数だけ書かないための設計(OfType+AddHandler)は、WinForms で大量コントロールを扱う定番テクニックです。ここからは難易度調整や演出追加、記録保存などを自由に拡張してみてください。
