Checkers

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

Checkers implements a two-player checkers (draughts) game where one side is controlled by the computer, using a 45-element array to represent the 8×8 board with sentinel values. The board uses alphabetic column labels (A–H) combined with numeric row labels, encoded in a 32-entry lookup table loaded from DATA statements that maps position strings like “B1” to array indices. Computer AI searches for capture moves first, then falls back to randomized piece selection with a loop counter to avoid infinite searching. A custom UDG character is defined via POKE USR for the player’s pieces, while the computer’s pieces use the letter “O” and inverse video characters for kings.


Program Structure

The program is organized into several logical phases:

  1. Lines 10–70: Title screen, initialization calls, and jump to setup
  2. Lines 80–430: Main game loop — board display, player input, move validation, and turn switching
  3. Lines 440–560: Board display subroutine, iterating array indices 40 down to 6
  4. Lines 570–630: Piece rendering subroutine
  5. Lines 640–1090: Computer AI — capture detection, double-jump attempts, random fallback
  6. Lines 1100–1250: Forward-capture (king) logic for the computer
  7. Lines 1300–1450: Board initialization and first-move prompt
  8. Lines 1460–1510: Move-string decoder (converts e.g. “A3” to an array index)
  9. Lines 1520–1580: Load coordinate lookup table from DATA
  10. Lines 1590–1640: UDG definition for player piece graphic

Board Representation

The board is stored in a 45-element array a(). Indices 1–5 and 41–45 are sentinel cells set to 9. Indices 14, 23, and 32 are also set to 9, representing the unused square in each row of the staggered checkers grid. Valid playable squares use indices 6–40 (excluding the sentinels), and piece values are:

ValueMeaning
NOT PI (0)Empty square
1Player’s man
2Player’s king
-1Computer’s man
-2Computer’s king
9Sentinel / off-board

Adjacent squares differ by 4 or 5 in index, and captures span 8 or 10. The staggered grid layout means rows alternate between 4- and 5-step offsets.

Coordinate Lookup Table

Lines 1520–1580 define a parallel pair of arrays: m$(32,2) holds 2-character position strings like "A2", and m(32) holds the corresponding array index. The data is stored in a compact form in the DATA statements at lines 1530–1540, where each entry is a 5-character string such as "B140" — the first two characters are the label and the remaining characters are the index. Line 1570 uses VAL c$(PI TO ) (i.e., VAL c$(4 TO ), since PI truncates to 3, so the slice starts at character 4) to extract the numeric index. The decoder subroutine at lines 1460–1510 performs a linear search through m$() to convert user input into an array index.

Key BASIC Idioms

  • NOT PI evaluates to 0 (since NOT of any nonzero value is 0), used pervasively as a zero literal and to initialize variables like p, q, si, sm.
  • VAL "number" in GO SUB and slice operations is used as a memory-efficient literal.
  • LET i= NOT PI: RETURN at line 1500 signals a failed lookup to the caller, which checks IF i= NOT PI at lines 260 and 300 to re-prompt input.
  • The display subroutine iterates FOR i=40 TO 6 STEP -1 so the board prints with the player’s side at the bottom.

Computer AI

The AI first scans all positions for backward captures (lines 660–690) and forward captures for kings (lines 700–720), jumping directly to specific move-execution blocks if found. If no capture is available, it falls back to a randomized loop (lines 750–880): a random starting index z is picked, legal moves are identified by setting k to 1, 2, or −7, and the loop retries up to 200 or 400 times before conceding. If the AI genuinely cannot move, it sets sm=12 to signal a player win.

Double-jump logic appears at lines 940–980 and 1040–1090, where after a capture the code checks if the landed piece can immediately capture again, executing a second jump in the same turn. However, this logic is partially inconsistent — variable p is used across multiple separate capture blocks without always being reset to 0, which can cause carry-over between turns.

UDG and Graphics

Lines 1590–1640 define a single UDG (character \\a) via POKE USR "\\a" with 8 bytes of circle/disc shape data from a DATA statement at line 1630. This UDG is used to render the player’s pieces. The computer’s men are displayed as "O", kings use escape sequences with character codes 20 and 1/0 to achieve inverse video highlighting (lines 610–620). The board squares themselves are rendered using the block graphic \\:: (a solid block █) in INK 2 (red).

Notable Bugs and Anomalies

  • Line 1140 contains a double increment z++3 (which BASIC parses as z + +3, equivalent to z+3), likely a typo for z+13 or similar; this may cause incorrect double-jump detection.
  • Line 350 handles the case c-b=8 (diagonal capture), clearing a(c-5), but the symmetric case c-b=10 clearing a(c-4) is absent — only the b-c directions are fully handled for the player’s captures.
  • Variable p (used for double-jump state) is initialized once at line 1410 but never reset between computer turns, meaning a double-jump flag from a previous turn could erroneously fire.
  • Line 730 contains IF z <=40 THEN GO TO 730 as an increment-free loop, but the preceding LET z=z+1 is a separate statement — this is an unusual but functional busy-wait scan pattern.
  • The move input at line 210 prompts for two values but uses a single INPUT with two string variables separated by a literal prompt string, which is valid BASIC syntax.

Image Gallery

Source Code

   10 PAPER 6:CLS 
   20 PRINT AT 6,13;"THIS "'' TAB 14;"IS"'' TAB 11;"CHECKERS"
   30 BEEP .5,8:PAUSE 90:BEEP .5,12:CLS 
   40 REM CHECKERS
   50 GO SUB 1590
   60 GO SUB 1520
   70 GO TO 1300
   80 CLS 
   90 PRINT TAB 12; PAPER 1;"CHECKERS"
  100 PRINT ,,
  110 PRINT "  "; PAPER 6;"ABCDEFGH"
  120 GO SUB 440
  130 PRINT "Your score ";sm,"Computers score ";si;" "
  140 PRINT 
  150 IF u$="N" THEN GO TO 640
  160 IF si=12 THEN PRINT "I Win ":STOP 
  170 IF sm=12 THEN PRINT "You win ":STOP  
  180 REM 
  190 IF q=2 THEN GO TO 400
  200 PRINT "Last to ";f$;
  210 INPUT "From (left,No. eg A3) ";c$;" to ";b$
  220 LET f$=b$
  230 LET d$=c$
  240 GO SUB 1460
  250 LET c=m(i)
  260 IF i= NOT PI THEN GO TO 210
  270 LET d$=b$
  280 GO SUB 1460
  290 LET b=m(i)
  300 IF i= NOT PI THEN GO TO 210
  310 IF ABS (c-b)=10 OR ABS (c-b)=8 THEN LET sm=sm+1
  320 LET u$=" "
  330 IF b-c=10 THEN LET a(b-5)= NOT PI
  340 IF b-c=8 THEN LET a(b-4)= NOT PI
  350 IF c-b=8 THEN LET a(c-5)= NOT PI
  360 LET a(b)=a(c)
  370 LET a(c)= NOT PI
  380 LET q=2
  390 GO TO 80
  400 LET u$="":LET q= NOT PI
  410 IF ABS (c-b)=10 OR ABS (c-b)=8 THEN PRINT ''':INPUT u$
  420 IF u$ <>"Y" THEN GO TO 640
  430 GO TO 80
  440 REM 
  450 LET m1= NOT PI:LET k=1
  460 LET j=-1
  470 FOR i=40 TO 6 STEP -1
  480 IF a(i)=1 AND i>37 THEN LET a(i)=2
  490 IF a(i)=-1 AND i<10 THEN LET a(i)=-2
  500 IF i=14 OR i=32 OR i=23 THEN GO TO 560
  510 IF m1= NOT PI THEN PRINT k;" ";:LET m1= NOT PI:LET k=k+1:LET j=-1*j:IF j=1 THEN PRINT INK 2;"\::";
  520 LET a=a(i)
  530 GO SUB 570
  540 IF m1 <>3 OR j=-1 THEN PRINT INK 2;"\::";
  550 LET m1=m1+1:IF m1>3 THEN LET m1= NOT PI:PRINT 
  560 NEXT i:PRINT :RETURN 
  570 REM print pieces
  580 IF a= NOT PI THEN PRINT " ";
  590 IF a=1 THEN PRINT "\a";
  600 IF a=-1 THEN PRINT "O";
  610 IF a=-2 THEN PRINT "\{20}\{1}O\{20}\{0}";
  620 IF a=2 THEN PRINT "\{20}\{1}\a\{20}\{0}";
  630 RETURN 
  640 LET u$="  ":LET q= NOT PI
  650 LET z=6
  660 IF z<9 THEN GO TO 700
  670 IF a(z)<0 AND (a(z-4)=1 OR a(z-4)=2) AND a(z-8)= NOT PI THEN GO TO 890
  680 IF z<11 THEN GO TO 700
  690 IF a(z)<0 AND (a(z-5)=1 OR a(z-5)=2) AND a(z-10)= NOT PI THEN GO TO 990
  700 IF z>25 THEN GO TO 730
  710 IF a(z)=-2 AND (a(z+4)=1 OR a(z+4)=2) AND a(z+8)= NOT PI THEN GO TO 1100
  720 IF a(z)=-2 AND (a(z+5)=1 OR a(z+5)=2) AND a(z+10)= NOT PI THEN GO TO 1210
  730 LET z=z+1:IF z <=40 THEN GO TO 730
  740 REM RANDOMIZE 
  750 LET u= NOT PI
  760 LET z=6+ INT (RND*34)+1
  770 LET k= NOT PI
  780 LET u=u+1
  790 IF a(z)<0 AND a(z-4)= NOT PI THEN LET k=1
  800 IF a(z)<0 AND a(z-5)= NOT PI AND k= NOT PI THEN LET k=2
  810 IF k= NOT PI AND z<26 AND a(z)=-2 AND a(z+4)= NOT PI THEN LET k=-7
  820 IF z<10 THEN GO TO 840
  830 IF (k=1 OR k=2) AND u<200 AND (a(z-(10 AND z>10))=1 OR a(z-8)=1) THEN GO TO 760
  840 IF k= NOT PI AND u<400 THEN GO TO 760
  850 IF k= NOT PI THEN LET sm=12:GO TO 80
  860 LET a(z-(3+k))=a(z)
  870 LET a(z)= NOT PI
  880 GO TO 80
  890 LET a(z-8)=a(z)
  900 LET a(z)= NOT PI
  910 LET a(z-4)= NOT PI
  920 LET si=si+1
  930 IF z<24 THEN GO TO 80
  940 IF (a(z-13)=1 OR a(z-13)=2) AND a(z-18)= NOT PI THEN LET p=2
  950 IF p=1 THEN LET a(z-18)=a(z-8):LET a(z-13)= NOT PI
  960 IF p=2 THEN LET a(z-8)= NOT PI
  970 IF p>0 THEN LET a(z-8)= NOT PI
  980 GO TO 80
  990 LET a(z-10)=a(z)
 1000 LET a(z)= NOT PI
 1010 LET a(z-5)= NOT PI
 1020 LET si=si+1
 1030 IF z<25 THEN GO TO 80
 1040 IF (a(z-15)=1 OR a(z-15)=2) AND a(z-20)= NOT PI THEN LET p=1
 1050 IF (a(z-14)=1 OR a(z-14)=2) AND a(z-18) THEN LET p=2
 1060 IF p=1 THEN LET a(z-15)= NOT PI:LET a(z-20)=a(z-10)
 1070 IF p=2 THEN LET a(z-14)= NOT PI:LET a(z-18)=a(z-10)
 1080 IF p>0 THEN LET a(z-10)= NOT PI
 1090 GO TO 80
 1100 LET a(z+8)=-2
 1110 LET a(z+4)= NOT PI
 1120 LET a(z)= NOT PI
 1130 LET si=si+1
 1140 IF z<32 AND (a(z++3)=1 OR a(z+3)=2) AND a(z-2)= NOT PI THEN LET p=1
 1150 IF z<23 AND (a(z+14)=1 OR a(z+14)=2) AND a(z+16)=2 THEN LET p=2
 1160 IF z<23 AND (a(z+13)=1 OR a(z+13)=2) AND a(z+18)= NOT PI THEN LET p=3
 1170 IF p=1 THEN LET a(z+3)= NOT PI:LET a(z-2)=-2
 1180 IF p=2 THEN LET a(z+14)= NOT PI:LET a(z+16)= NOT PI
 1190 IF p=3 THEN LET a(z+13)= NOT PI:LET a(z+18)=-2
 1200 IF p>0 THEN LET a(z+8)= NOT PI
 1210 LET a(z+10)=-2
 1220 LET a(z+5)= NOT PI
 1230 LET a(z)= NOT PI
 1240 LET si=si+1
 1250 GO TO 80
 1260 PRINT :PRINT 
 1270 PRINT :PRINT 
 1280 RETURN 
 1290 REM * initialize *
 1300 DIM a(45)
 1310 PRINT 
 1320 FOR z=1 TO 45
 1330 IF z<6 THEN LET a(z)=9
 1340 IF z>5 AND z<19 THEN LET a(z)=1
 1350 IF z>18 AND z<28 THEN LET a(z)= NOT PI
 1360 IF z>27 AND z<41 THEN LET a(z)=-1
 1370 IF z>40 THEN LET a(z)=9
 1380 NEXT z
 1390 LET a(14)=9:LET a(23)=9:LET a(32)=9
 1400 LET f$="--":LET u$=""
 1410 LET p= NOT PI:LET q=p:LET si=p:LET sm=p
 1420 INPUT "Do You Want The First Move Y/N"; LINE q$ 
 1430 PRINT 
 1440 IF q$ <>"Y" THEN GO TO 640
 1450 GO TO 80
 1460 REM decodeMOVE 
 1470 LET i=1
 1480 IF m$(i)=d$ THEN RETURN 
 1490 LET i=i+1
 1500 IF i=33 THEN LET i= NOT PI:RETURN 
 1510 GO TO 1480
 1520 DIM m$(32,2):DIM m(32)
 1530 DATA "B140","D139","F138","H137","A236","C235","E234","G233","B331","D330","F329","H328","A427","C426","E425","G424","B522","D521","F520","H519","A618","C617","E616"
 1540 DATA "G615","B713","D712","F711","H710","A809","C808","E807","G806"
 1550 RESTORE 1530
 1560 FOR i=1 TO 32
 1570 READ c$:LET m$(i)=c$:LET m(i)= VAL c$(PI TO )
 1580 NEXT i:RETURN 
 1590 BORDER NOT PI:PAPER NOT PI:INK 9:CLS 
 1600 RESTORE 1630:FOR a= NOT PI TO 7
 1610 READ u:POKE USR "\a"+a,u
 1620 NEXT a:RETURN 
 1630 DATA 0,60,126,u,u,u,60,0
 1640 REM a=\a

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