NIM 2K

Developer(s): Fred Nachbaur
Date: 1984
Type: Cassette
Platform(s): TS 1000
Tags: Game

NIM 2K implements the classic mathematical strategy game Nim for two human players, fitting entirely within a 2K RAM machine. The board displays seven rows, each initially containing seven objects, and players take turns removing one to seven objects from a single row; the player left with the last object loses. A notable technical constraint is that the program exploits the compressed display file of the 2K machine: it calculates display-file addresses directly using PEEK 16396 and 16397 to obtain the base address, then computes individual cell locations via the formula DF+38*H+2*I+1, POKEing character codes from an animation string to erase tokens. Variable names like N0N2, N7, O7, and P1 cache frequently used numeric constants, a common 2K RAM conservation technique. The delay routine at line 250 spins on an empty INKEY$ loop rather than using PAUSE, and VAL “number” is used in GO TO and GO SUB targets to save memory.

Demonstrates what’s possible in just 2K of RAM, using only standard Sinclair BASIC. Because it uses the characteristics of the compressed display file, if you want to run it in a 16K ZX81 or emulator, you first have to POKE 16389, 72 then NEW before loading.


Program Analysis

Program Structure

The program is organized into a compact set of functional blocks, exploiting line-number ranges as a rough substitute for named procedures:

  1. Lines 10–110: Initialization — set SLOW mode, cache numeric constants, probe display file base address, and display the title banner.
  2. Lines 120–170: Player name entry loop (two players).
  3. Lines 200–270: Subroutines — address calculator (200), validated numeric input 1–7 (220), and a keypress/delay loop (250).
  4. Lines 300–390: Board setup — CLS, initialize the row-state string X$ and object count N, draw the seven rows of tokens.
  5. Lines 500–810: Main game loop — prompt for row, validate, prompt for count, validate, animate removal via POKE, update state, test win/lose conditions.
  6. Lines 820–940: End-of-game messages, play-again prompt, and optional side-swap.
  7. Lines 1000–1010: SAVE and RUN.

Constant Caching

A hallmark 2K technique is pre-computing frequently used literals into variables at startup, avoiding repeated tokenization of numeric literals throughout the program:

VariableValueUsed for
N00Zero comparisons, loop initialization, AT column
N11Loop starts, STEP, index arithmetic
N22Player count, DIM, address formula
N77Row count, object count, loop bounds
O717AT row for status messages
P121AT row for input prompts

Using VAL "number" on the right-hand side of LET (lines 20–70) is itself a space-saving trick, as the stored string representation can be shorter than a full numeric literal in some BASIC implementations. The same idiom is used in GO TO VAL "..." and GO SUB VAL "..." throughout.

Display File Address Calculation

The 2K compressed display file does not use the standard 6912-byte layout; instead each print position maps more compactly. Line 80 reads the display file base address from system variables:

LET DF=PEEK 16396+256*PEEK 16397

The subroutine at line 200 then computes the exact byte address of a token in row H, column I:

LET L=DF+38*H+N2*I+N1

which expands to DF + 38*H + 2*I + 1. This reflects the 2K display file’s 38-byte-per-line stride and 2-byte-per-character encoding. The game then uses POKE L, CODE B$(A) to cycle through the animation string B$="▞▚▞*. ", replacing the token graphic with successive characters ending in a space, giving a rudimentary erasure animation.

Game Logic

Row occupancy is tracked by the seven-character string X$="1111111" (line 340); a row’s character is set to "0" when all its objects are removed (line 730). The total object count N starts at 49 (N7*N7) and is decremented by the number taken each turn (line 740).

  • If N=0 after a move, the current player took the last object and loses (line 820 — “YOU’RE A FOOL”).
  • If N=1 before a move, the current player is forced to take the last object, so the other player wins (line 840).

Finding the topmost remaining object in a row (lines 600–620) iterates I from 7 down to 1, calling subroutine 200 and checking PEEK L=N0 to skip already-empty cells. The removal loop (lines 640–720) then steps back from I by S positions, POKEing each cell.

Input Validation

The subroutine at line 220 uses INPUT A and loops back to itself if the entered value is outside 1–7:

IF A<N1 OR A>N7 THEN GOTO VAL "220"

A separate check at line 630 catches the case where the player requests more objects than remain in the chosen row, jumping to an error message and re-prompting. Row-empty validation (lines 520–550) checks the X$ flag string rather than re-scanning the display.

Delay and Keypress Routines

The subroutine at line 250 implements a combined pause-and-keypress-skip: it counts up to N7*O7 (119) iterations, returning early if any key is held. This is used after error messages and the title screen to give the player time to read before continuing.

The play-again prompt (lines 860–930) polls INKEY$ in a tight loop, branching on “Y” or “N”. The side-swap prompt at line 910 similarly polls until a valid key is seen, then sets the turn variable T using the boolean expression (INKEY$="Y"), which evaluates to 1 (true) or 0 (false).

Notable Techniques and Anomalies

  • N$(T+N1) selects the current player’s name by adding 1 to the 0/1 turn flag, indexing into the two-row string array. This avoids an IF/THEN branch.
  • Line 170 has no line 160 — a harmless gap.
  • The removal animation string B$="▞▚▞*. " has six characters; iterating over all of them means each cell gets POKEd six times before settling on a space, producing a brief flicker effect visible in SLOW mode.
  • NOT T at line 770 cleanly toggles the turn between 0 and 1 without arithmetic.
  • The use of GO TO VAL "900" at line 900 (targeting itself) combined with an INKEY$ check creates a wait-for-keypress loop that stalls until any key is released before proceeding — a standard INKEY$ debounce pattern.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Source Code

  10 SLOW
  20 LET N0=VAL "0"
  30 LET N1=VAL "1"
  40 LET N2=VAL "2"
  50 LET N7=VAL "7"
  60 LET O7=VAL "17"
  70 LET P1=VAL "21"
  80 LET DF=PEEK 16396+256*PEEK 16397
  90 LET T=N0
 100 DIM N$(N2,N7)
 110 PRINT AT N7,N7;"▌▌▌[*] [N][I][M] [*]▐▐▐",,,,"BY F.NACHBAUR",,,
 120 GOSUB VAL "250"
 130 FOR A=N1 TO N2
 140 PRINT "NAME-PLAYER ";A;"?"
 150 INPUT N$(A)
 170 NEXT A
 180 LET B$="▞▚▞*. "
 190 GOTO VAL "300"
 200 LET L=DF+38*H+N2*I+N1
 210 RETURN
 220 INPUT A
 230 IF A<N1 OR A>N7 THEN GOTO VAL "220"
 240 RETURN
 250 FOR A=N0 TO N7*O7
 255 IF INKEY$ <>"" THEN RETURN
 260 NEXT A
 270 RETURN
 300 CLS
 340 LET X$="1111111"
 350 LET N=N7*N7
 360 PRINT "[R][O][W]",
 370 FOR A=N1 TO N7
 380 PRINT ,,," ";A;"  ";"[O] [O] [O] [O] [O] [O] [O] ";
 390 NEXT A
 500 PRINT AT O7,N0;"YOUR TURN,";N$(T+N1);AT P1,N0;"WHICH ROW? "
 510 GOSUB 220
 520 IF X$(A)="1" THEN GOTO 560
 530 PRINT AT P1,N0;"█[R][O][W]█[E][M][P][T][Y][.]"
 540 GOSUB VAL "250"
 550 GOTO VAL "500"
 560 LET H=A
 570 PRINT AT P1,N0;"HOW MANY?  "
 580 GOSUB 220
 590 LET S=A
 600 FOR I=N7 TO N1 STEP -N1
 610 GOSUB 200
 620 IF PEEK L=N0 THEN NEXT I
 630 IF S>I THEN GOTO 790
 640 FOR I=I TO I-S+N1 STEP -N1
 650 GOSUB 200
 660 FOR A=N1 TO LEN B$
 670 POKE L,CODE B$(A)
 680 NEXT A
 720 NEXT I
 730 IF I=N0 THEN LET X$(H)="0"
 740 LET N=N-S
 750 IF N=N0 THEN GOTO 820
 760 IF N=N1 THEN GOTO 840
 770 LET T=NOT T
 780 GOTO 500
 790 PRINT AT P1,N0;"[T][O][O]█[M][A][N][Y][.]  "
 800 GOSUB VAL "250"
 810 GOTO 500
 820 PRINT AT O7,N0;"YOU""RE A FOOL,";N$(T+N1)
 830 GOTO VAL "850"
 840 PRINT AT O7,N0;"YOU WIN, ";N$(N1+T)
 850 PRINT AT P1,N0;"AGAIN? Y/N"
 860 IF INKEY$ ="Y" THEN GOTO 890
 870 IF INKEY$ ="N" THEN STOP
 880 GOTO 860
 890 PRINT AT P1,N0;N$(N2);" STARTS?"
 900 IF INKEY$ <>"" THEN GOTO VAL "900"
 910 LET T=(INKEY$ ="Y")
 930 IF INKEY$ <>"Y" AND INKEY$ <>"N" THEN GOTO 910
 940 GOTO VAL "300"
 1000 SAVE "NI[M]"
 1010 RUN 

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top