--- title: "Fox at Dusk" id: 57504 type: "computer_media" slug: "fox-at-dusk" url: "http://localhost/computer_media/fox-at-dusk/" markdown_url: "http://localhost/computer_media/fox-at-dusk.md" published_at: "2024-10-05T21:11:13+00:00" modified_at: "2026-04-03T07:58:26+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/259_Fox.png" excerpt: "A hidden-fox strategy game where hounds must trap an elusive computer-controlled fox that can leap over pieces and disappear into the dusk." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" genre: - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_contents: - id: 56737 title: "Timex Sinclair Public Domain Library Tape 1006" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-1006/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/10/259_Fox.png" media_type_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"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+(B1 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 ```