The Tower of Hanoi is a puzzle game where you have to move all the disks from one rod to another, stacked in descending order of size (largest at the bottom, smallest on top) using as few moves as possible. Taking out one disk from a rod and placing it on another rod counts as one move. There are, in the basic configuration, three rods and four disks. Additionally, larger disks cannot be stacked on top of smaller disks.
For the first part of this tutorial, let's focus on drawing the rods and disks. Honestly, that's the easy part. First, let's assume that the background is black. If you really want, you can use a variable for that, but I'm just going to go with black.
Let's start with drawing the bases. The bases will be a nice brown color. That's 6 in QBasic. Here, we implement the action as a subroutine drawbase(), that accepts a parameter stackno. We'll put in a call to drawbase(), adding an argument of "1", to test.
drawbase 1
SUB drawbase (stackno)
END SUB
SUB drawbase (stackno)
END SUB
Set the foreground to black and the background to brown. Then print three brown spaces, followed by stackno, followed by another three brown spaces. Reset the colors at the end of the subroutine.
SUB drawbase (stackno)
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
This is what you should have. Simple enough, right?
EDITOR'S NOTE: The following screenshot is incorrect because I neglected to reset the colors originally. You should really be seeing "Press any key to continue" in white text on black background.
Now, delete the call to drawbase(), create a call to drawpiece() instead (using the same argument of "1") and create another subroutine, drawpiece(). This will accept the parameter pieceno.
drawpiece 1
SUB drawpiece (pieceno)
END SUB
SUB drawbase (stackno)
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
SUB drawpiece (pieceno)
END SUB
SUB drawbase (stackno)
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
Also, define the array piece. Then initialize the values. Each element in the piece array represents a disk. See how the smallest one is 1, followed by 2, and so on? The number of spaces also corresponds to the number of the disk. For instance, the first element of piece, piece(1), has one space on either side of the "1". For piece(2), there are two spaces on either side of the "2". This can be done programmatically, but I don't see the point since we're not reusing this anywhere.
DIM SHARED piece(4) AS STRING
piece(1) = " 1 "
piece(2) = " 2 "
piece(3) = " 3 "
piece(4) = " 4 "
drawpiece 1
SUB drawpiece (pieceno)
END SUB
piece(1) = " 1 "
piece(2) = " 2 "
piece(3) = " 3 "
piece(4) = " 4 "
drawpiece 1
SUB drawpiece (pieceno)
END SUB
Now drawpiece() will print black spaces in front and back, just like in drawbase(). However, unlike drawbase(), the size of the piece varies according to the number. The bigger the number, the bigger the piece, and therefore the smaller the black spaces. The largest piece is piece(4), so piece(4) will have (5 - 4 = 1) black space preceding and after it. The smallest piece, piece(1), will have (5 - 1 = 4) black spaces.
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
Next, we cater for a case of pieceno being 0. When that happens, you print a single brown space, to indicate that this section of rod has no disks, and it's all rod.
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
And if pieceno is not 0, which means there is a disk on that section of rod, you draw the element of the piece array referenced by pieceno. For the color of the disk, we'll just use the color that pieceno represents in the QBasic color table. piece(1) will be blue, piece(2) will be green, piece(3) will be yellow and piece(4) will be red.
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
END SUB
After that, reset the colors.
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 15, 0
END SUB
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 15, 0
END SUB
Now let's test the subroutine!
drawpiece 1
drawpiece 2
drawpiece 3
drawpiece 4
drawpiece 0
drawpiece 2
drawpiece 3
drawpiece 4
drawpiece 0
As expected.
Now delete the test statements. And write a new subroutine, drawstack(). This one will leverage off the subroutine, drawbase(), that we created earlier.
SUB drawbase (stackno)
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
SUB drawstack ()
END SUB
COLOR 0, 6
FOR i = 1 TO 3
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 3
PRINT " ";
NEXT
COLOR 15, 0
END SUB
SUB drawstack ()
END SUB
The entire stack contains three bases and three rods. Counting the bases, it will be 6 spaces high. So create a For loop iterating from 1 to 6. Within it, send the cursor to a y value of (i + 1) and an x value of 2. The x value is to allow some space at the left side of the screen.
SUB drawstack ()
FOR i = 1 TO 6
LOCATE i + 1, 2
NEXT i
END SUB
FOR i = 1 TO 6
LOCATE i + 1, 2
NEXT i
END SUB
Define another For loop within it, iterating from 1 to 3. j will represent each base and rod.
SUB drawstack ()
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
NEXT j
NEXT i
END SUB
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
NEXT j
NEXT i
END SUB
If we're at the top of the stack (i.e, i is 1), whether or not there are disks, there will be only the rod showing. So call drawpiece(), and use 0 as an argument.
SUB drawstack ()
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
END IF
NEXT j
NEXT i
END SUB
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
END IF
NEXT j
NEXT i
END SUB
If i is not 1, then check if i is 6, which means you're now drawing the bottom of the stack. If so, draw the base by calling drawbase() and pass in j as an argument.
SUB drawstack ()
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
IF i = 6 THEN
drawbase j
ELSE
END IF
END IF
NEXT j
NEXT i
END SUB
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
IF i = 6 THEN
drawbase j
ELSE
END IF
END IF
NEXT j
NEXT i
END SUB
If i is not 1 or 6, then... well, for now let's just use drawpiece() with an argument of 0 to show what the entire setup would look like without disks.
SUB drawstack ()
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
IF i = 6 THEN
drawbase j
ELSE
drawpiece 0
END IF
END IF
NEXT j
NEXT i
END SUB
FOR i = 1 TO 6
LOCATE i + 1, 2
FOR j = 1 TO 3
IF i = 1 THEN
drawpiece 0
ELSE
IF i = 6 THEN
drawbase j
ELSE
drawpiece 0
END IF
END IF
NEXT j
NEXT i
END SUB
Now call drawstack().
drawstack
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
OK, this is a little off. Let's fix it...
In drawpiece(), add a black space after drawing.
SUB drawpiece (pieceno)
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 0, 0
PRINT " ";
COLOR 15, 0
END SUB
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
IF pieceno = 0 THEN
COLOR 0, 6
PRINT " ";
ELSE
COLOR 0, pieceno
PRINT piece(pieceno);
END IF
COLOR 0, 0
FOR i = 1 TO (5 - pieceno)
PRINT " ";
NEXT i
COLOR 0, 0
PRINT " ";
COLOR 15, 0
END SUB
Do the same for drawbase().
SUB drawbase (stackno)
COLOR 0, 6
FOR i = 1 TO 4
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 4
PRINT " ";
NEXT
COLOR 0, 0
PRINT " ";
COLOR 15, 0
END SUB
COLOR 0, 6
FOR i = 1 TO 4
PRINT " ";
NEXT
PRINT stackno;
FOR i = 1 TO 4
PRINT " ";
NEXT
COLOR 0, 0
PRINT " ";
COLOR 15, 0
END SUB
Ladies and gentlemen, your rods and bases!
No comments:
Post a Comment