Introduction
I have a cube assembly puzzle that I could not solve. The parts of the puzzle have been laying around loose for years. It appeared to be an ideal project to improve my programming skills.
The user interface is a Windows Form. First, encapsulate the routines in a puzzle class. Then, in the form code, I can instantiate the class by:
Private d = New cubepuzzle
In the cubepuzzle
class, we have:
Public part As New Bitmap(1301, 501, Drawing.Imaging.PixelFormat.Format24bppRgb)
The dimensions are chosen to give nice even numbers for the program to work with. It will fit into a PictureBox
on the form.
Using the Code
When the form loads, we have:
d.wide = Me.Width d.high = Me.Height
The puzzle class uses the user form information to set the dimensions of the PictureBox
so that it will be the the same size for any user screen resolution.
Dim partbox As New PictureBox partbox = d.picbox(True) Me.Controls.Add(partbox)
We now have the PictureBox
on the form, but we need to link to mouse_move
and then fill the box with the user entry display.
AddHandler partbox.MouseMove, AddressOf partbox_MouseMove partbox.Image = d.partentrymap
In the partbox_MouseMove
event, we use the position and left and right click to provide the part configuration to the puzzle class:
If e.Button = Windows.Forms.MouseButtons.Left Then C_left = True If e.Button =
Windows.Forms.MouseButtons.Right Then C_right = True d.shaderect(e.Y, e.X, C_left,
C_right)
When the part is correct, the user selects the enter part to program. Here, we save a copy of the part display in a reduced size to the form. Up to 7 parts can be input:
Dim partbox As New PictureBox partbox =
d.picbox(False) Me.Controls.Add(partbox) d.enter_part() partbox.Image =
d.partentrymap.clone
When all parts have been input, the user selects to solve the puzzle, and we:
d.solve_puzzle()
The puzzle may take some time and lots of CPU time, so I start a worker thread with a low priority to do the calculations. This is to go through every combination to find one that works. The user can use the computer without loss of performance, but whenever it's free, it can run the worker thread. XP keeps the CPU at 100%, but Vista runs at 60% while the thread is working. Why only 60%??
The worker thread keeps a count down going, and updates this in the part bitmap. The worker thread cannot update the Windows control, so a timer keeps the display updated in the main thread. To prevent the worker thread accessing the bitmap while the PictureBox
is being refreshed, it is wrapped in:
SyncLock part
Windows controls are not thread safe, so to prevent clash with the worker, the refresh is also wrapped in SyncLock d.part
.
Finally, the solution is displayed on the form, or a message of no solution is displayed.