]]] 8パズル・ゲーム [[[ | プログラミング実習(VB) |
Microsoft Visual Basic 2010 Express Edition |
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
ボタン以外のオブジェクトでも同じ方法が使える。
フォーム
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
(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
(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 完成したかどうか調べる。
→完成した→ 完成メッセージを表示する。
→未完成→ イベント待機。
パズルが完成した時、何回で完成したかなどを記録処理なども考えられるが、…
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
クリックされたボタンの上下左右のどこかに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
クリックされたボタンの番号がわかれば、移動処理をするメソッド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個のボタンをクリックすると、空いている場所があれば、その場所に移動するようになる。
実行直後は、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
最後に、パズルが整列(完成)したかどうかを調べる。この処理も別のメソッドで用意する。
メソッド 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 |