]]] 8パズル・ゲーム [[[ プログラミング実習(VB)  
Microsoft Visual Basic 2010 Express Edition

8パズル・ゲーム(15パズル・ゲーム)

 15パズルは、スライディングブロックパズル(Sliding puzzle)のひとつである。4×4のボードの上に4×4-1すなわち15枚の駒があり、1駒ぶんの空きを利用して駒をスライドし、駒を目的の配置にする。3×3のボード上で8枚の駒で同様に遊ぶものは8パズルと呼ばれる。 ウィキペディアより

オブジェクトを配列で管理する

 同じような働きをするボタンオブジェクトが複数ある時、これらのオブジェクトを配列で管理すると便利な場合が多い。図のように9個のボタンがあるとき、ボタンにはButton1〜Button9の名前が自動的につけられる。この時、1番のボタンと残りのボタンのx座標(Leftプロパティ)を比較して、1つだけある同じx座標のボタンを探すコードは次のようになる。
If Button1.Left = Button2.Left Then
  MessageBox.Show("1と2が同じ")
ElseIf Button1.Left = Button3.Left Then
  MessageBox.Show("1と3が同じ")
      ………
ElseIf Button1.Left = Button8.Left Then
  MessageBox.Show("1と8が同じ")
Else
  MessageBox.Show("1と9が同じ")
End If
ボタンを配列BTNに格納しておくと、同じコードが次のように、繰返しが使える。
For n = 2 To 9
  If BTN(1).Left = BTN(n).Left Then
    MessageBox.Show("1と" & n.ToString & "が同じ")
  End If
Next
ボタン以外のオブジェクトでも同じ方法が使える。

 

1 デザイン

8パズル・ゲームのデザインフォーム
 Text = 8パズル・ゲーム
 Font.Size = 11
 
ボタン 9個
 (Name) = button1 〜 button9
 Text = 1,2,3,4,5,6,7,8,9(番号1〜9)
 Size = 75,75
 Font.Size = 32
 
ボタン 1個
 (Name) = btnKaishi
 Text = 開始
 Size = 80,36

 

2 ボタンオブジェクトの管理

(1) メンバ変数の宣言

 メンバ変数とは、全てのメソッド(サブルーチン)から参照できる(使用できる)変数である。この変数をオブジェクトの管理用に宣言する。

Public Class Form1
  '複数のボタンを配列で管理する。
  Dim btnTile(9) As Button '1〜9のボタン用の配列
  Dim Kaisuu As Integer '移動回数カウント用
  Dim InitX(9), InitY(9) As Integer 'ボタンの初期座標(答え合わせ用)

(2) オブジェクトの管理

@ ボタンを配列btnTileに格納する。
A ボタンを整列する(座標の計算)。ボタンの初期座標を記憶する(答え合わせ用)。ボタンのイベントハンドラを設定する。
B 9番タイルを非表示にする

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim n As Integer
    '9個のボタンオブジェクトを配列に格納 ←@
    btnTile(1) = Button1
    btnTile(2) = Button2
    btnTile(3) = Button3
    btnTile(4) = Button4
    btnTile(5) = Button5
    btnTile(6) = Button6
    btnTile(7) = Button7
    btnTile(8) = Button8
    btnTile(9) = Button9
    '9個のボタンの設定 ←A
    For n = 1 To 9
      'ボタン初期座標の計算
      btnTile(n).Left = ((n - 1) Mod 3) * btnTile(1).Width + 15
      btnTile(n).Top = Int((n - 1) / 3) * btnTile(1).Height + 15
      'ボタン初期座標の格納
      InitX(n) = btnTile(n).Left
      InitY(n) = btnTile(n).Top
      'イベントハンドラの登録
      AddHandler btnTile(n).Click, AddressOf btnTile_Click
    Next                                   ↑この部分はエラー
    '9番のボタンを非表示にする
    btnTile(9).Visible = False
  End Sub

 イベントハンドラとは、イベントの発生によって動作するメソッドのことである。イベントハンドラの登録とは、オブジェクトのイベントとメソッドを対応付けるものである。
 次の命令は、btnTile(n).Clickイベントの発生でbtnTile_Clickメソッドを動作するように対応付けるものである。
AddHandler btnTile(n).Click, AddressOf btnTile_Click

 

3 ボタンをクリックしたときの処理

(1) イベントハンドラの準備

 ボタンbtnTile(1)〜btnTile(9)のどれかをクリックするとイベントハンドラbtnTile_Clickが実行される。このイベントハンドラは、ユーザが設定したものであるから、メソッドの定義部分"Private Sub btnTile_Click( … )"を自動的には用意してくれない。
 まずは、次のようにイベントハンドラbtnTile_Clickを準備する。

Public Class Form1
  '複数のボタンを配列で管理する。
  Dim btnTile(9) As Button '1〜9のボタン用の配列
  << 略 >>
 
  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim n As Integer
    << 略 >>
  End Sub
 
  Private Sub btnTile_Click( Form1_Loadのカッコ内下線部と同じ ) ←追加

  End Sub
End Class

(2) ボタンがクリックされた時の処理

@ 何番のボタンがクリックされたか調べる。
A そのボタンが移動可能かどうか調べる。
  →移動可能→ 移動する。
  →移動不可→ イベント待機。
B 完成したかどうか調べる。
  →完成した→ 完成メッセージを表示する。
  →未完成→ イベント待機。

 パズルが完成した時、何回で完成したかなどを記録処理なども考えられるが、…

 

4 クリックされたボタンの番号

 9番のボタンは非表示にしているので、調べるボタンは1番〜8番でよい。
 引数senderのEqualsメソッドでクリックされたボタンを調べる。

  Private Sub btnTile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim n As Integer
    For n = 1 To 8
      If sender.Equals(btnTile(n)) = True Then
        MessageBox.Show(n.ToString & "番のボタン")
      End If
    Next
  End Sub

 

5 移動できるか調べる & 移動する

 クリックされたボタンの上下左右のどこかに9番のボタンがあれば、その場所に移動できる。この時、クリックされたボタンと9番ボタンを入れ替えれば移動が完了する。
 これらの処理はプログラム長くなるので、別のメソッドを用意する。

メソッド  IsMoveTile(調べるボタンの番号) As Boolean
返却値   True = 移動完了/False = 移動できず
※ Function 〜 End Functionは、返却値のあるメソッドの定義である。返却値は、Retrun命令で設定する。

  Private Function IsMoveTile(ByVal TileNum As Integer) As Boolean
    'TileNum番のボタンが移動可能かどうかを調べ、
    ' 移動可能であれば移動して、Trueを返却する。
    ' 移動できなければ、Falseを返却する。
    '移動の可否は、TileNum番の上下左右のどこかに9番のボタンがあるかどうかで
    '決める。あれば、移動可能ということになる。
    Dim work As Integer 'データ入れ替え用
    'TileNum番の上
    If btnTile(TileNum).Top - btnTile(1).Height = btnTile(9).Top _
    And btnTile(TileNum).Left = btnTile(9).Left Then
      work = btnTile(TileNum).Top    'タイル9番と入れ替え
      btnTile(TileNum).Top = btnTile(9).Top
      btnTile(9).Top = work
    'TileNum番の下
    ElseIf btnTile(TileNum).Top + btnTile(1).Height = btnTile(9).Top _
    And btnTile(TileNum).Left = btnTile(9).Left Then
      work = btnTile(TileNum).Top    'タイル9番と入れ替え
      btnTile(TileNum).Top = btnTile(9).Top
      btnTile(9).Top = work
    'TileNum番の左
    ElseIf btnTile(TileNum).Top = btnTile(9).Top _
    And btnTile(TileNum).Left - btnTile(1).Width = btnTile(9).Left Then
      work = btnTile(TileNum).Left    'タイル9番と入れ替え
      btnTile(TileNum).Left = btnTile(9).Left
      btnTile(9).Left = work
    'TileNum番の右
    ElseIf btnTile(TileNum).Top = btnTile(9).Top _
    And btnTile(TileNum).Left + btnTile(1).Width = btnTile(9).Left Then
      work = btnTile(TileNum).Left    'タイル9番と入れ替え
      btnTile(TileNum).Left = btnTile(9).Left
      btnTile(9).Left = work
    Else    '移動不可
      Return False    '返却値。(移動不可)
    End If
    Return True    '返却値。(移動可能、移動済み)
  End Function

 

6 移動処理を組み込む

 クリックされたボタンの番号がわかれば、移動処理をするメソッドIsMoveTileで調べることができる。この処理をボタンのイベントハンドラbtnTile_Clickに組み込む。(下線部を追加)

  Private Sub btnTile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim n As Integer
    For n = 1 To 8
      If sender.Equals(btnTile(n)) = True Then
        'MessageBox.Show(n.ToString & "番のボタン")  ←不要なのでコメントに。
        If IsMoveTile(n) = True Then    '移動の可否を調べる
          Kaisuu = Kaisuu + 1    '移動回数カウント
          lblKaisuu.Text = "移動回数:" & Kaisuu.ToString & "回"
        End If
      End If
    Next
  End Sub

 ここまでで、8個のボタンをクリックすると、空いている場所があれば、その場所に移動するようになる。

 

7 ゲーム開始の処理 [開始]ボタン

 実行直後は、1から8までボタンは整列している。ゲーム開始ボタンをクリックするとボタンの並びがランダムになり、ゲームが始められるようにする。
 ボタンをまったくのでたらめに並べると、完成させることができない場合が起こるのて、整列している状態から移動させてランダムな並びになるようにする。

  Private Sub btnKaishi_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnKaishi.Click
    Dim Ransuu As New System.Random    '乱数オブジェクトの作成
    Dim mae As Integer = 0    '前に移動したタイル番号
    Dim rd As Integer        '乱数データ(整数1-8)
    Dim n As Integer
 
    For n = 0 To 30    '移動回数 30回
      Do '永久ループ
        rd = Ransuu.Next(1, 9)    '乱数(移動するタイル番号)の生成
        If mae <> rd Then      '前の番号と違う
          If IsMoveTile(rd) = True Then    '移動できた
            mae = rd    '移動したタイル番号を記憶しておく
            Exit Do     '永久ループ脱出
          End If
        End If
      Loop
    Next
 
    Kaisuu = 0    '移動回数の初期化
    lblKaisuu.Text = "移動回数:" & Kaisuu.ToString & "回"
  End Sub

 

8 完成したかどうか調べる(ゲームクリア)

 最後に、パズルが整列(完成)したかどうかを調べる。この処理も別のメソッドで用意する。

メソッド  IsGameClear( ) As Boolean
返却値   True = 完成/False = 未完成

  Private Function IsGameClear() As Boolean
    Dim n As Integer
    For n = 1 To 9
      If btnTile(n).Left <> InitX(n) Or btnTile(n).Top <> InitY(n) Then
        '未完成
        Return False    '返却値
      End If
    Next
    '完成(クリア)
    Return True    '返却値
  End Function

 完成したかどうかは、ボタンをクリックした後に調べることにし、完成していたらメッセージを表示するようにする。(下線部を追加)

  Private Sub btnTile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    Dim n As Integer
    For n = 1 To 8
      If sender.Equals(btnTile(n)) = True Then
        'MessageBox.Show(n.ToString & "番のボタン")
        If IsMoveTile(n) = True Then '移動の可否を調べる
          Kaisuu = Kaisuu + 1 '移動回数カウント
          lblKaisuu.Text = "移動回数:" & Kaisuu.ToString & "回"
        End If
      End If
    Next
 
    'クリアの判定
    If IsGameClear() = True Then
      MessageBox.Show(Kaisuu.ToString & "回で完成しました。", "8パズル")
    End If
  End Sub

 

  Microsoft Visual Basic 2010 Express Edition
]]] 8パズル・ゲーム [[[ Copyright©2014 Hiroshi Masuda 

 

 

 

inserted by FC2 system