Maze Program for the Casio PB-1000
While experimenting with the Casio PB-770, I translated a maze algorithm to BASIC for a sample program to use for the pixel addressable LCD.
The Casio PB-1000 has a slightly larger number of pixels compared to the PB-770. The PB-1000 has 192 x 32 pixels. The PB-770 has 160 x 32 pixels.
The PB-1000 has an FA-7 or MD-100 dock which provides a Centronics parallel port, which means an external printer can be used. Casio released a full page plotter, the FP-100 which has a Centronics port and I also have an Epson POS thermal printer which has a Centronics port. Either printer can be attached to the MD-100.
Maze Algorithm
The maze algorithm I started with is the backtracking algorithm, since this is easy to follow and easy to implement in BASIC. Since I already created the maze algorithm for the PB-770, converting it to run on the PB-1000 was simple.
Performance
A 25 x 25 maze took 2 minutes and 30 seconds to complete. As a reference, the older Casio PB-770 took over 6 minutes for the same size maze to render. Even though the PB-1000 was approximately 3 times faster with the same program in BASIC than the older PB-770, it is still quite slow by today’s standards.
Printing the Maze
The PB-1000 can be connected to a standard Centronics printer such as a POS thermal printer, or, the FP-100 plotter. I started with the POS thermal printer, since the consumables with these printers are readily available and inexpensive.
The POS printer I am using is an Epson TS-88V, with a parallel (Centronics) port connection. The paper is 80mm wide and the printer’s horizontal character width is 42 characters. I set the size of the maze to 41 (must be odd) and a height of 31 (again, must be odd) so that the maze generation is visible on the screen and also fills up most of the space on the printed width on paper.
Note that the PB-1000 has another 32 pixels on the Y-axis beyond the first 32 pixels on the Y-axis that are “virtual” and simply off screen.
The character size of these printers (English models) is taller than it is wide (12 x 24 pixels). I need to print two characters horizontally to square out the size a bit. In doing so, my printable maze width drops from 41 to 21. However, the result looks much better. The output is more balanced with respect to height and width (aspect ratio).
The output looked good and the program worked as expected – however, what if I were to use some of the extended ASCII characters from the old BBS and DOS days?
The Epson TM-88V supports many code pages and one of them, the default, includes all of the extended ASCII characters I need:
The printing algorithm would need to be modified of course. Specifically, it would need to be aware of the surrounding pixel states to pick the correct character to print.
This can be accomplished quite easily by inspecting the surrounding pixel states, representing those pixel states as a single numeric value that can be used as an index into an array of ASCII characters. Only four other pixels need to be inspected: the one above, below, to the left and to the right.
I labeled each position around the center pixel with a number, which represents the nth bit in a byte value. This is an efficient way to store all possible combinations of pixel states.
If we take a look for example at a pixel which is on, and the one on the bottom and the one to the right are also on, then this is a “corner”:
This corner could be represented with a “┌” ASCII character (code 218). The byte value for this condition (according to my labelling scheme) would be bits 1 and 3 set, or a decimal value of 10. I can then map the value 10 to ASCII code 218.
Looking at all possible combinations of pixel states, I arrived at the following table:
Decimal Value ASCII Code
0 32 (space)
1 196 ─
2 196 ─
3 196 ─
4 179 │
5 217 ┘
6 192 └
7 193 ┴
8 179 │
9 191 ┐
10 218 ┌
11 194 ┬
12 179 │
13 180 ┤
14 195 ├
15 197 ┼
I can use a simple array with 16 positions as a mapping between my bit scheme and the corresponding ASCII codes.
4000 DATA 32,196,196,196,179,217,192,193,179,191,218,194,179,180,195,197
4010 DIM M(16)
4020 FOR J = 0 TO 15
4030 READ M(J)
4040 NEXT J
The results worked quite well! The output is quite a bit slower due to the conversion of the bit patterns.
Large Maze Plot
Just for nostalgia, I thought why not plot a maze to a full size plotter? I have the Casio FP-100 printer plotter, some working pens, and standard 8.5 x 11 Amazon Basics printer paper.
I already have a basic printing algorithm for the Casio plotter (FA-10) on the PB-770. I made a few minor changes to this algorithm for the PB-1000. Luckily the FP-100 plotter uses the same command set as the FA-10.
I set the width and height for the plot to 31 x 31 with a scale factor of 4. I could have made the plot bigger either with more pixels or scaling factor, but as it is, it took over 15 minutes to render and plot.
The FP-100 is the first vintage full-page plotter I have used. It handles (tracks) the paper remarkably well, surprisingly. I can readily see how accurately the lines overlap, especially compared to my FA-10 (for the PB-770). I suspect those smaller plotters depend on a very specific thickness and style of paper. Clearly the paper type makes a difference in those smaller plotters.
There were only a few spots where my blue pen did not mark the paper correctly. This particular pen is original to a PC-2 plotter.
Program Listing
I have included the PB-1000 program listing for my conversion of the backtracking maze algorithm in BASIC below. This listing includes the various printing subroutines. Remove or ignore the highlighted comments in the listing.
I have added some parameters that should be set before using the program. The width and height should be set (highlighted below in line 20). Note that you cannot exceed the actual screen size here, and the number should be odd. Further, the larger the canvas size, the longer the maze will take to generate.
Line 20 includes a “scaling factor” for the plotter. For example, if the width and height were 25 and 25, the scale factor can be 4, giving a total X and Y travel of 100 points in both directions. If you increase the width and height to 50 by 50, the scale factor should be cut in half, for a value of 2 for the same travel points.
Once the width and height are set, be sure to choose which output you wish for the printer in line 590. Set this to 3100 for the “ASCII” version, 3000 for the block version, or 5000 for the plotter version.
MAZE GENERATOR VERSION 1.0
10 CLEAR : B=&H7000 : A=B : DIM N(4,2) : CLS
20 W=21 : H=21 : S = 4
30 W = W - (W MOD 2) + 1
40 H = H - (H MOD 2) + 1
FILL WORKSPACE WITH CLOSED BLOCKS
50 FOR Y=0 TO H-1
60 DRAW (0,Y)-(W-1,Y)
70 NEXT Y
CUT OPENING AT TOP
80 DRAWC (1,0)
RANDOM START SOMEWHERE
100 SY = ROUND(RND(-1)*(H-2),-1)+1
110 IF SY MOD 2 = 0 THEN 100
120 SX = ROUND(RND(-1)*(W-2),-1)+1
130 IF SX MOD 2 = 0 THEN 120
140 DRAWC(SX,SY)
150 POKE B,SX : B = B + 1 : POKE B,SY : B=B+1
POP NEXT OPEN SPACE OFF STACK
200 IF A=B THEN 580
205 B=B-1:CY = PEEK(B): B=B - 1 : CX = PEEK(B)
GET ADJACENT SPACES NOT OPEN YET
210 GOSUB 1000
IF NONE FOUND, POP PREVIOUS OPEN SPACE OFF STACK
500 IF NC = 0 THEN 200
RANDOM CHOICE MADE, OPEN AND JOIN TO PREVIOUS
530 CH = ROUND(RND(-1)*(NC-1),-1)
540 POKE B,N(CH,0) : B=B+1: POKE B,N(CH,1) : B=B+1
550 DRAWC(N(CH,0),N(CH,1))
560 DRAWC((N(CH,0)+CX)/2,(N(CH,1)+CY)/2)
570 CX = N(CH,0) : CY = N(CH,1) : GOTO 210
CUT OPENING AT BOTTOM, BEEP AND PAUSE, THEN PRINT
580 DRAWC(W-2,H-1) : DRAWC(W-2,H-2)
590 GOSUB 700 : GOSUB 3100 : END
BEEP AND PAUSE
700 BEEP
710 IF INKEY$="" THEN 710
720 RETURN
FIND ADJACENT CLOSED BLOCKS
1000 NC = 0 : YP = CY+2 : YM = CY-2 : XP = CX + 2 : XM = CX - 2
1010 IF YM <= 0 THEN 1030
1015 IF POINT(CX,YM) = 0 THEN 1030
1020 N(NC,0) = CX : N(NC,1) = YM : NC = NC + 1
1030 IF YP > H THEN 1050
1035 IF POINT(CX,YP) = 0 THEN 1050
1040 N(NC,0) = CX : N(NC,1) = YP : NC = NC + 1
1050 IF XM <= 0 THEN 1070
1055 IF POINT(XM,CY) = 0 THEN 1070
1060 N(NC,0) = XM : N(NC,1) = CY : NC = NC + 1
1070 IF XP > W THEN 1090
1075 IF POINT(XP,CY) = 0 THEN 1090
1080 N(NC,0) = XP : N(NC,1) = CY : NC = NC + 1
1090 RETURN
REDEFINE "~" TO SOLID BLACK BOX, ENABLE CUSTOM FONT
2000 LPRINT CHR$(27);CHR$(38);CHR$(3);CHR$(126);CHR$(126);CHR$(12);
2010 FOR M=0 TO 34 : LPRINT CHR$(255); : NEXT M : LPRINT CHR$(255)
2020 LPRINT CHR$(27);CHR$(37);CHR$(1)
2030 RETURN
SET LINE SPACING TO 0
2100 LPRINT CHR$(27);"3";CHR$(0)
2120 RETURN
SET LINE SPACING TO DEFAULT
2200 LPRINT CHR$(27);"2"
2210 RETURN
CUT PAPER
2300 LPRINT CHR$(29);"V";CHR$(66);CHR$(0)
2310 RETURN
RESET PRINTER
2500 LPRINT CHR$(27);CHR$(64) : RETURN
PRINT MAZE - BLOCK VERSION
3000 GOSUB 2500 : GOSUB 2100 : GOSUB 2000
3005 FOR Y = 0 TO H
3010 FOR X = 0 TO W
3020 IF POINT(X,Y) = 1 THEN LPRINT "~~"; : GOTO 3040
3030 LPRINT " ";
3040 NEXT X
3050 IF W<21 THEN LPRINT ""
3060 NEXT Y
3065 LPRINT ""
3070 GOSUB 2500 : GOSUB 2300 : GOSUB 700
3080 END
PRINT MAZE - ASCII VERSION
3100 GOSUB 2500 : GOSUB 2100 : GOSUB 4000
3120 FOR Y = 0 TO H
3130 FOR X = 0 TO W
3140 I = 0
3150 IF POINT(X,Y) = 0 THEN 3200
3155 IF X=0 THEN 3170
3160 IF POINT(X-1,Y) = 1 THEN I = I + 1
3165 IF X=W THEN 3175
3170 IF POINT(X+1,Y) = 1 THEN I = I + 2
3175 IF Y=0 THEN 3190
3180 IF POINT(X,Y-1) = 1 THEN I = I + 4
3185 IF Y=H THEN 3200
3190 IF POINT(X,Y+1) = 1 THEN I = I + 8
3200 LPRINT CHR$(M(I));
3210 NEXT X
3220 LPRINT ""
3230 NEXT Y
3340 GOSUB 2500 : GOSUB 2300 : GOSUB 700
3350 END
BIT PATTERN TO ASCII MAPPING
4000 DATA 20,63,63,196,63,217,192,193,63,191,218,194,179,180,195,197
4010 DIM M(16)
4020 FOR J = 0 TO 15
4030 READ M(J)
4040 NEXT J
4050 RETURN
PRINT MAZE - PLOTTER MODE
5000 LPRINT CHR$(28);CHR$(37)
LOOK FOR HORIZONTAL LINES
5010 FOR Y = 0 TO H
5020 PX = -1
5025 FOR X = 0 TO W
5030 P = POINT(X,Y)
5040 IF P = 0 THEN 5070
5050 IF PX >= 0 THEN 5080
5060 PX = X : GOTO 5080
5070 GOSUB 7000 : PX = -1
5080 NEXT X
5090 GOSUB 7000
6000 NEXT Y
6005 LPRINT “M0,0”
LOOK FOR VERTICAL LINES
6010 FOR X = 0 TO W
6020 PY = -1
6025 FOR Y = 0 TO H
6030 P = POINT(X,Y)
6040 IF P = 0 THEN 6070
6050 IF PY >= 0 THEN 6080
6060 PY = Y : GOTO 6080
6070 GOSUB 8000 : PY = -1
6080 NEXT Y
6090 GOSUB 8000
6099 NEXT X
6100 LPRINT “F4”
6110 GOSUB 700 : END
PRINT HORIZONTAL LINES
7000 IF PX < 0 THEN RETURN
7010 LPRINT “D” ; PX * S ; ”,” ; Y * S * -1; ”,” ; X * S ; ”,” ; Y * S * -1
7015 LPRINT “D” ; PX * S ; ”,” ; (Y * S * -1) - S; ”,” ; X * S ; ”,” ; (Y * S * -1) - S
7020 RETURN
PRINT VERTICAL LINES
8000 IF PY < 0 THEN RETURN
8010 LPRINT “D” ; X * S ; ”,” ; PY * S * -1; ”,” ; X * S ; ”,” ; Y * S * -1
8015 LPRINT “D” ; (X * S) + S ; ”,” ; PY * S * -1; ”,” ; (X * S) + S ; ”,” ; Y * S * -1
8020 RETURN
Final Thoughts
My kids enjoy completing mazes, and while we have several maze books and printouts from the interwebs, having a vintage pocket computer and plotter (or receipt printer) print out randomly generated mazes on demand is interesting to see.
I am impressed with the print quality of the FP-100 plotter. It is quite old and still works like it did when new. I suppose it likely was not used very much, but it does have some rather weak spots that will eventually render it inoperable (pinion years and other nylon gears).
This is a rather long program, I was sure to save it to a 3.5″ floppy disk before packing away the PB-1000.
I might expand on the maze idea a bit, perhaps make a game out of it. The PB-1000 has a real-time clock, a touch screen, and four directional arrow keys for game play. Perhaps a maze competition game for who can solve it fastest would be in the cards for a future project.