📄 mainform.vb
字号:
Public Class MainForm
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Panel1 As System.Windows.Forms.Panel
Friend WithEvents cmdSolve As System.Windows.Forms.Button
Friend WithEvents cmdPlay As System.Windows.Forms.Button
Friend WithEvents txtShuffleNum As System.Windows.Forms.TextBox
Friend WithEvents cmdShuffle As System.Windows.Forms.Button
Friend WithEvents optEight As System.Windows.Forms.RadioButton
Friend WithEvents lblStatus As System.Windows.Forms.Label
Friend WithEvents optFifteen As System.Windows.Forms.RadioButton
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.cmdSolve = New System.Windows.Forms.Button
Me.Panel1 = New System.Windows.Forms.Panel
Me.cmdPlay = New System.Windows.Forms.Button
Me.cmdShuffle = New System.Windows.Forms.Button
Me.txtShuffleNum = New System.Windows.Forms.TextBox
Me.optEight = New System.Windows.Forms.RadioButton
Me.optFifteen = New System.Windows.Forms.RadioButton
Me.lblStatus = New System.Windows.Forms.Label
Me.SuspendLayout()
'
'cmdSolve
'
Me.cmdSolve.Location = New System.Drawing.Point(133, 303)
Me.cmdSolve.Name = "cmdSolve"
Me.cmdSolve.Size = New System.Drawing.Size(73, 23)
Me.cmdSolve.TabIndex = 1
Me.cmdSolve.Text = "Solve"
'
'Panel1
'
Me.Panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D
Me.Panel1.Location = New System.Drawing.Point(2, 8)
Me.Panel1.Name = "Panel1"
Me.Panel1.Size = New System.Drawing.Size(292, 292)
Me.Panel1.TabIndex = 2
'
'cmdPlay
'
Me.cmdPlay.Enabled = False
Me.cmdPlay.Location = New System.Drawing.Point(212, 303)
Me.cmdPlay.Name = "cmdPlay"
Me.cmdPlay.Size = New System.Drawing.Size(82, 23)
Me.cmdPlay.TabIndex = 3
Me.cmdPlay.Text = "Play Solution"
'
'cmdShuffle
'
Me.cmdShuffle.Location = New System.Drawing.Point(6, 303)
Me.cmdShuffle.Name = "cmdShuffle"
Me.cmdShuffle.Size = New System.Drawing.Size(73, 23)
Me.cmdShuffle.TabIndex = 5
Me.cmdShuffle.Text = "Shuffle"
'
'txtShuffleNum
'
Me.txtShuffleNum.Location = New System.Drawing.Point(80, 303)
Me.txtShuffleNum.Name = "txtShuffleNum"
Me.txtShuffleNum.Size = New System.Drawing.Size(36, 20)
Me.txtShuffleNum.TabIndex = 6
Me.txtShuffleNum.Text = "10"
'
'optEight
'
Me.optEight.Checked = True
Me.optEight.Location = New System.Drawing.Point(17, 329)
Me.optEight.Name = "optEight"
Me.optEight.Size = New System.Drawing.Size(59, 24)
Me.optEight.TabIndex = 7
Me.optEight.TabStop = True
Me.optEight.Text = "Eight"
'
'optFifteen
'
Me.optFifteen.Location = New System.Drawing.Point(17, 348)
Me.optFifteen.Name = "optFifteen"
Me.optFifteen.Size = New System.Drawing.Size(104, 24)
Me.optFifteen.TabIndex = 8
Me.optFifteen.Text = "Fifteen"
'
'lblStatus
'
Me.lblStatus.Location = New System.Drawing.Point(82, 335)
Me.lblStatus.Name = "lblStatus"
Me.lblStatus.Size = New System.Drawing.Size(202, 33)
Me.lblStatus.TabIndex = 9
'
'MainForm
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(296, 377)
Me.Controls.Add(Me.lblStatus)
Me.Controls.Add(Me.optFifteen)
Me.Controls.Add(Me.optEight)
Me.Controls.Add(Me.txtShuffleNum)
Me.Controls.Add(Me.cmdShuffle)
Me.Controls.Add(Me.cmdPlay)
Me.Controls.Add(Me.Panel1)
Me.Controls.Add(Me.cmdSolve)
Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog
Me.MaximizeBox = False
Me.Name = "MainForm"
Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
Me.Text = "Sliding Puzzle Solver"
Me.ResumeLayout(False)
Me.PerformLayout()
End Sub
#End Region
Private mRootState As PuzzleState
Private mSolution As ArrayList
Private mSolveStep As Integer
Private mTiles() As Button
Private mTileMax As Integer
Private mRowWidth As Integer
Const GoalState8 As String = "010203080004070605"
Const GoalState15 As String = "01020304050607080910111213141500"
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
optEight.Checked = True
End Sub
Private Sub cmdSolve_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdSolve.Click
Dim ps, psChild As PuzzleState
'Maintains a sorted list of PuzzleState nodes, sorted by cost
Dim Queue As New PriorityQueue2()
Dim i, j As Integer
Dim Start As Date = Now
cmdSolve.Enabled = False
'gSolver.DebugPrint(mRootState)
If gSolver.IsGoal(mRootState) Then
MsgBox("You need to shuffle before solving.")
Exit Sub
End If
Dim psNew() As PuzzleState = gSolver.GetNextStates(mRootState) 'enumerate next states
For Each psChild In psNew 'add the first lot of subnodes to the open list
psChild.CalculateCost()
Queue.Push(psChild)
Next
'Start checking the open list
ps = Queue.Pop
Do While Not ps Is Nothing
i += 1
If i Mod 100 = 0 Then
Me.Text = String.Format("{0} nodes checked", i)
Application.DoEvents()
End If
If gSolver.IsGoal(ps) Then
'We have it, set up the solution for stepping through with the play button.
lblStatus.Text = Now.Subtract(Start).ToString & " for " & i.ToString & " positions searched"
GetSolution(ps)
cmdPlay.Enabled = True
mSolveStep = mSolution.Count - 1
Exit Do
Else
'if the node is not the goal state, then get the next possible moves and add them
'to the open list
psNew = gSolver.GetNextStates(ps)
For Each psChild In psNew
If Not ps.Parent.Equals(psChild) Then 'don't add if we're going around in circles
psChild.CalculateCost()
Queue.Push(psChild)
End If
Next
End If
'Get the next node from the open list to check
ps = Queue.Pop
Loop
cmdSolve.Enabled = False
cmdShuffle.Enabled = True
End Sub
Private Sub GetSolution(ByVal ps As PuzzleState)
Debug.WriteLine("SOLUTION")
gSolver.DebugPrint(ps)
mSolution = New ArrayList
Do While Not ps.Parent Is Nothing
mSolution.Add(ps)
ps = ps.Parent
Loop
End Sub
Private Sub StateToForm(ByVal ps As PuzzleState)
Dim ButtonSize As Size = mTiles(0).Size
For i As Integer = 0 To mTileMax
If ps.Tile(i) > 0 Then
'Debug.WriteLine(ps.Tile(i))
mTiles(ps.Tile(i) - 1).Left = (i Mod mRowWidth) * ButtonSize.Width + 1
mTiles(ps.Tile(i) - 1).Top = (i \ mRowWidth) * ButtonSize.Height + 1
End If
Next
End Sub
Private Sub cmdPlay_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPlay.Click
Dim ps As PuzzleState
'We have to walk backwards through the solution since the goal state is at index 0
If mSolveStep < 0 Then Exit Sub
ps = DirectCast(mSolution(mSolveStep), PuzzleState)
StateToForm(ps)
mSolveStep -= 1
End Sub
Private Sub cmdShuffle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdShuffle.Click
Dim ShuffleNum As Integer
GC.Collect() 'this program can blow out memory pretty quickly... makes sense to manage before it becomes a problem
If IsNumeric(Me.txtShuffleNum.Text) Then
ShuffleNum = CInt(txtShuffleNum.Text)
If ShuffleNum > 30 Then
If MsgBox("Numbers larger than 30 can consume large amounts of memory and take a long time. Do you wish to continue?", MsgBoxStyle.YesNo) = MsgBoxResult.No Then
Exit Sub
End If
End If
Else
MsgBox("Enter the number of steps to shuffle by.")
Exit Sub
End If
If mRowWidth = 4 Then
mRootState = New PuzzleState(mTileMax, GoalState15, 0)
Else
mRootState = New PuzzleState(mTileMax, GoalState8, 0)
End If
mRootState = gSolver.Shuffle(mRootState, ShuffleNum)
StateToForm(mRootState)
cmdShuffle.Enabled = False
cmdPlay.Enabled = False
cmdSolve.Enabled = True
lblStatus.Text = String.Empty
End Sub
Private Sub optEight_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles optEight.CheckedChanged
If optEight.Checked Then
Init(8)
End If
End Sub
Private Sub Init(ByVal Num As Integer)
Dim i As Integer
Dim ButtonSize As Size
mTileMax = Num
mRowWidth = CInt(Math.Sqrt(mTileMax + 1))
If mRowWidth = 4 Then
ButtonSize = New Size(72, 72)
Else
ButtonSize = New Size(96, 96)
End If
ReDim mTiles(mTileMax - 1)
Panel1.Controls.Clear()
For i = 0 To mTileMax - 1
mTiles(i) = New Button
'AddHandler mTiles(i).Click, AddressOf Tile_Click
mTiles(i).Tag = i + 1
mTiles(i).Text = (i + 1).ToString
mTiles(i).Parent = Panel1
mTiles(i).Font = New Font("MS Sans Serif", 24)
mTiles(i).Size = ButtonSize
mTiles(i).Visible = True
mTiles(i).Left = (i Mod mRowWidth) * ButtonSize.Width + 1
mTiles(i).Top = (i \ mRowWidth) * ButtonSize.Height + 1
Next
If mRowWidth = 4 Then
gSolver = New Solver(mTileMax, GoalState15)
mRootState = New PuzzleState(mTileMax, GoalState15, 0)
Else
gSolver = New Solver(mTileMax, GoalState8)
mRootState = New PuzzleState(mTileMax, GoalState8, 0)
End If
gSolver.DebugPrint(mRootState)
StateToForm(mRootState)
cmdShuffle.Enabled = True
cmdSolve.Enabled = False
cmdPlay.Enabled = False
lblStatus.Text = String.Empty
End Sub
Private Sub optFifteen_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles optFifteen.CheckedChanged
If optFifteen.Checked Then
Init(15)
End If
End Sub
End Class
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -