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!

Bigger grid, please

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 GRID
4005 INPUT "GRID SIZE (3-10)";GS
4006 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 GAME
6 GOSUB 6000
10 REM INITIALIZE GRID
15 MV=0
20 GOSUB 4000
30 REM SHOW GRID
40 GOSUB 1000
47 IF LO=0 THEN 200
50 REM INPUT SQUARE
60 GOSUB 2000
70 REM TOGGLE SQUARES
80 GOSUB 3000
90 REM REPEAT
95 MV=MV+1
100 GOTO 30

200 REM GAME WON
220 PRINT "YOU WON IN";MV;"MOVES."
230 INPUT "PLAY AGAIN (Y/N)";Q$
240 IF Q$="Y" THEN 5
250 PRINT "GAME OVER"
260 END

1000 REM SHOW GRID
1005 PRINT "GAME NUMBER:";GN
1006 PRINT " ";
1007 FOR A=1 TO GS
1008 PRINT RIGHT$(STR$(A),2);
1009 NEXT:PRINT
1010 FOR Y=0 TO GS-1
1015 PRINT RIGHT$(STR$(Y+1),2);" ";
1020 FOR X=0 TO GS-1
1030 IF L(X,Y) THEN PRINT "X ";:GOTO 1050
1040 PRINT ". ";
1050 NEXT
1060 PRINT
1070 NEXT
1080 PRINT "MOVES:";MV;"LIGHTS ON:";LO
1090 RETURN

2000 REM INPUT SQUARE
2010 PRINT "X,Y (1-";GS;",1-";GS;" OR 0,0)";
2011 INPUT X,Y
2015 IF X=0 THEN IF Y=0 THEN 230
2020 IF X<1 OR X>GS OR Y<1 OR Y>GS THEN 2010
2025 X=X-1:Y=Y-1
2030 RETURN

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<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 RETURN

4000 REM INITIALIZE GRID
4005 INPUT "GRID SIZE (3-10)";GS
4006 IF GS<3 OR GS>10 THEN 4005
4010 PRINT "INITIALIZING..."
4020 FOR A=1 TO 10
4030 Y=RND(GS)-1
4040 X=RND(GS)-1
4050 GOSUB 3000
4060 NEXT
4070 RETURN

6000 REM SELECT GAME
6010 PRINT "PLAY SPECIFIC GAME # (Y/N)?"
6020 S=S+1:A$=INKEY$:IF A$="" THEN 6020
6030 IF A$="Y" THEN 6060
6040 IF A$="N" THEN A=RND(-S)
6045 GN=RND(65535):A=RND(-GN)
6046 GOTO 6090
6050 GOTO 6020
6060 INPUT "PLAY GAME (1-65535)";GN
6070 IF GN<1 OR GN>65535 THEN 6060
6080 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…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.