As you may recall, the Sokoban board is an array of integers. A value of zero indicates an unreachable space. The other spaces can be normal (with a value of 10) or target (20). Additionally, a valid space can be empty, or contain the man (1) or a box (5). The value of a space is its base value plus its contents.
I created a simple helper class to hold a set of coordinates.
Class MPoint
Public X, Y As Int16
Public Sub New(ByVal xx As Int16, ByVal yy As Int16)
X = xx
Y = yy
End Sub
End Class
The current position of the Man is held in an MPoint called _currpos. I also created a list of direction names as follows:
Private Enum Dirs
Left
Right
Up
Down
End Enum
Using an MPoint and a direction, we can pass parameters concisely. In the OnPreviewKeyDown event, a simple test for the arrow keys determines what parameter to use, for example:
Case Keys.Left
TryMoveMan(Dirs.Left)
Then the movement handling logic tests to see that the destination is on the board, and either to an unoccupied space or a valid push.
Private Sub TryMoveMan(ByVal d As Dirs)
' Can man move to an empty square in this direction?
If (OnBoardAndVacant(_currPos, d)) Then
DoMove(_currPos, d, _MAN)
' Square is valid, but not empty (has box).
ElseIf (OnBoard(_currPos, d)) Then
Dim boxPos As MPoint = GetNewPos(_currPos, d)
' Can it be pushed?
If (OnBoardAndVacant(boxPos, d)) Then
DoMove(boxPos, d, _BOX)
DoMove(_currPos, d, _MAN)
End If
End If
End Sub
You can see what the functions should do: OnBoardAndVacant looks for a value indicating an unoccupied normal or target space. OnBoard just looks for a valid space, which can be occupied. GetNewPos returns an MPoint at the new coordinates. DoMove subtracts the piece value from its current position and adds it to its new position.
This is the bulk of the program from a logic point of view. We'll get to handling "Undo" and the display of graphics.