Fox at Dusk

This file is part of and Timex Sinclair Public Domain Library Tape 1006. Download the collection to get this file.
Date: 198x
Type: Program
Platform(s): TS 1000
Tags: Game

This program implements a two-player strategic board game called “Fox at Dusk” on an 8×8 checkerboard. The human controls a set of hounds (3–8, user-selectable) while the computer controls a fox; pieces move diagonally and the fox can leap over hounds. A difficulty toggle hides the fox except when it leaps or collides with a hound. The board is drawn using ZX81 block graphics characters, with each square rendered as a 3×3 character cell. The fox’s AI scores candidate moves using a weighted random formula that accounts for board depth, proximity to row 1, and whether a leap over a hound is possible.


Program Analysis

Program Structure

The program is organised into a main flow followed by a set of subroutines accessed via GOSUB. The top-level sections are:

  1. Lines 10–90: Initialisation, title screen, difficulty prompt.
  2. Lines 100–140: Hound-count input and validation.
  3. Lines 160–480: Board array setup and hound placement.
  4. Lines 490–560: Fox placement and first display.
  5. Lines 560–1160: Main game loop — human hound move, then fox AI move.
  6. Lines 1170–1240: Single-digit input subroutine (returns value in Z).
  7. Lines 1250–1360: Board rendering subroutines for hound, fox, and blank square.
  8. Lines 1370–1420: Fox-leap logic.
  9. Lines 1430–1490: Win/loss messages.
  10. Lines 1510–1570: Fox flash animation subroutine.
  11. Lines 1580–1600: SAVE and RUN for auto-restart.

Board Representation

The game state is held in A$(8,8), an 8×8 string array. Each cell contains one character: "B" for a black square (off-limits), "H" for a hound, "F" for the fox, or " " (space) for an empty playable square. The checkerboard pattern is set at lines 320–360 by testing whether (A+B) is odd. The fox’s current column and row are tracked separately in scalar variables E and F.

Screen Layout and Block Graphics

Each board square occupies a 3×3 character cell on screen. The column-to-screen mapping is 3*(X-1) and the row mapping inverts the board with 3*(8-Y), placing row 8 at the top and row 1 at the bottom. ZX81 block graphics characters are used to draw checkerboard shading (lines 220–290) and to render the hound (GOSUB 1250), fox (GOSUB 1300), and erased square (GOSUB 1340) as distinct 3-row sprites.

The title area in the right margin (columns 25–31) uses inverse-video characters for labels and move prompts, rendered with PRINT AT statements that leave the board area untouched.

Input Subroutine

The subroutine at line 1170 implements a robust single-keystroke digit reader. Line 1180 first flushes any held key with a busy-wait loop, lines 1190–1200 wait for a new keypress, and lines 1210–1230 reject characters outside "1""8" (looping back to flush again). The accepted character is echoed with PRINT C$;, converted to a column/row integer via CODE C$-28 (since CODE "1" = 29 on the ZX81), and returned in Z. The human enters the column then the row on two separate calls (lines 580–600 and 630–650).

Move Validation

A compact string expression is stored at line 170:

LET B$="A>8 OR A<1 OR B>8 OR B<1"

This string is later evaluated with VAL B$ at line 880 and line 1400 to perform bounds-checking on candidate positions — a classic ZX81 memory-saving idiom that avoids repeating the condition in code. Human hound moves are validated at line 710, which checks that the source cell contains "H", the destination is empty " ", and both column and row distances are exactly 1.

Fox AI

The fox AI (lines 820–1010) iterates over the four diagonal neighbours of the fox’s current position (E,F) using nested FOR loops over W=F-1 TO F+1 STEP 2 and V=E-1 TO E+1 STEP 2. For each candidate square it computes a score in T:

  • 3*RND: random noise (0–3) to vary play.
  • (B<F): +1 if the move advances toward row 1 (the fox’s goal).
  • (B=1): +1 bonus for landing on the winning row immediately.

The best-scoring move is stored in (X,Y) and M tracks the maximum score. If a candidate square is occupied by a hound, the leap subroutine at line 1370 is called, which projects the fox two squares in that direction and retries with a reduced random weight (T=RND). If M remains 0 after all candidates are examined, the fox is trapped and the player wins (line 1030).

Visibility (“Dusk”) Mechanic

Variable I is set to 1 (easy mode) or 0 (hard mode) at line 80 based on the player’s "Y"/"N" answer. The fox sprite is drawn at line 1090 whenever G is true (a leap occurred), and at line 1150 when G OR I — meaning in easy mode it is shown every move, while in hard mode it is only shown after a leap. The flash animation subroutine at line 1510 toggles the fox sprite on and off four times to draw attention to leaps.

Notable Techniques and Idioms

  • POKE 16418,2 at line 30 sets the system variable controlling the display file, and POKE 16418,0 at line 200 restores it — used here to manipulate the display during setup under FAST mode.
  • LET H=CODE H$-28 (line 130) converts the ASCII digit character to a numeric count using the ZX81 character code offset, consistent with the same technique in the input subroutine.
  • The hound-placement loop (lines 380–480) fills the bottom two rows of playable squares left-to-right until H hounds have been placed, decrementing H each time and stopping when NOT H is true.
  • SAVE "1025" at line 1590 (where is an inverse digit) saves the program with the auto-run flag set, so reloading the tape starts the game immediately.

Bugs and Anomalies

  • Line 1260 stores a value into Z (LET Z=3*(X-1)) but this is the hound-draw subroutine entered at line 1250 — line 1250 itself does not exist in the listing; the subroutine effectively starts at 1260. The GOSUB 1250 calls target this gap, which on the ZX81 causes execution to continue from the next higher line (1260), so it functions correctly.
  • Similarly, GOSUB 1290 (called for the win/loss display at lines 1430 and 1470) targets a non-existent line; execution falls through to line 1300, which draws the fox. This means the fox is always revealed on game-end regardless of the visibility mode — likely intentional.
  • The instruction text at line 50 contains the typo “COLUME” (for “COLUMN”) and the run-together word “THENTHE”.
  • Lines 20 and 550 are referenced by GOTO (lines 1460 and 1160 respectively) but do not appear in the listing. GOTO 20 restarts near the beginning (falling through to line 30), and GOTO 550 re-enters the human move prompt section (falling through to line 560) — both are deliberate restart targets.

Content

Appears On

Assembled by Tim Ward from many sources. Contains programs 10252 – 10293.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

  10 RAND 
  30 POKE 16418,2
  40 CLS 
  50 PRINT TAB 10;"""FOX AT DUSK""",,,"TRAP THE FOX SO IT CANNOT MOVE. FOX AND HOUNDS MOVE ONE SPACE   DIAGONALLY UP OR DOWN, BUT THE  FOX MAY LEAP OVER A HOUND.","   ENTER MOVES COLUME FIRST THENTHE ROW..E.G. 11 IS BOTTOM LEFT CORNER.",,
  60 PRINT "  AT DUSK THE FOX CAN ONLY BE   SEEN AT THE GAME START, WHEN IT LEAPS OVER A HOUND, OR WHEN A   HOUND TRIES TO MOVE INTO THE    SQUARE THAT THE FOX IS IN.",,,,,,,"WOULD YOU PREFER THE EASIER GAMEWHERE YOU SEE THE FOX WHENEVER  IT MOVES?"
  70 INPUT B$
  80 LET I=B$(1)="Y"
  90 CLS 
 100 PRINT AT 4,0;"  HOW MANY HOUNDS WOULD YOU LIKETO USE?   (FROM THREE TO EIGHT)   "
 110 INPUT H$
 120 IF H$>"8" OR H$<"3" THEN GOTO 110
 130 LET H=CODE H$-28
 140 FAST 
 160 DIM A$(8,8)
 170 LET B$="A>8 OR A<1 OR B>8 OR B<1"
 180 CLS 
 200 POKE 16418,0
 220 FOR A=0 TO 7
 230 FOR B=0 TO 2
 240 LET D=3*(A-2*INT (A/2))
 250 FOR C=0 TO 3
 260 PRINT TAB (D+C*6);"@@@@@@";
 270 NEXT C
 280 NEXT B
 290 NEXT A
 300 PRINT AT 2,25;"FOX AT";TAB 25;"''''''''''''";TAB 26;"DUSK";TAB 26;"''''''''"
 320 FOR A=1 TO 8
 330 FOR B=1 TO 8
 340 IF (A+B)/2<>INT ((A+B)/2) THEN LET A$(A,B)="B"
 350 NEXT B
 360 NEXT A
 380 FOR A=1 TO 2
 390 FOR B=1 TO 8
 400 IF NOT H THEN GOTO 490
 410 IF A$(B,A)="B" THEN GOTO 470
 420 LET A$(B,A)="H"
 430 LET H=H-1
 440 LET X=B
 450 LET Y=A
 460 GOSUB 1250
 470 NEXT B
 480 NEXT A
 490 SLOW 
 510 LET F=8
 520 LET E=2*INT (1+RND*4)
 530 LET A$(E,F)="F"
 540 GOSUB 1500
 560 PRINT AT 7,26;"%M%O%V%E";TAB 26;"%F%R%O%M";AT 10,27;
 570 GOSUB 1170
 580 LET A=Z
 590 GOSUB 1170
 600 LET B=Z
 610 PRINT AT 12,27;"%T%O";AT 14,27;
 620 GOSUB 1170
 630 LET C=Z
 640 GOSUB 1170
 650 LET D=Z
 670 IF A$(C,D)="F" THEN GOSUB 1500
 690 PRINT AT 7,26;"    ";TAB 26;"    ";AT 10,27;"  ";AT 12,27;"  ";AT 14,27;"  "
 710 IF ABS (A-C)>1 OR ABS (B-D)>1 OR A$(A,B)<>"H" OR A$(C,D)<>" " THEN GOTO 550
 730 LET X=A
 740 LET Y=B
 750 GOSUB 1330
 760 LET A$(A,B)=" "
 770 LET X=C
 780 LET Y=D
 790 GOSUB 1250
 800 LET A$(C,D)="H"
 820 LET M=0
 830 FOR W=F-1 TO F+1 STEP 2
 840 FOR V=E-1 TO E+1 STEP 2
 850 LET A=V
 860 LET B=W
 880 IF VAL B$ THEN GOTO 1000
 890 LET T=0
 910 IF A$(A,B)="H" THEN GOTO 1370
 930 IF A$(A,B)<>" " THEN GOTO 1000
 950 LET T=T+3*RND+(B<F)+(B=1)
 960 IF T<M THEN GOTO 1000
 970 LET Y=B
 980 LET X=A
 990 LET M=T
 1000 NEXT V
 1010 NEXT W
 1030 IF NOT M THEN GOTO 1430
 1050 LET A$(E,F)=" "
 1060 LET A$(X,Y)="F"
 1080 LET G=ABS (E-X)>1
 1090 IF G THEN GOSUB 1500
 1100 LET E=X
 1110 LET F=Y
 1130 IF Y=1 THEN GOTO 1470
 1150 IF G OR I THEN GOSUB 1500
 1160 GOTO 550
 1180 IF INKEY$<>"" THEN GOTO 1180
 1190 LET C$=INKEY$
 1200 IF C$="" THEN GOTO 1190
 1210 IF C$>"8" OR C$<"1" THEN GOTO 1180
 1220 PRINT C$;
 1230 LET Z=CODE C$-28
 1240 RETURN 
 1260 LET Z=3*(X-1)
 1270 PRINT AT 3*(8-Y),Z;"/ :.";TAB Z;"% % : ";TAB Z;":  :"
 1280 RETURN 
 1300 LET Z=3*(E-1)
 1310 PRINT AT 3*(8-F),Z;":. .:";TAB Z;":'% ':";TAB Z;"':% :'"
 1320 RETURN 
 1340 LET Z=3*(X-1)
 1350 PRINT AT 3*(8-Y),Z;"   ";TAB Z;"   ";TAB Z;"   "
 1360 RETURN 
 1380 LET A=V+(V-E)
 1390 LET B=W+(W-F)
 1400 IF VAL B$ THEN GOTO 1000
 1410 LET T=RND
 1420 GOTO 920
 1430 GOSUB 1290
 1440 PRINT AT 8,25;"%Y%O%U %W%O%N"
 1450 PAUSE 40000
 1460 GOTO 20
 1470 GOSUB 1290
 1480 PRINT AT 8,25;"%I %W%I%N"
 1490 GOTO 1450
 1510 FOR A=1 TO 4
 1520 GOSUB 1290
 1530 FOR B=1 TO 4
 1540 NEXT B
 1550 PRINT AT 3*(8-F),Z;"   ";TAB Z;"   ";TAB Z;"   "
 1560 NEXT A
 1570 RETURN 
 1580 CLEAR 
 1590 SAVE "1025%9"
 1600 RUN 

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

People

No people associated with this content.

Scroll to Top