Battle

Date: 198
Type: Program
Platform(s): TS 2068
Tags: Game

This program implements a two-player diagonal-move board game played on a 9×9 grid using block graphics for the border and “X” versus “O” pieces. The board is stored in a 12×13 string array S$, with an 11-character-wide border representation built from a separate 10×11 string array B$ using Spectrum block graphic characters (▄, █, ▟, ▘). The human player inputs moves as two-digit coordinates (row×10+column), and the computer’s AI subroutine at line 1000 scans the board for an X piece that has a valid diagonal capture of an O piece, setting flag FL and direction offsets G and H. Score tracking variables HS (human score) and CS (computer score) count captured pieces, with a win condition at 6 captures.


Program Analysis

Program Structure

The program is divided into three logical sections: board initialization (lines 6–132), the main game loop (lines 135–320), the computer AI subroutine (lines 1000–1129), and the display subroutine (lines 1130–1180). A SAVE command is placed at line 2000 for archiving purposes.

  1. Lines 6–132: Build the graphical border in B$, then copy each character into the game state array S$.
  2. Lines 135–320: Main game loop — display board, accept player move, validate it, update state, invoke AI.
  3. Lines 1000–1129: Computer move subroutine — scans for an X piece with an adjacent A$ neighbor and sets direction offsets.
  4. Lines 1130–1180: Display subroutine — redraws the full board and score line.

Board Representation

The playing field is encoded using two string arrays. B$(10,11) stores the visual rows of the border/grid using Spectrum block graphic characters: \.' (▖), \:: (█), \:. (▙), \':. (▟), \'. (▚), and \.' (▖). The border rows use characters like 19 as column labels, and rows 1 and 10 serve as top and bottom decorative borders. The actual game state array S$(12,13) is slightly oversized to allow safe ±1 index arithmetic without boundary errors.

At line 125, the copy loop uses C$(B TO )(1) — a slice-then-index idiom — to extract a single character from position B of the cached row string C$, avoiding repeated indexing into the 2D array B$ inside the inner loop.

Move Input and Validation

The player encodes a board position as a two-digit number: tens digit = row, units digit = column. Lines 167–175 decode this with integer division and modulo arithmetic. The move is validated at line 180: both the row and column differences between source and destination must be exactly 1 (diagonal adjacency), enforced with ABS(A-C)<>1 OR ABS(B-D)<>1. There is no check that the source square actually contains the player’s piece (“O”), so the player could technically move from any non-border square.

Computer AI Subroutine (Lines 1000–1120)

The AI scans the board sequentially, column by column within each row, looking for an “X” piece. For each X found, it checks all four diagonal neighbors for the target piece type stored in A$. The direction variables G and H are set according to which diagonal contains the match. Flag FL=1 is raised and the routine returns as soon as a valid move is found.

The subroutine is called twice in the main loop: first with A$="O" to find a capture move (line 255), and if none is found (FL=0), again with A$=" " to find any move to an empty square (line 265). This gives the computer a simple capture-first priority heuristic.

VariableRole
E, FRow/column of the X piece found by AI
G, HRow/column direction offsets (+1 or -1) for the move
FLFlag: 1 if a valid move was found
HSHuman score (captures)
CSComputer score (captures)

Notable Techniques

  • The S$ array is dimensioned DIM S$(12,13) rather than (10,11), providing a one-cell buffer on all sides so the AI’s E±1 / F±1 accesses never go out of bounds.
  • Line 135 uses RND>0.5 to randomly decide whether to pre-place an X at position (5,5) and clear (5,7), adding slight positional variety at the start.
  • The display subroutine uses PRINT AT 0,0; to home the cursor without clearing the screen, then overwrites the previous board in place — a flicker-free redraw technique.
  • Line 125’s C$(B TO )(1) is a character extraction idiom: C$(B TO ) produces a substring from position B to the end, and (1) takes its first character — equivalent to C$(B) on some BASICs but here used as a workaround for single-character extraction from a slice.

Bugs and Anomalies

  • Line 1145 uses lowercase a and b in PRINT S$(a,b); — on the Spectrum/TS2068, variable names are case-sensitive in the token stream; these should be uppercase A and B to match the loop variables declared at lines 1132 and 1140. This is likely a transcription artifact.
  • The win condition checks at lines 157 and 245 print a win message but do not halt the game — they fall through to the next input prompt. The variable SW referenced in both win messages is never assigned, so it would print as 0.
  • Line 1085 returns from within the scan loop with E and F pointing to a found piece, but does not reset E, F, G, H on entry — lines 1000–1003 do this explicitly each call, which is correct.
  • No check is made that the destination square is empty before placing the player’s piece at line 221, allowing overwriting of border characters or the opponent’s pieces.

Content

Appears On

One of a series of library tapes compiled from multiple user groups.

Related Products

Related Articles

Related Content

Image Gallery

Battle

Source Code

    6 DIM B$(10,11)
   10 LET B$(1)="\.'123456789\'."
   20 LET B$(2)="1X\::X\::X\::X\::X1"
   30 LET B$(3)="2\::X\::X\::X\::X\::2"
   40 LET B$(4)="3X\::X\::X\::X\::X3"
   50 LET B$(5)="4\::X\::X\::X\::X\::4"
   60 LET B$(6)="5 \:: \:: \:: \:: 5"
   70 LET B$(7)="6\::O\::O\::O\::O\::6"
   80 LET B$(8)="7O\::O\::O\::O\::O7"
   90 LET B$(9)="8\::O\::O\::O\::O\::8"
  100 LET B$(10)="\'.123456789\.'"
  102 LET HS=0
  105 LET CS=0
  110 DIM S$(12,13)
  115 FOR A=1 TO 10
  117 LET C$=B$(A)
  120 FOR B=1 TO 11
  125 LET S$(A,B)=C$(B TO )(1)
  130 NEXT B
  132 NEXT A
  135 IF RND>.5 THEN GO TO 150
  140 LET S$(5,5)="X"
  141 LET S$(5,7)=" "
  150 GO SUB 1130
  155 PRINT 
  157 IF CS=6 THEN PRINT "I WIN ";SW
  160 PRINT AT 15,0;"FROM?"
  165 INPUT MOVE
  166 PRINT AT 15,4;" ";MOVE;" TO?"
  167 LET A=INT (MOVE/10)
  168 LET B=MOVE-10*A
  170 INPUT MOVE
  171 PRINT AT 15,0;"                     "
  172 LET C=INT (MOVE/10)
  175 LET D=MOVE-10*C
  180 IF ABS (A-C)<>1 OR ABS (B-D)<>1 THEN GO TO 160
  190 IF S$(C+1)(D+1)="X" THEN LET HS=HS+1
  210 LET S$(A+1)(B+1)=" "
  221 LET S$(C+1)(D+1)="O"
  240 GO SUB 1130
  245 IF HS=6 THEN PRINT "YOU WIN ";SW
  250 LET A$="O"
  255 GO SUB 1000
  257 IF FL=1 THEN GO TO 300
  260 LET A$=" "
  265 GO SUB 1000
  300 LET S$(E)(F)=" "
  305 IF S$(E+G)(F+H)="O" THEN LET CS=CS+1
  310 LET S$(E+G)(F+H)="X"
  320 GO TO 150
 1000 LET E=2
 1001 LET F=2
 1002 LET G=0
 1003 LET H=0
 1010 LET FL=0
 1020 IF S$(E)(F)<>"X" THEN GO TO 1100
 1040 IF S$(E+1)(F+1)=A$ OR S$(E+1)(F-1)=A$ THEN LET G=1
 1050 IF S$(E+1)(F+1)=A$ OR S$(E-1)(F+1)=A$ THEN LET H=1
 1060 IF S$(E-1)(F+1)=A$ OR S$(E-1)(F-1)=A$ THEN LET G=-1
 1070 IF S$(E+1)(F-1)=A$ OR S$(E-1)(F-1)=A$ THEN LET H=-1
 1080 IF G<>0 AND H<>0 THEN LET FL=1
 1085 IF FL=1 THEN RETURN 
 1100 LET E=E+1
 1101 IF E>10 THEN LET F=F+1
 1102 IF E>10 THEN LET E=2
 1110 IF F>11 THEN RETURN 
 1120 GO TO 1010
 1129 STOP 
 1130 PRINT AT 0,0;
 1132 FOR A=1 TO 10
 1135 PRINT 
 1140 FOR B=1 TO 11
 1145 PRINT S$(a,b);
 1150 NEXT B
 1155 NEXT A
 1160 PRINT 
 1165 PRINT 
 1170 PRINT "ME: ";Cs;"   YOU:  ";HS
 1180 RETURN 
 2000 SAVE "BATTLE"
 2010 STOP 

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

People

No people associated with this content.

Scroll to Top