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 screen 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 (or FA-7).

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

In order to print the maze, I could simply read the pixel states off the LCD buffer area directly. The type of printout will depend on the type of printer being used. For example, a plotter versus thermal would be printed by different methods.

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 TM-T88V, 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 pixels wide x 24 pixels tall). I need to print two characters horizontally to square out the size. 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).

Casio PB-1000 Maze from Epson TM-88V POS Printer

In order to get a full “block” character output, I used the custom character definition feature in the Epson printer. I redefined the “~” character to become a full sized block, and printed the block by sending the “~” character to the printer.

In order to minimize spacing between lines, I set the line spacing to zero.

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-T88V supports many code pages and one of them, the default, includes all of the extended ASCII characters I need:

Epson TM-88V Code Page 0

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
Casio PB-1000 Maze from Epson TM-88V POS Printer

The results worked quite well! The output is quite a bit slower due to the conversion of the bit patterns.

If desired, the characters for each time of block can be swapped out, such as the double line ASCII characters for example.

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.

Casio FP-100 Four Color Plotter

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 updated the printing algorithm by eliminating the extra lines creating a “box” type printout. This version prints only the lines and lengths necessary by inspecting the surrounding pixel states.

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 increasing the scaling factor, but as it is, it took over 13 minutes to render and plot.

Casio PB-1000 with FP-100 Plotting a Maze
Casio PB-1000 with FP-100 Plotting a Maze
Maze Program Touch-Screen Menu Options

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 line up, 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 refilled black pen did not mark the paper correctly.

Similar to the my banner program for the PB-1000, I utilized a menu with touch screen for setting options and reprinting.

Note that the reprinting works only for height less than 24 pixels, as the menu itself would overwrite any part of the maze below that.

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 default width and height could be changed (highlighted below in line 10). 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. 

When using a plotter to print, line 10 also 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.

Be sure to choose which printer output option you wish for the printer in line 600. The three options are:

  • 3100 for the “ASCII” version (for Epson ESC/POS)
  • 3000 for the block version (for Epson ESC/POS)
  • 5000 for the plotter version (for Casio FP-100)
MAZE GENERATOR VERSION 1.2

10 CLEAR : W=21 : H=21 : S = 4 : B=&H7000 : DIM N(4,2) : GOTO 9100
20 A=B : CLS
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  
600 GOSUB 3100 : GOTO 9100

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 
3080 GOTO 9100

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 
3350 GOTO 9100

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 PX1 = -1 
5020 FOR Y = 0 TO H - 1
5024 PY = Y * S * -1
5030 FOR X = 0 TO W - 1
5040 IF POINT(X,Y) = 0 THEN GOSUB 7000 : GOTO 5090
5050 IF Y = 0 THEN 5070
5060 IF POINT(X,Y-1) = 1 THEN GOSUB 7000 : GOTO 5090
5070 IF PX1 < 0 THEN LET PX1 = X 
5090 NEXT X
5100 GOSUB 7000
5110 PY = (Y * S * -1) - S
5120 FOR X = 0 TO W - 1
5130 IF POINT(X,Y) = 0 THEN GOSUB 7000 : GOTO 5180
5140 IF Y = H THEN 5160
5150 IF POINT(X,Y+1) = 1 THEN GOSUB 7000 : GOTO 5180
5160 IF PX1 < 0 THEN LET PX1 = X 
5180 NEXT X
5190 GOSUB 7000
5200 NEXT Y

6005 LPRINT “M0,0”

LOOK FOR VERTICAL LINES

6010 PY1 = -1
6020 FOR X = 0 TO W - 1
6025 PX = X * S
6030 FOR Y = 0 TO H - 1
6040 IF POINT(X,Y) = 0 THEN GOSUB 8000 : GOTO 6080
6050 IF X = 0 THEN 6070
6060 IF POINT(X-1,Y) = 1 THEN GOSUB 8000 : GOTO 6080
6070 IF PY1 < 0 THEN LET PY1 = Y
6080 NEXT Y
6090 GOSUB 8000
6100 PX = (X * S) + S
6110 FOR Y = 0 TO H - 1
6120 IF POINT(X,Y) = 0 THEN GOSUB 8000 : GOTO 6160
6130 IF X = W THEN 6150
6140 IF POINT(X+1,Y) = 1 THEN GOSUB 8000 : GOTO 6160
6150 IF PY1 < 0 THEN LET PY1 = Y
6160 NEXT Y
6170 GOSUB 8000
6180 NEXT X
6190 LPRINT “F4”
6200 GOTO 9100

PRINT HORIZONTAL LINES

7000 IF PX1 < 0 THEN RETURN
7010 LPRINT “D”; PX1 * S; ”,”; PY; ”,”; X * S; ”,”; PY
7020 PX1 = -1 : RETURN

PRINT VERTICAL LINES

8000 IF PY1 < 0 THEN RETURN 
8010 IF Y - PY1 >= 0 THEN LPRINT “D”; PX; ”,”; PY1 * S * -1; ”,”; PX; ”,”; Y * S * -1
8020 PY = -1 : RETURN

MENU

9000 LOCATE 0,3 : PRINT "[  GO  ][REPRNT][ W";
9010 PRINT USING "##";W;
9020 PRINT "  ][ H";
9030 PRINT USING "##";H;
9040 PRINT " ]";
9050 RETURN

9100 BEEP : GOSUB 9000
9110 K$=INKEY$
9120 IF K$=CHR$(252) THEN 20
9130 IF K$=CHR$(253) THEN 600
9140 IF K$=CHR$(254) THEN CLS : INPUT "Width?",W : GOSUB 9000
9150 IF K$=CHR$(255) THEN CLS : INPUT "Height?",H : GOSUB 9000
9160 GOTO 9110

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.

Leave a Reply