# BASIC and many input options…

Earlier this year, Jason Pittman shared a BASIC program with me that drew representations of all the letters of the alphabet. It was a cute program, and did some fancy drawing.

`130 PMODE3,1:A\$=INKEY\$140 IFA\$="A"THEN410150 IFA\$="B"THEN510160 IFA\$="C"THEN590170 IFA\$="D"THEN680180 IFA\$="E"THEN750190 IFA\$="F"THEN820200 IFA\$="G"THEN900210 IFA\$="H"THEN1020220 IFA\$="I"THEN1100230 IFA\$="J"THEN1130240 IFA\$="K"THEN1220250 IFA\$="L"THEN1340260 IFA\$="M"THEN1410270 IFA\$="N"THEN1490280 IFA\$="O"THEN1560290 IFA\$="P"THEN1680300 IFA\$="Q"THEN1780310 IFA\$="R"THEN1890320 IFA\$="S"THEN2020330 IFA\$="T"THEN2100340 IFA\$="U"THEN2190350 IFA\$="V"THEN2250360 IFA\$="W"THEN2360370 IFA\$="X"THEN2440380 IFA\$="Y"THEN2490390 IFA\$="Z"THEN2550400 GOTO130`

I thought it might be fun to ask you — in the comments — to tell me how YOU would have done this. I can think of one way, that uses an Extended BASIC keyword, and another way, that would work on Color BASIC.

For a series of options that are sequential (like “A to Z”) there are certainly some options.

As a part two … what if they were not sequential? What if it was for a menu that had options like “A, B, C, D, Q, Z” or whatever? That let me think of a third way to do it to work in Color BASIC.

Comment away!

# Let’s write Lights Out in BASIC – part 7

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

## Code cleanup in aisle 4.

Let me begin this installment by presenting the current Lights Out code with some renumbering done and a few minor improvements.

`0 REM LITESOUT-P7.BAS10 REM SETUP20 DIM L(9,9)100 REM START NEW GAME110 GOSUB 5000120 REM INITIALIZE GRID130 MV=0140 GOSUB 4000150 REM SHOW GRID160 GOSUB 1000170 REM CHECK FOR WIN180 IF LO=0 THEN 300190 REM INPUT SQUARE200 GOSUB 2000210 REM TOGGLE SQUARES220 GOSUB 3000230 REM REPEAT240 MV=MV+1250 GOTO 150300 REM GAME WON310 PRINT "YOU WON IN";MV;"MOVES."320 INPUT "PLAY AGAIN (Y/N)";Q\$330 IF Q\$="Y" THEN 100340 PRINT "GAME OVER"350 END1000 REM SHOW GRID1010 PRINT "GAME NUMBER:";GN1020 PRINT "  ";1030 FOR A=1 TO GS1040 PRINT RIGHT\$(STR\$(A),2);1050 NEXT:PRINT1060 FOR Y=0 TO GS-11070 PRINT RIGHT\$(STR\$(Y+1),2);" ";1080 FOR X=0 TO GS-11090 IF L(X,Y) THEN PRINT "X ";:GOTO 11101100 PRINT ". ";1110 NEXT1120 PRINT1130 NEXT1140 PRINT "MOVES:";MV;"LIGHTS ON:";LO1150 RETURN2000 REM INPUT SQUARE2010 S\$=MID\$(STR\$(GS),2):PRINT "X,Y (1-";S\$;",1-";S\$;" OR 0,0)";2020 INPUT X,Y2030 IF X=0 THEN IF Y=0 THEN 3202040 IF X<1 OR X>GS OR Y<1 OR Y>GS THEN 20102050 X=X-1:Y=Y-12060 RETURN3000 REM TOGGLE SQUARES 3010 L(X,Y)=NOT L(X,Y):LO=LO-(L(X,Y)*2+1)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y):LO=LO-(L(X-1,Y)*2+1)3030 IF X<GS-1 THEN L(X+1,Y)=NOT L(X+1,Y):LO=LO-(L(X+1,Y)*2+1)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1):LO=LO-(L(X,Y-1)*2+1)3050 IF Y<GS-1 THEN L(X,Y+1)=NOT L(X,Y+1):LO=LO-(L(X,Y+1)*2+1)3060 RETURN4000 REM INITIALIZE GRID4010 INPUT "GRID SIZE (3-10, ENTER=5)";GS4020 IF GS=0 THEN GS=54030 IF GS<3 OR GS>10 THEN 40104040 PRINT "INITIALIZING..."4050 FOR A=1 TO 10*GS4060 Y=RND(GS)-14070 X=RND(GS)-14080 GOSUB 30004090 NEXT4100 RETURN5000 REM SELECT GAME5010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"5020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 50205030 IF A\$="Y" THEN 50705040 IF A\$="N" THEN A=RND(-S)5050 GN=RND(65535):A=RND(-GN)5060 GOTO 51005070 INPUT "PLAY GAME (1-65535)";GN5080 IF GN<1 OR GN>65535 THEN 50605090 A=RND(-GN)5100 RETURN`

As I tested this version, I noticed my random grid generator was not very good–at least on a large 10×10 grid. It really needed to do more random light toggling for larger grids. This change would go in this line – maybe just doing a “grid size * X”, like “10*GS” or something. I am still trying things, but for now I made it do more random toggles the larger the grid size is (line 4050).

I also made it so the default grid size was 5 (line 4010).

And I fixed some output where it printed a numeric variable. In Color BASIC, there is an extra space printed before and after printing a number:

`PRINT "*";42;"*"* 42 *`

And, technically, it’s not a space before a number — it’s a place for the sign (none if positive, “-” if negative):

`PRINT "*";-42;"*"*-42 *`

Since I knew I was only printing a positive number, I just got rid of that leading space, and the one after it. I did this by converting the number to a string using STR\$. That will convert it to a string with the first space (a place for the sign) but no space after it:

`PRINT "*";STR\$(42);"*"* 42*`

Then all I needed to do was trim off that leading space. In the old days, I would have done this by getting the length of the string using LEN\$ and then using RIGHT\$ to get just the character(s) after that leading space:

`N=42N\$=STR\$(N)L=LEN(N\$)PRINT RIGHT\$(N\$,L-1)`

But in recent years, someone commented on this site (I believe) about how you could use MID\$ without a size and just specify the starting position in a string, and it would return everything from that position to the end:

`N=42PRINT MID\$(STR\$(N),2)`

Nice! “Wish I knew then what I know now…”

But I digress…

We now have a fairly “feature complete” version of Lights Out that runs in very basic BASIC — it doesn’t even make use of ELSE.

Before I move on to making this look a lot nicer on a CoCo, I thought it might be fun to port it to a VIC-20. I made use of the wonderful CBM prg Studio Windows-based tool that can build BASIC or assembly programs for all kinds of Commodore machines. I just pasted in my source, and then found a few minor things I would need to change to run on the VIC-20’s CBM BASIC.

The first thing I did after pasting the code in to the editor was to convert it all to lowercase. That seems to be how that BASIC works, as SHIFT characters turn in to PETSCII graphics characters.

Now I would be able to build the program.

It would build right away, but not run on the VIC yet until I fix two things that are different between Color BASIC and CBM BASIC:

• A\$=INKEY\$ must be changed to GET A\$
• RND(x) must be changed to INT(RND(1)*X)-1 (Doing the random seed using RND(-X) works the same way on the VIC, and could be left alone.)
`CoCo:5020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 5020VIC:5020 S=S+1:GET A\$:IF A\$="" THEN 5020CoCo:4060 Y=RND(GS)-1VIC:4060 Y=INT(RND(1)*GS)CoCo:4070 X=RND(GS)-1VIC:4070 X=INT(RND(1)*GS)`

After that, I tried to RUN it and ran in to a problem with INPUT:

From testing, it seems that long prompts on INPUT cause issues, possibly related to how the VIC’s full screen editor works. I sent a tweet to 8-Bit Show and Tell to see what he knew, and did a simple workaround by breaking up the prompt and the input on separate screen lines:

`4000 rem initialize grid4010 print "grid size (3-10, enter=5)":input gs`

I thought I might have the same issue with the “select square” input, but that prompt does not overlap to the next line so it worked… or so I thought. With the default grid size of 5×5, the prompt looked like:

`X,Y (0-5,0-5 OR 0,0)?(space)*(cursor here)`

That seemed to work just fine, but when I did a grid of 10×10, it made the prompt longer, wrapping the “?” of INPUT to the next line:

`X,Y (0-10,0-10 OR 0,0)? *(cursor here)`

So I needed to fix that, too. I had already had to break that one up in to a PRINT and an INPUT since I was printing variables in the prompt, so I just took the semicolon off from the end of the PRINT:

`2000 rem input square2010 s\$=mid\$(str\$(gs),2):print "x,y (1-";s\$;",1-";s\$;" or 0,0)"2020 input x,y`

Now I had what appeared to be a working version of the game for VIC-20. BUT, it would need some work to reformat the prompts to fit on a 22-column screen, versus the 32- column CoCo screen. For anyone who wants to work on that, here is the VIC-20 version with the lines in bold that have changes from the CoCo version:

`0 rem litesout-p7.bas10 rem setup20 dim l(9,9)100 rem start new game110 gosub 5000120 rem initialize grid130 mv=0140 gosub 4000150 rem show grid160 gosub 1000170 rem check for win180 if lo=0 then 300190 rem input square200 gosub 2000210 rem toggle squares220 gosub 3000230 rem repeat240 mv=mv+1250 goto 150300 rem game won310 print "you won in";mv;"moves."320 input "play again (y/n)";q\$330 if q\$="y" then 100340 print "game over"350 end1000 rem show grid1010 print "game number:";gn1020 print "  ";1030 for a=1 to gs1040 print right\$(str\$(a),2);1050 next:print1060 for y=0 to gs-11070 print right\$(str\$(y+1),2);" ";1080 for x=0 to gs-11090 if l(x,y) then print "x ";:goto 11101100 print ". ";1110 next1120 print1130 next1140 print "moves:";mv;"lights on:";lo1150 return2000 rem input square2010 s\$=mid\$(str\$(gs),2):print "x,y (1-";s\$;",1-";s\$;" or 0,0)"2020 input x,y2030 if x=0 then if y=0 then 3202040 if x<1 or x>gs or y<1 or y>gs then 20102050 x=x-1:y=y-12060 return3000 rem toggle squares 3010 l(x,y)=not l(x,y):lo=lo-(l(x,y)*2+1)3020 if x>0 then l(x-1,y)=not l(x-1,y):lo=lo-(l(x-1,y)*2+1)3030 if x<gs-1 then l(x+1,y)=not l(x+1,y):lo=lo-(l(x+1,y)*2+1)3040 if y>0 then l(x,y-1)=not l(x,y-1):lo=lo-(l(x,y-1)*2+1)3050 if y<gs-1 then l(x,y+1)=not l(x,y+1):lo=lo-(l(x,y+1)*2+1)3060 return4000 rem initialize grid4010 print "grid size (3-10, enter=5)":input gs4020 if gs=0 then gs=54030 if gs<3 or gs>10 then 40104040 print "initializing..."4050 for a=1 to 10*gs4060 y=int(rnd(1)*gs)4070 x=int(rnd(1)*gs)4080 gosub 30004090 next4100 return5000 rem select game5010 print "play specific game # (y/n)?"5020 rem s=s+1:a\$=inkey\$:if a\$="" then 50205021 s=s+1:get a\$:if a\$="" then 50205030 if a\$="y" then 50705040 if a\$="n" then a=rnd(-s)5050 gn=rnd(65535):a=rnd(-gn)5051 rem gn=int(rnd(1)*65535)-1:a=rnd(-gn)5060 goto 51005070 input "play game (1-65535)";gn5080 if gn<1 or gn>65535 then 50605090 a=rnd(-gn)5100 return`

The more I look at this code, the more optimizations I want to make to it.

But for now, that is a version for CoCo, and a version for Commodore. It should be easy to port to other flavors of BASIC. Let me know if you port it to something.

Now that I know how to write the game, the next goal will be to make it look a lot better on the CoCo (and maybe VIC-20 as well, if I feel ambitious).

But I think I need a brake from Lights Out for a bit…

Until then…

# Let’s write Lights Out in BASIC – part 6

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

At this point, we have a nicely functional BASIC version of Lights Out. Some of its features include:

• 5×5 grid of lights.
• Random games.
• Allows replaying a specific game.
• Counts moves for scoring.
• Ability to quite a game in progress.
• Slightly less sucky user interface than the original version.

But we still have more to do!

One of the enhancements I mentioned in the previous installment was the ability to specify larger (or smaller, I suppose), grid sizes. We know that the official Lights Out games from Tiger Electronics in the 1990s used a 5×5 and 6×6 grid. Others have since created variations, such as one that operates around a cube (maybe we write that version some day). Let’s start there…

For this simple version, we’ll just arbitrarily pick a maximum grid size of 10×10. This should still fit easily on the CoCo’s 32×16 text screen. For fun, we could also allow a grid size smaller than 5×5 to be chosen. Since the spiritual predecessor of Lights Out was a 1970s game that featured a 3×3 grid, I’ll use that size as the minimum.

The changes needed should be fairly minor. When starting a game, the user will be prompted for the grid size.

It seems we could allow rectangular grids (5×3, 10×5, etc.), but for now we’ll just stick to square grids where both sides are the same size. The array for the grid just needs to be large enough to hold the largest sized grid.

## Wrong DIMension

An oversight I made when starting this program was not adding a DIM statement to specify the maximum size of the two-dimensional grid array! The current version really needs a line that contains this at the very top:

`DIM L(4,4)`

Reminder: DIM is base-0, so it starts counting entries at 0. A DIM X(4) gives entries X(0), X(1), X(2), X(3) and X(4).

The program only works because Color BASIC allows array entries 0-10 before the DIM is needed. You can do A(10)=42 without needing to DIM A(10) first. (I find it weird that Microsoft chose to default to 11 array entries. I bet whoever coded that was thinking “1-10” rather than “0-10”.)

To enhance the program to support up to a 10×10 grid, we’ll allocate an array that large.

`4 DIM L(9,9)`

Next we need to ask the user what size grid they want. This can be added to the “initialize grid” subroutine:

`4000 REM INITIALIZE GRID4005 INPUT "GRID SIZE (3-10)";GS4006 IF GS<3 OR GS>10 THEN 4005...`

After that, any place that is currently hard coded to 4 will need to be changed to use the grid size variable. If the user types in 10 (for a 10×10), the array will be using 0-9. We must pay attention to that and know that a 10 grid is actually 0-9.

This is also a good time to clean up the printing of the grid a bit. Here is the full program with the latest changes in bold:

`4 DIM L(9,9)5 REM SELECT GAME6 GOSUB 600010 REM INITIALIZE GRID15 MV=020 GOSUB 400030 REM SHOW GRID40 GOSUB 100047 IF LO=0 THEN 20050 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT95 MV=MV+1100 GOTO 30200 REM GAME WON220 PRINT "YOU WON IN";MV;"MOVES."230 INPUT "PLAY AGAIN (Y/N)";Q\$240 IF Q\$="Y" THEN 5250 PRINT "GAME OVER"260 END1000 REM SHOW GRID1005 PRINT "GAME NUMBER:";GN1006 PRINT "  ";1007 FOR A=1 TO GS1008 PRINT RIGHT\$(STR\$(A),2);1009 NEXT:PRINT1010 FOR Y=0 TO GS-11015 PRINT RIGHT\$(STR\$(Y+1),2);" ";1020 FOR X=0 TO GS-11030 IF L(X,Y) THEN PRINT "X ";:GOTO 10501040 PRINT ". ";1050 NEXT1060 PRINT1070 NEXT1080 PRINT "MOVES:";MV;"LIGHTS ON:";LO1090 RETURN2000 REM INPUT SQUARE2010 PRINT "X,Y (1-";GS;",1-";GS;" OR 0,0)";2011 INPUT X,Y2015 IF X=0 THEN IF Y=0 THEN 2302020 IF X<1 OR X>GS OR Y<1 OR Y>GS THEN 20102025 X=X-1:Y=Y-12030 RETURN3000 REM TOGGLE SQUARES 3010 L(X,Y)=NOT L(X,Y):LO=LO-(L(X,Y)*2+1)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y):LO=LO-(L(X-1,Y)*2+1)3030 IF X<GS-1 THEN L(X+1,Y)=NOT L(X+1,Y):LO=LO-(L(X+1,Y)*2+1)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1):LO=LO-(L(X,Y-1)*2+1)3050 IF Y<GS-1 THEN L(X,Y+1)=NOT L(X,Y+1):LO=LO-(L(X,Y+1)*2+1)3060 RETURN4000 REM INITIALIZE GRID4005 INPUT "GRID SIZE (3-10)";GS4006 IF GS<3 OR GS>10 THEN 40054010 PRINT "INITIALIZING..."4020 FOR A=1 TO 104030 Y=RND(GS)-14040 X=RND(GS)-14050 GOSUB 30004060 NEXT4070 RETURN6000 REM SELECT GAME6010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"6020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 60206030 IF A\$="Y" THEN 60606040 IF A\$="N" THEN A=RND(-S)6045 GN=RND(65535):A=RND(-GN)6046 GOTO 60906050 GOTO 60206060 INPUT "PLAY GAME (1-65535)";GN6070 IF GN<1 OR GN>65535 THEN 60606080 A=RND(-GN)6090 RETURN`

This version will display the grid with nicely (?) formatted headers for the columns and rows, and less nicely formatted prompts for what values are allowed.

There is still so much work to do to make the user interface nicer to look at and interact with.

To be continued…

# Let’s write Lights Out in BASIC – part 5

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

As we begin this part, let’s look at the BASIC Lights Out code as it stands currently:

`5 REM SELECT GAME6 GOSUB 600010 REM INITIALIZE GRID20 GOSUB 400030 REM SHOW GRID40 GOSUB 100047 IF LO=0 THEN PRINT "YOU WON!":END48 PRINT "LIGHTS ON:";LO50 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT100 GOTO 301000 REM SHOW GRID1005 PRINT "GAME NUMBER:";GN1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT1090 RETURN2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4)";X,Y2020 IF X<0 OR X>4 OR Y<0 OR Y>4 THEN 20102030 RETURN3000 REM TOGGLE SQUARES 3010 L(X,Y)=NOT L(X,Y):LO=LO-(L(X,Y)*2+1)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y):LO=LO-(L(X-1,Y)*2+1)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y):LO=LO-(L(X+1,Y)*2+1)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1):LO=LO-(L(X,Y-1)*2+1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1):LO=LO-(L(X,Y+1)*2+1)3060 RETURN4000 REM INITIALIZE GRID4010 PRINT "INITIALIZING..."4020 FOR A=1 TO 104030 Y=RND(5)-14040 X=RND(5)-14050 GOSUB 30004060 NEXT4070 RETURN6000 REM SELECT GAME6010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"6020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 60206030 IF A\$="Y" THEN 60606040 IF A\$="N" THEN A=RND(-S)6045 GN=RND(65535):A=RND(-GN)6046 GOTO 60906050 GOTO 60206060 INPUT "PLAY GAME (1-65535)";GN6070 IF GN<1 OR GN>65535 THEN 60606080 A=RND(-GN)6090 RETURN`

There are quite a few more things that could (and probably need to) be done:

• The number of moves taken should be counted and displayed.
• If the game is won, it just ENDs in line 47. It could ask the player if they want to play again.
• There is no way to quit a game in progress other than hitting the break key.
• The user interface (typing in coordinates such as “0,2”) is user-hostile. At the very least, we could label the rows/columns to show which values to type. Perhaps even labeling them “A B C D E …” across, and “1 2 3 4 5” vertically, similar to how chess boards are done.
• Options for grids larger than 5×5 could be implemented with very little change in the code.

Once the game is “code complete“, there is also be some cleanup and renumbering that should be done. (Having those odd line numbers like 47 bugs me.)

## Score (Counting Moves)

The current code only knows that you won the game (the game ends) or you are still playing. If one person plays game number 16809 and solves it in 80 moves, and another person plays the same game and solves it in 10 moves, they are both treated to the same ending – the game exits.

Let’s add a move counter. We’ll reset it at the start of a game…

`10 REM INITIALIZE GRID15 MV=020 GOSUB 4000`

…and increment it after every move:

`90 REM REPEAT95 MV=MV+1100 GOTO 30`

We should also display the move count each time the grid is display. This is a good time to also move the “number of lights on” in to the display grid routine, too.

`48 PRINT "LIGHTS ON:";LO (removed)1000 REM SHOW GRID1005 PRINT "GAME NUMBER:";GN1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT "MOVES:";MV;"LIGHTS ON:";LO1090 RETURN`

This now gives us a display of our game number (which was already there), the number of moves made so far (new), and the current count of how many lights are on (already there).

DONE: The number of moves taken should be counted and displayed.

## Game Over

The next thing I want to add is a game over screen. When the game is on, this screen should display how many moves it took. It could then prompt the user to see if they want to play agan.

It could be as simple as this:

`47 IF LO=0 THEN 200200 REM GAME WON220 PRINT "YOU WON IN";MV;"MOVES."230 INPUT "PLAY AGAIN (Y/N)";Q\$240 IF Q\$="Y" THEN 5250 PRINT "GAME OVER"260 END`

DONE: If the game is won, it just ENDs in line 47. It could ask the player if they want to play again.

## I give up!

The user should also be able to quit. Currently, the awful “type in an X,Y coordinate” thing is yucky, but we could make typing “-1,-1” end the game. (We will fix the user interface later.)

``2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4 OR -1,-1)";X,Y2015 IF X=-1 THEN IF Y=-1 THEN 2302020 IF X<0 OR X>4 OR Y<0 OR Y>4 THEN 20102030 RETURN``

This is so yucky, but the goal here is to get the code fully functional. We can make it nice later.

DONE: There is no way to quit a game in progress other than hitting the break key.

## The user interface sucks!

Okay, this one will take more work, but a quick enhancement might be to just print the columns and rows so the player knows what to type. Also, humans like counting from one instead of zero (base-1 humans) so typing in things to match the base-0 arrays is not very human friendly. We can fix both things here.

`1000 REM SHOW GRID1005 PRINT "GAME NUMBER:";GN1006 PRINT "   12345"1010 FOR Y=0 TO 41015 PRINT Y+1;1020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT "MOVES:";MV;"LIGHTS ON:";LO1090 RETURN`

…and…

`2000 REM INPUT SQUARE2010 INPUT "X,Y (1-5,1-5 OR 0,0)";X,Y2015 IF X=0 THEN IF Y=0 THEN 2302020 IF X<1 OR X>5 OR Y<1 OR Y>5 THEN 20102025 X=X-1:Y=Y-12030 RETURN`

Now the user will see numbers above the grid, and to the left of the grid, and be able to enter them using 1-5 rather than 0-4. I made 0,0 exit as well to save the use from having to type the minus signs.

But, this interface still sucks. After we get the “text and typing” version done, we can do one that is more modern and uses the arrow keys to cursor around and select squares.

DONE: The user interface (typing in coordinates such as “0,2”) is user-hostile.

Hey, let’s just get the basic game working first, then we can worry about “Deluxe Lights Out.”

DEFERRED: Options for grids larger than 5×5 could be implemented with very little change in the code.

To be continued…

# Let’s write Lights Out in BASIC – part 4

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

Where where we?

Oh, right. Light Out, in very basic BASIC.

If Lights Out always started with the same lights on, once you figured out how to win, you could repeat those steps and win every time. This reminds me of a wooden golf tee game I was given as a child. (If you have ever eaten at a Cracker Barrel restaurant, you probably have seen this — they have/had one on every table.)

I never learned how to win that game intentionally, but sometimes I would get lucky. This made visits to Cracker Barrel sometimes frustrating. The game had a listing of rankings based on how many pegs you had left at the end of the game. I was often an “EG-NO-RA-MOOSE.” :)

But then the iPhone happened in 2007, and a year later there was an App Store and you could play games on the phone! I found a peg game app and decided to learn and memorize the steps that win the game. I took screen shots of every step so I could consult them later. Here is one of those tiny 320×480 screen shots taken in 2008 on my original 2007 iPhone:

While I no longer remember those steps, I did for awhile, and visits to the Cracker Barrel were never the same. I was the peg game master! But soon it become boring and not worth playing since I knew how to win it every time.

Oh well. At least the collard greens and fried okra were still great.

Side Note: During research for this article, I found that Cracker Barrel has a blog post with the history of the peg game, as well as all the steps to solve it.

But I digress…

## “Random” game variations

The current program has an initializing routine which turns random lights on. But does it really?

As I wrote in an earlier article about RND, RND is not really random. On my CoCo, each time I turn it on, I can print some random numbers. Each time I power cycle and try it again, I will get those same “random” numbers. Here is an example of the first eight random numbers between 1 and 50 on the CoCo:

Any programmer that writes something that relies on RND to generate levels or patterns should be aware that it will make the same level or pattern each time the program runs from a fresh power up. BUT, in Color BASIC, you can seed the random number generator to change that pattern. It works by passing in a negative value to RND. When you do that, it seeds the number generator to a specific and repeatable sequence for that seed value.

If you run this code on a CoCo, you will see it print the same set of eight random numbers ten times:

`10 FOR A=1 TO 1020 B=RND(-42)30 FOR B=1 TO 840 PRINT RND(50);:50 NEXT60 PRINT70 NEXT`

This means that if I powered up my computer and ran this Lights Out program, I would get the same pattern the next time I powered up and ran the program.

This is probably not a problem that really needs to be solved, but since there is a simple solution, it makes for a good excuse to discuss it.

## Seeding the random number generator

In Extended Color BASIC, there is a TIMER function that starts at 0 on power up, then increments every 60th of a second until it rolls over and starts again from 0. Since the amount of time between power up, typing in “CLOAD” or whatever, and “RUN” will vary, using that value makes for a simple seed:

`A=RND(-TIMER)`

Just doing something like that at the start of the program should be enough to reduce chances that the patterns are not the same each time the game is played from a fresh start.

BUT, Color BASIC does not have TIMER. It would need a different approach to creating that number. If the program has a title/splash screen, it might sit in a loop waiting for the user to press a key to start. Something like that could be used to create a seed number:

`PRINT "PRESS ANY KEY TO BEGIN:"xx S=S+1:IF INKEY\$="" THEN xxA=RND(-S)`

It is not perfect since if the user types RUN and quickly hits a key, there is a good potential that the program would be using one of only a few seeds based on the low numbers that the counter got to. But, hey, better than nothing… And that’s something.

We could also keep incrementing that S variable inside the main program loop. If the user chose to play again (our program does not offer that feature, yet), the value could be used to create more random patterns. This is probably overkill, but it would be simple to add.

## Predictable randomness could be a feature…

I recall some game that came with Microsoft Windows (maybe a Solitaire, or perhaps Minesweeper) that had a spot where you entered a “game number” or something. This let you replay a specific game. I did not realize it at the time, but this was probably just seeding a random number generator so the order of the cards or the mines (whatever game it was) would be the same for those that wanted to try again.

Update: I was close! It was apparently FreeCell for Windows 95. I asked BING’s AI and it told me:

I believe the game you are referring to is FreeCell. FreeCell is a solitaire card game that was first introduced in Windows 95. It is a popular game that allows players to replay specific games by entering a “game number” 1If you’re interested in playing FreeCell, you can download it from the Microsoft Store 1.

I hope this helps!

– BING AI

Thank you, large language model.

But I digress…

The game could try to randomize, but could also allow the user to pick a “game number” that would be repeatable. That could be a fun feature, since players could use it to practice different strategies.

It could be as simple as something like this (for Extended Color BASIC which has the TIMER function):

`xx INPUT "PLAY GAME (1-65535, 0=RND)";SIF S<0 OR S>65535 THEN xxIF S=0 THEN S=TIMERA=RND(-S)`

Or if TIMER was not available, it could prompt the user then sit in a loop counting and use the count value as the seed. This is not a great approach, but might work…

`PRINT "PLAY SPECIFIC GAME # (Y/N)?"xx S=S+1:A\$=INKEY\$:IF A\$="" THEN xxIF A\$="Y" THEN yyIF A\$="N" THEN A=RND(-S):GOTO zzGOTO xxyy INPUT "PLAY GAME (1-65535)";SIF S<1 OR S>65535 THEN yyA=RND(-S)zz RETURN`

I decided to add it to the program as a subroutine that can be called before the main game loop:

`6000 REM SELECT GAME6010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"6020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 60206030 IF A\$="Y" THEN 60606040 IF A\$="N" THEN A=RND(-S):GOTO 60906050 GOTO 60206060 INPUT "PLAY GAME (1-65535)";S6070 IF S<1 OR S>65535 THEN 60606080 A=RND(-S)6090 RETURN`

I could just call this before the game begins:

`5 REM SELECT GAME6 GOSUB 600010 REM INITIALIZE GRID20 GOSUB 400030 REM SHOW GRID40 GOSUB 100047 IF LO=0 THEN PRINT "YOU WON!":END48 PRINT "LIGHTS ON:";LO50 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT100 GOTO 30`

This would be simple enough to allow the user to replay a specific game. Here is a screen shot showing two instances of the XRoar emulator running the program, and generating the same pattern by using the same random seed:

This still is not 100% what we might want. While it does allow the user to request a specific game over and over, if they choose a random game, there is no way to get back to that game — it was chosen randomly.

To do that, we’d pick a random number for the “game number”, then use that as the seed value and display it as part of the game (so the user knows which number to use next time). We would still need to do some initial random seeding at the start so the game did not choose the same pattern of game numbers.

Here is a modification to the “select game” routine with some variable changes (GN for game number):

`6000 REM SELECT GAME6010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"6020 S=S+1:A\$=INKEY\$:IF A\$="" THEN 60206030 IF A\$="Y" THEN 60606040 IF A\$="N" THEN A=RND(-S)6045 GN=RND(65535):A=RND(-GN)6046 GOTO 60906050 GOTO 60206060 INPUT "PLAY GAME (1-65535)";GN6070 IF GN<1 OR GN>65535 THEN 60606080 A=RND(-GN)6090 RETURN`

Then, we could print the game number before it prints the grid each time:

`1000 REM SHOW GRID1005 PRINT "GAME NUMBER:";GN1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT1090 RETURN`

Now I can have the program generate a “random” game for me, and use that game number later to get the same puzzle.

At this point, we have a fairly playable (though ugly) version of a 5×5 Lights Out game.

There are a few more “nice to haves” we can add, so we’ll do those in the next installment.

Until then…

# Let’s write Lights Out in BASIC – part 3

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

The story so far… In the beginning, we learned a bit about the game Lights Out and its history. We then saw some very basic BASIC that implements the basic functionality of a basic game of this type. We still have a bit more work to do, such as initializing some of the squares to an “on” state and adding code to detect when the game has been won.

## Game Initialization

Since variables in BASIC initialize as 0, and 0 means FALSE (the light is “off”), the initial grid would be shown with all lights off. Congratulations. You win!

To make it a game, we need to have some or all of those lights on when the game starts. My initial attempts of just randomly setting some number of lights to on seemed to often produce puzzles that could not be solved — even when using lookup tables (i.e., “cheating”) that show the winning patterns. Are there unsolvable patterns in Lights Out???

I consulted the chat section of the BING search engine, and asked it…

Yes, there are some configurations of the Lights Out game that cannot be solved. In fact, Marlow Anderson and Todd Feil proved in 1998 that not all configurations are solvable. However, it is important to note that these unsolvable configurations are not valid Lights Out puzzles.

– BING AI Chat

Well then. Since unsolvable patterns are not valid for Lights Out, tust turning on random lights is not an acceptable way to start a game.

Side Note: Card games like Solitaire certainly can be unwinnable depending on the order of cards in the deck. I am pretty sure games like Minesweeper are like that, too. But Lights Out patterns are always supposed to be winnable.

It seemed if you started with all lights off, you could simply work backwards by toggling lights on randomly until you got to a stopping point. Whatever pattern that is, the player was assured that there was a way to win. Instead of just turning on specific lights, I could just select a square and allow it to do the normal toggle (that light, plus the adjacent lights).

For my version, I will just make a very simple “initialize game” routine that does this. To do this, I will use a FOR/NEXT loop and generate random X/Y coordinates and call the “toggle” subroutine. This should end up with a random pattern that is 100% solvable.

`4000 REM INITIALIZE GRID4010 PRINT "INITIALIZING..."4020 FOR A=1 TO 104030 X=RND(5)-14040 Y=RND(5)-14050 GOSUB 30004060 NEXT4070 RETURN`

This is what it is doing:

• Line 4010 – Since the FOR/NEXT loop will cause a pause, I wanted to print out something to tell the player what was happening.
• Line 4020 – A FOR/NEXT loop is done so the random grid selections can be done 10 times. (We’ll improve this later.)
• Line 4030 – For X, RND is used to choose a number from 1 to 5. Since the DIM arrays are base-0 (0-4), we subtract 1 so Y will be a number form 0-4.
• Line 4040 – Same thing, but for Y.
• Line 4050 – We GOSUB to the routine that toggles the specific square (X,Y), and any adjacent squares.
• Line 4060 – Continue the FOR/NEXT loop…
• Line 4070 – We return back to wherever we were GOSUB’d from.

At the start of the game, we’d just “GOSUB 4000” to initialize the grid. Here is the complete code, so far:

`10 REM INITIALIZE GRID20 GOSUB 400030 REM SHOW GRID40 GOSUB 100050 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT100 GOTO 301000 REM SHOW GRID1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT1090 RETURN2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4)";X,Y2020 IF X<0 OR X>4 OR Y<0 OR Y>4 THEN 20102030 RETURN3000 REM TOGGLE SQUARES3010 L(X,Y)=NOT L(X,Y)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1)3060 RETURN4000 REM INITIALIZE GRID4010 PRINT "INITIALIZING..."4020 FOR A=1 TO 104030 Y=RND(5)-14040 X=RND(5)-14050 GOSUB 30004060 NEXT4070 RETURN`

And it works! Even on a 1980 4K TRS-80 Color Computer (shown here, emulated in XRoar):

But the game still cannot be won because there is no code to check for a win ;-)

## Defining a “Win”

Since the goal of Lights Out is to turn all the lights out, winning means that the number of lights that are on is zero. One simple (but slow) way to test for this condition would be to scan through the entire grid and add up how many lights are on.

`5000 REM COUNT LIGHTS ON5005 LO=05010 FOR Y=0 TO 45020 FOR X=0 TO 45030 IF L(X,Y) THEN LO=LO+15040 NEXT5050 NEXT5060 RETURN`

To check, that routine is called. If LO=0 then the game has been won. Since the routine counts the number of “on” lights,, the user could also be told how many lights are on. I would probably add this right after it draws the grid, so the final winning grid is shown before the game ends.

`10 REM INITIALIZE GRID20 GOSUB 400030 REM SHOW GRID40 GOSUB 100045 REM CHECK FOR WIN46 GOSUB 500047 IF LO=0 THEN PRINT "YOU WON!":END48 PRINT "LIGHTS ON:";LO50 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT100 GOTO 30`

For a small 5×5 grid, the CoCo seems plenty fast enough to do this check without much of a delay in between moves. If the machine were very slow, or the grid was very large (and thus, took much longer to check), this might not be the best approach.

Another option might be to start with a count of all lights that are on, and decrement that value each time a light is turned off. If a light is turned on, increment it. If the value reaches zero, the game has been won.

But how do we know which lights are on? We’d could just call our “count lights that are on” function after the grid is initialized and get that value.

Or, maybe we don’t use that routine at all. We could put the count routine directly in the routine that toggles the squares on and off:

`3000 REM TOGGLE SQUARES3010 L(X,Y)=NOT L(X,Y)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1)3060 RETURN`

We could increment some variable every time a light is turned on, and decrement it any time a light is turned off.

It looks like our shortcut of using NOT is going to cause us more work. Since we aren’t manually setting the value to something meaning ON, and something else meaning OFF, we have no place add code to increment or decrement our Lights On count. Had we used 1 for on, and -1 for off, we could just add the value of the square (1 or -1) and been done.

But we didn’t.

We know after the NOT toggle, the value will be -1 or 0. Had it been 1 and -1, counting would be very straightforward. But with -1 and 0, we need to somehow make the -1 (meaning TRUE, a light was turned on) be an increment (+1), and the 0 (meaning FALSE, a light was turned off) to be a decrement (-1).

Side Note: There are many ways to write a program. In this one, I chose an easy way to toggle the lights. At the time, I was not considering counting the lights that were on. This NOT approach adds a bit more work to do the count. It could be that adding extra work here might be larger/slower than just doing a count routine that scans the whole grid. Depending on if we are going for speed or memory usage, the design decisions may need to be different.

Mapping this out, I find a simple solution. I can multiply the value (-1 or 0) by 2, and then add 1.

• If the value is -1, multiplying by 2 will make it -2. Then adding 1 will make it -1.
• If the value is 0, multiplying by 2 will be 0. Then adding 1 will make it 1.
`ON: -1 * 2 = -2 + 1 = -1OFF: 0 * 2 = 0 + 1 = 1`

Well, that gets us a +/- 1, but it is backwards from what I would have preferred. To work around that, I can subtract the value. If you subtract -1, it is like adding one. And if you subtract 1, it is like adding a -1. Easy! :)

The updated routine looks like this:

`3000 REM TOGGLE SQUARES 3010 L(X,Y)=NOT L(X,Y):LO=LO-(L(X,Y)*2+1)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y):LO=LO-(L(X-1,Y)*2+1)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y):LO=LO-(L(X+1,Y)*2+1)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1):LO=LO-(L(X,Y-1)*2+1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1):LO=LO-(L(X,Y+1)*2+1)3060 RETURN`

Yuck. But hey, it works!

Now, instead of calling the “count all the squares” routine, we can just reset the LO “lights on” variable during the initialization routine, and it should be decremented/incremented as the game plays.

To test, let’s comment out the call that counts the squares:

`10 REM INITIALIZE GRID20 GOSUB 400030 REM SHOW GRID40 GOSUB 100045 REM CHECK FOR WIN46 REM GOSUB 500047 IF LO=0 THEN PRINT "YOU WON!":END48 PRINT "LIGHTS ON:";LO50 REM INPUT SQUARE60 GOSUB 200070 REM TOGGLE SQUARES80 GOSUB 300090 REM REPEAT100 GOTO 30`

I did a quick test, and this appears to work. It is also faster, since it bypasses the small delay that was happening each time it called the “count all 25 squares” routine. Nice.

Again, the overhead of adding the count in five locations (about 21 bytes each, so 100 bytes extra) does appear to be larger than the “count all the squares” routine. If code size were more important than speed, the count routine would make more sense.

But so far, it still fits on my 1980 4K CoCo with 1514 bytes left to spare (and more room once I remove the un-used “count all the squares” routine). We can add more code! :)

We now have a very primitive but functional version of Lights Out that should guarantee each “random” pattern can be won. The “random” patterns should keep someone from just learning the moves and repeating them to win the level if they play it over and over.

Except they may not be as random as we think.

To be continued…

# The 9 colors of the CoCo’s high resolution screens…

I was today year’s old when I realized the CoCo’s high-resolution color values actually make sense.

Let me just get this right out in the open…

“I feel dumb I never realized the PMODE colors in the manual were correct.”

– Allen

You all probably knew this. If I did, I forgot I knew it. And I really don’t think I ever knew it. Because dumb.

My first CoCo was a grey TRS-80 Color Computer that I got around 1984. Today we call it a “CoCo 1” but back then it was the only CoCo.

The CoCo had eight colors (nine if you count black) that it could display:

The colors are listed as:

• 0 – Black
• 1- Green
• 2 – Yellow
• 3 – Blue
• 4 – Red
• 5 – Buff (I always called it white)
• 6 – Cyan
• 7 – Magenta
• 8 – Orange

When you use the high resolution graphics (PMODEs), you have a choice of a higher high-resolution with 2 colors, or lower high-resolution with 4 colors. Each of these modes has two color sets, which select which 4 or 2 colors you can use on the screen. Here is how the Extended Color BASIC manual describe the PMODEs:

There are some high resolution graphics commands that let you specify a color — such as the COLOR, CIRCLE and DRAW — let you specify a color value to use. I found it odd that the color value was listed as “0-8” — as if you could use nine colors on a high resolution screen. You can’t! Only four, or two.

But the manual listed nine colors, anyway:

The first dumb thing I never realized until today was those high-resolution color numbers are the same as the ones for the text screen, as used by text commands CLS and SET. As I previously wrote about, I also did not realize that the colors available on the high resolution screens were actually the same as the ones on the text screen. I’d never seen them at the same time, and they always “looked different” to me.

But why did Microsoft let you specify color values 0-8 for a screen that can only have four colors? When I started playing with the CoCo again as a grown-up, I assumed Extended Color BASIC must have been ported from a system with more colors and they just left it as-is.

But the manual was weird about it. For example, it would tell you use use colors 5, 6, 7 and 8!

“If you want to try changing the dots’ colors, use buff (5), cyan (6), or magenta (7). Then change the color back to orange (8) before proceeding…”

– Extended Color BASIC manual, page 86

But I knew back then that this was just silly. If you used colors 1, 2, 3 and 4 in one mode, you could also use colors 1, 2, 3 and 4 in the other color set. You’d get the four unique colors in each mode, just different colors based on the mode. (Or you could use 0, 1, 2 and 3 just shifting the order over.)

The important part of the manual was listing which four colors you got when you used SCREEN to specify the color set to use:

SCREEN 1,0 gave you the green/yellow/blue/red colors on a green screen with green border, and SCREEN 1,1 gave you the buff/cyan/magenta/orange colors on a buff screen with a buff border.

Then, there were the higher high-resolution modes that only had two colors. The manual mentioned them (and the four color modes) later:

I guess they were introducing things slowly as you progressed through the chapters.

In a 2-color mode, SCREEN 1,0 gives you a green border with black background and you can draw in green. SCREEN 1,1 gives you a black screen with a white background and you can draw in white.

And my mind was blown when I realized that, though you could use 1-4 on any 4-color screen, or 1-2 on any 2-color screen, and get different colors, the way the manual tried to teach us was basically: “In this mode, use colors A to B. In that mode, use colors C to D” and so on.

Behold! PMODE 3,1:SCREEN 1,0 5-color mode showing what it draws for all 9 colors (0-8):

If you use the color chart, you can see you should be using colors 1-4:

• 1- Green
• 2 – Yellow
• 3 – Blue
• 4 – Red

If you go to PMODE 3,1:SCREEN 1,1 you get these colors:

And here is why the manual told you to use colors 5-8:

• 5 – Buff
• 6 – Cyan
• 7 – Magenta
• 8 – Orange

And in the 2-color mode, if you went PMODE 4,1:SCREEN 1,0 you would get the same two colors repeated over and over:

And that corresponds to using colors 0 and 1 in the chart:

• 0 – Black
• 1- Green

And PMODE 4,1:SCREEN 1,1 looks like this:

Here, you would want to use colors 0 and 5:

• 0 – Black
• 5 – Buff

I don’t know if ANY of us ever programmed using the numbers like that — mostly because the manual really did not make it clear which colors were part of which mode. You’d need a fancier chart that showed what you could do, like:

I would have needed to keep this chart nearby for reference until I memorized it.

What color values did you learn to use when you learned Extended Color BASIC? Leave a comment and let me know.

Until next time…

## Bonus Code

Here’s my sample program.

`0 'COLORS.BAS10 PMODE 3,1:PCLS:SCREEN 1,020 GOSUB 50030 PMODE 3,1:PCLS:SCREEN 1,140 GOSUB 50050 PMODE 4,1:PCLS:SCREEN 1,060 GOSUB 50070 PMODE 4,1:PCLS:SCREEN 1,180 GOSUB 500499 END500 ' SHOW COLORS505 DRAW"BM10,3 D8R8U8NL8 BR20 ND8 BR28 R8D4L8D4R8 BR20 R8U4NL8U4NL8 BR20 D4R8NU4D4 BR20 R8U4L8U4R8 BR20 NR8D8R8U4NL8BU4 BR20 R8D8 BR20 R8U8L8D4R8"510 FOR C=0 TO 8520 COLOR C530 LINE (C*28,16)-(C*28+27,191),PSET,BF540 NEXT550 IF INKEY\$="" THEN 550560 RETURN`

# Let’s write Lights Out in BASIC – part 2

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

• 2023-02-06 – William Astle pointed out that Color BASIC doeshave ELSE. Not sure why I thought it didn’t — I never had a machine with plain Color BASIC. Striked out!

In the first installment, I shared a brief history of the game Lights Out using “extensive” research from the Wikipedia page and some YouTube videos.

This time, let’s look begin implementing the game in BASIC. My first goal is to write something generic enough that it could be easily ported to other systems. I specifically have VIC-20 in mind, since it was my first home computer.

After this is achieved, maybe we can see how much we could optimize and enhance it specifically for the CoCo (or VIC).

In Rick Adams‘ CoCo 3 version, he uses what appears to be the high-resolution 320×200 16-color graphics screen. It uses a joystick to move around and select squares.

It is quite nice, and reminds me of how his Shanghai game was controlled. (Rick wrote the official Color Computer version, sold on a ROM-Pak cartridge by Radio Shack.)

For my version, I’ll only use the text screen, and the keyboard to select squares.

## Representing the Grid of Lights

Since the game is played on a 5×5 grid, a simple (and obvious) way to represent that grid of lights might be to use a two-dimensioned array. Something like this:

`DIM L(4,4)`

That may look wrong for a 5×5 grid, but on Color BASIC, dimensions start at 0. DIM X(4) gives entries X(0), X(1), X(2), X(3) and X(4). For DIM L(4,4) we get:

`+---+---+---+---+---+---+| . | 0 | 1 | 2 | 3 | 4 |+---+---+---+---+---+---+| 0 | . | . | . | . | . |+---+---+---+---+---+---+| 1 | . | . | . | . | . |+---+---+---+---+---+---+| 2 | . | . | . | . | . |+---+---+---+---+---+---+| 3 | . | . | . | . | . |+---+---+---+---+---+---+| 4 | . | . | . | . | . |+---+---+---+---+---+---+`

If I were to do L(0,0)=123, the top left square would be 123:

`+---+---+---+---+---+---+| . | 0 | 1 | 2 | 3 | 4 |+---+---+---+---+---+---+| 0 |123| . | . | . | . |+---+---+---+---+---+---+| 1 | . | . | . | . | . |+---+---+---+---+---+---+| 2 | . | . | . | . | . |+---+---+---+---+---+---+| 3 | . | . | . | . | . |+---+---+---+---+---+---+| 4 | . | . | . | . | . |+---+---+---+---+---+---+`

Then if I did L(3,2)=456:

`+---+---+---+---+---+---+| . | 0 | 1 | 2 | 3 | 4 |+---+---+---+---+---+---+| 0 |123| . | . | . | . |+---+---+---+---+---+---+| 1 | . | . | . | . | . |+---+---+---+---+---+---+| 2 | . | . | . |456| . |+---+---+---+---+---+---+| 3 | . | . | . | . | . |+---+---+---+---+---+---+| 4 | . | . | . | . | . |+---+---+---+---+---+---+`

## Toggling a Grid Value

By having a two-dimensional 5×5 array like that, I can represent the 25 squares of the Lights Out game. If I made it so a value of 0 was “off” and a value of “1” was on, I could toggle the value of a square using some simple logic like this:

`IF L(X,Y)=1 THEN L(X,Y)=0 ELSE IF L(X,Y)=0 THEN L(X,Y)=1`

Or, since I know I am only going to be putting a 0 or 1 there, I could simplify:

`IF L(X,Y)=1 THEN L(X,Y)=0 ELSE L(X,Y)=1`

That’s a bit clunky, and requires a BASIC that has the ELSE keyword. While the CoCo got ELSE with Extended BASIC, it was not present on the original Color BASIC. (Thanks, William A.!) My Commodore VIC-20 does not have it. To avoid using ELSE, it could be written like this:

`100 IF L(X,Y)=1 THEN L(X,Y)=0:GOTO 120110 L(X,Y)=1120 ...program continues...`

That “GOTO 120” to skip the next line is very important, else the first line would set it to 0, then the next line would set it back to 1. See? Clunky.

Since our goal is simply to toggle a square from on to off, or from off to on, the value is not important. It could be any two values, such as -57 and +123, using that code.

BUT, we can do better. We can make use of the BASIC mathematical NOT keyword. NOT is available in 1980 Color BASIC and even on the VIC-20.

NOT can be used on a number to flip it back and forth between two values:

`PRINT NOT 0-1PRINT NOT -10`

If we made 0 mean OFF, and -1 mean ON, we could toggle them back and forth by using NOT.

`100 IF L(X,Y)=NOT L(X,Y)`

That looks much simpler. And, as an added bonus, when you compare things in BASIC, the result is either -1 for TRUE, or 0 for FALSE. This is what the IF keyword is expecting. For example:

`IF -1 THEN PRINT "THIS IS TRUE"IF 0 THEN PRINT "YOU WON'T SEE THIS"`

That will print “THIS IS TRUE”.

This would allow printing something quite easily based on the variable. We could use a FOR/NEXT loop for each row of the grid, and a second FOR/NEXT loop for each column in that row. A simple check could be done to decide if an “X” or “Y” should be printed for that grid element.

`1000 REM SHOW GRID1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT "X";:GOTO 10501040 PRINT ".";1050 NEXT1060 PRINT1070 NEXT1080 PRINT`

Since 0 represents FALSE (light is on), and since BASIC variables are initialized to 0, running that program should present a grid of all lights off (represented by a dot):

`.........................`

If we set some of those array elements to -1 (FALSE, off), like this:

`10 L(0,0)=-120 L(1,1)=-130 L(2,2)=-140 L(3,3)=-150 L(4,4)=-1`

…then running it would show something like this:

`X.....X.....X.....X.....X`

This gives us a very simple “show grid” subroutine.

## Selecting a Square to Toggle

If we go really, really old school, we could use INPUT and ask the user to tell us which square to toggle by using X and Y coordinates.

`2000 REM INPUT SQUARE2010 INPUT "X (0-4)";X2020 INPUT "Y (0-4)";Y`

Or, both variables could be asked for at the same time using “INPUT X,Y” like this:

`2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4)";X,Y`

To make sure typing a number larger than the array size (like 5), or smaller (like -5), does not crash the program, we should add some error checking:

`2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4)";X,Y2020 IF X<0 OR X>4 OR Y<0 OR Y>4 THEN 2010`

Do you remember when we were learning BASIC like this? I promise, we’ll make it less remedial later.

## Toggling that Square

Once we know the X and Y for a square inside the array, we can toggle that square as shown earlier:

`L(X,Y)=NOT L(X,Y)`

If the square value was 0, it will become -1. If it was -1, it will become zero. NOT does the work for us.

But, the way Lights Out works is it not only toggles that square, but the ones above, below, left and right of it (if there is a square there). Our toggle routine should do all that for us — and it should also know when there is not a square above, below, left or right of it:

`3000 REM TOGGLE SQUARES3010 L(X,Y)=NOT L(X,Y)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1)`

Let’s walk through that…

• Line 3010 – toggles the selected square.
• Line 3020 – if the selected square’s column (X) is greater than 0 (1-4), there will be a square to the left. Toggle that square (X-1).
• Line 3030 – if the selected square’s column (X) is less than 4 (0-3), there will be a square to the right. Toggle that square (X+1).
• Line 3040 – if the selected square’s row (Y) is greater than 0 (1-4), there will be a square above it. Toggle that square (Y-1).
• Line 3050 – if the selected square’s row (Y) is less than 4 (0-3), there will be a square below it. Toggle that square (Y+1).

## Putting it all together…

By adding a “RETURN” at the end of those three blocks of code, we can make them subroutines and call them using GOSUB. We now have the basic framework for a Lights Out game!

`10 REM SHOW GRID20 GOSUB 100030 REM INPUT SQUARE40 GOSUB 200050 REM TOGGLE SQUARES60 GOSUB 300070 REM REPEAT80 GOTO 101000 REM SHOW GRID1010 FOR Y=0 TO 41020 FOR X=0 TO 41030 IF L(X,Y) THEN PRINT ".";:GOTO 10501040 PRINT "X";1050 NEXT1060 PRINT1070 NEXT1080 PRINT1090 RETURN2000 REM INPUT SQUARE2010 INPUT "X,Y (0-4,0-4)";X,Y2020 IF X<0 OR X>4 OR Y<0 OR Y>4 THEN 20102030 RETURN3000 REM TOGGLE SQUARES3010 L(X,Y)=NOT L(X,Y)3020 IF X>0 THEN L(X-1,Y)=NOT L(X-1,Y)3030 IF X<4 THEN L(X+1,Y)=NOT L(X+1,Y)3040 IF Y>0 THEN L(X,Y-1)=NOT L(X,Y-1)3050 IF Y<4 THEN L(X,Y+1)=NOT L(X,Y+1)3060 RETURN`

BUT, since variables initialize as 0, and see means FALSE (off), there would be no lights on at the start of this game. The game would initialize to “already won” ;-) There would need to be some kind of initializing routine that sets some or all of the squares “on” at the start of the game.

But even with that, this would still be an un-win-able game – there is no code that checks to see if all the lights have been turned off.

Let’s add that in the next installment…

# Displaying all 11 of the CoCo’s 8 colors…

I was today years old when I learned that the colors of the CoCo’s high resolution graphics screens are the same as the colors of the text mode semigraphics.

I knew that the CoCo’s MC6847 video chip could produce eight colors on the text screen. The manual describes them as green, yellow, blue, red, buff, cyan, magenta and orange. (Okay fine. It is really nine since you have black as well.)

These eight colors are shown in an example program in the Radio Shack quick reference guide. You will notice this does not draw a black strip for the 9th color – I guess theblack border is enough of a color test for black.

On the text screen, these colors are part of the character set. Each character block can have colors set in a 2X2 grid, with one color plus black per character location.

I also knew that when you went in to one of the 4-color high resolution graphics modes, PMODE 1 or PMODE 3, you had two sets of colors available.

In SCREEN 1,0, you get a green border, and four colors – green, yellow, blue and red.

In SCREEN 1,1, you get a white border and four colors – white, green, purple and orange.

I wondered if it might be possible to write some code to switch graphics modes and get all of these colors on screen at the same time. I created a sample of what it might look like … and then I realized these colors are all the same!

For SCREEN 1,0 you are getting the same green, yellow, blue and red that the text screen has.

For SCREEN 1,1 you are getting the same buff, cyan, magenta and orange that the text screen has.

“I feel dumb I never realized they were the same colors!”

– Allen

Here is the program I used to switch between them to get my screen shots…

`0 'ALL COCO 1/2 COLORS10 CLS0:PRINT@4*32,;20 FOR R=0 TO 330 FOR C=0 TO 340 PRINT STRING\$(8,143+C*16);50 NEXT:NEXT60 FOR R=0 TO 370 FOR C=4 TO 780 PRINT STRING\$(8,143+C*16);90 NEXT:NEXT95 GOSUB 1000100 ' COLOR SET 0110 PMODE 1,1:PCLS:SCREEN 1,0120 FOR C=1 TO 3130 COLOR C:LINE((C-1)*64,0)-((C-1)*64+63,0+47),PSET,BF140 NEXT145 COLOR 0:LINE(3*64,0)-(3*64+63,0+47),PSET,BF150 GOSUB 1000200 ' COLOR SET 1210 PMODE 1,1:PCLS:SCREEN 1,1220 FOR C=1 TO 3230 COLOR C:LINE((C-1)*64,144)-((C-1)*64+63,144+47),PSET,BF240 NEXT245 COLOR 0:LINE(3*64,144)-(3*64+63,144+47),PSET,BF250 GOSUB 1000999 END1000 IF INKEY\$="" THEN 10001010 RETURN`

This means, even with the two different graphics mode color sets, you still only get those eight (or nine, including black) colors to play with.

BUT… technically there are more color than that. The color of the text characters is not black — but some kind of dark green (see the square I drew to the left of the text, below):

And, there is an alternate color set for the text screen that has a different color for the text, and a different color for the background.

Or does it?

Admittedly, the usefulness of the text colors is limited since you cannot do anything with those colors except put text characters on the screen with them… (More on this in a moment…)

Having the alternate background does seem useful. Or is it?

I was today years old when I learned that the alternate background text color (SCREEN 0,1) is the same as one the orange primary color (CHR\$ 255), just as the normal background text color (SCREEN 0,0) is the same as the green primary color (CHR\$ 143)!

Sample code:

`10 CLS20 PRINT "----SPACES-----";CHR\$(128);CHR\$(128)"---CHR\$(143)---";30 FOR R=1 TO 1440 PRINT STRING\$(15," ");STRING\$(2,128);STRING\$(15,143);50 NEXT60 PRINT "----SPACES-----";CHR\$(128);CHR\$(128)"---CHR\$(143)--";70 IF INKEY\$="" THEN 7080 CLS90 PRINT "----SPACES-----";CHR\$(128);CHR\$(128)"---CHR\$(255)---";100 FOR R=1 TO 14110 PRINT STRING\$(15," ");STRING\$(2,128);STRING\$(15,255);120 NEXT130 PRINT "----SPACES-----";CHR\$(128);CHR\$(128)"---CHR\$(255)--";140 SCREEN 0,1150 GOTO 70`

So I guess that, even with the alternate color set, you still only have the same eight colors plus black – plus whatever color the text is, which you cannot use.

Or can you?

Lowercase is represented by inverted video, and although you cannot PRINT a lowercase space, you can POKE it to the screen.

`POKE 1024,32`

That will poke the inverted space to the top left of the 32 column screen.

And that is another color!

Let’s update the color bar…

`10 CLS20 FOR R=0 TO 1530 PRINT @R*32,"X";40 FOR C=0 TO 750 PRINT STRING\$(3,143+C*16);60 NEXT70 PRINT STRING\$(3,128);80 POKE 1024+32*R+28,32:POKE 1024+32*R+29,32:POKE 1024+32*R+30,3290 POKE 1024+32*R+31,ASC("X")100 NEXT110 IF INKEY\$="" THEN 110120 SCREEN 0,1130 IF INKEY\$="" THEN 130140 SCREEN 0,0150 GOTO 110`

This program will print vertical bars of the 9 semigraphics block colors – black, green, yellow, blue, red, buff, cyan, magenta and orange.

It then uses POKE to set three blocks on each line to an inverted space (“lowercase space”) to show that color. The end result is ten colors on the screen:

Look closely on the right — there is black bar, then a bar using the text color (inverted space), then the bar of Xs.

Pressing a key flips to the alternate color mode and that helps make that last column easier to see:

This means if you wanted to do glorious 32×16 color graphics, you actually have 11 colors you can choose from, though that would be the ten at a time (nine base colors plus the text color of the mode).

But I expect many of you already knew this.

# Let’s write Lights Out in BASIC – part 1

See also: part 1, part 2, part 3, part 4, part 5, part 6 and part 7.

Recently, Rick Adams let me see a CoCo 3 Lights Out game he was working on. I have heard of the Lights Out, but have never played it. I gave it a shot…

I was immediately frustrated by how difficult such a simple game could be to win. In fact, I have yet to purposely win it, but I did get lucky one time and accidentally won.

For those who, like I was, are unfamiliar with the game… There is a 5×5 grid of squares. Of the 25 squares, random squares will be “on”, represented as green in Rick’s version. The goal is to turn them all off, represented by black.

You select a square, and that square, and the squares above, below, left and right of it will switch their state. If an adjacent square is on, it will be turned off. If it is off, it will be turned on. If you are at the edge of the grid, it does not wrap around and affect any squares on the other side.

Simple… and incredibly frustrating. I can manage to get down to one or two squares, but still haven’t figured out a pattern to shut them all off. It reminds me of when I was trying to figure out a Rubik’s Cube when they were new (maybe around 1979 or 1980?). I never did. I gave up the first week and ordered the official solution manual.

I recall Lights Out being quite trendy in recent years — maybe as a phone app or something online. This made me wonder about the origin of the game. I decided to do some “intensive/extensive” research.

## 1990s

From checking the always accurate and reliable Wikipedia, I learned that a game called “Lights Out” first appeared in 1995 as a handheld electronic game from Tiger Electronics. That version used a 5×5 grid of push button lights. Here is a commercial for it:

From that TV ad, I learned that not only was there the 5×5 original, but also a “Deluxe Lights Out” that used a 6×6 grid.

In 1997 they also released Lights Out in cartridge form for their touchscreen Game.com game system. I owned one of those, and since I read this game was included with the system, perhaps I did play it back then. From looking at a gameplay video, this version appears to use a 6×6 grid of lights, which I suppose made it closer to Deluxe Lights Out.

Side note: I believe it was the late Steve Bjork that told me about Game.com. It had the potential to be a Gameboy Killer, but disappeared into obscurity instead. I had one and a number of the cartridges. I actually found my Game.com Monopoly cartridge a few weeks ago, but I sold the game unit years ago.

But I digress…

## 1980s

Tiger Electronics was not the first to sell this game — only the first (that I can find) to call it Lights Out. In 1983, there was a handheld game called XL25 from Vulcan Electronics . It appears to play the same style game — except the goal was to turn all the lights ON instead of off… Did Tiger rip them off, 12 years later? (And what does XL25 even mean?)

## 1970s

The Wiki also mentions a similar game existed in the 1970s for the Parker Brothers Merlin handheld system. I remember seeing TV ads for Merlin, and I recall wanting one. I don’t think I ever even got to play with one, though.

From this TV ad, the game in question appears to be Magic Square. The goal of it was not to get all of its 3×3 lights off or on, but to make just the outer lights on to form a square.

It does appear the game mechanics where the same as Lights Out.

Did Magic Square lead to XL25 which led to Lights Out? Or was there something even earlier? Maybe on some mainframe system? Leave a comment if you have more information on just what “Lights Out” patient zero is.

## Present Day (not Christmas or Birthday)

Since the concept was known in the 1970s, someone could have used it for inspiration to write a CoCo version of the Merlin 3×3 “Magic Square” on a 1980 CoCo. In 1983, a CoCo owner could have created a 5×5 XL25 version. Heck, many of us were still using our CoCos in 1995 and 1997 when Tiger Electronics had their 5×5 and 6×6 versions.

Did you ever see this game on the CoCo back then?

Inspired by Rick Adams’ work, I thought it might be fun to see how much effort this game would be to write. I expect it will be much easier to write than it is to win.

In the next installment, we’ll look at some ways to implement this game in Color BASIC.

Until then…