This program implements a chess board manager designed for use with bulletin board systems (BBS), allowing two players to conduct a correspondence chess game by saving board states to memory and uploading screen content to a message buffer. The board is rendered using a combination of text characters and user-defined graphics (UDGs) stored via POKE statements into memory starting at addresses such as 64272 and 64344, covering six piece types (bishop, king, knight, pawn, queen, rook) in two sets for black and white. Piece positions are tracked in an 8×8 string array `f$`, with column coordinates translated from algebraic notation (a–h) via a linear search through the string “abcdefgh” in the subroutine at line 8500. The screen capture routine at line 4000 copies the display using `SCREEN$` into a 533-byte buffer at address 50000, ready for upload through terminal software (Mterm II), with specific POKEs (23627, 107 and 23628, 106) and a `RANDOMIZE USR 54016` call to interface with external code loaded at address 26710. The `OVER 1` mode is used at lines 1036–1111 to overlay the dark-square checkerboard pattern onto the board display without erasing the existing text.
Program Analysis
Program Structure
The program is divided into several functional blocks:
- Lines 10–40: Title screen flash and UDG/sprite data loading via POKE.
- Lines 50–70: Main menu and introductory text display; branch to continue or start new game.
- Lines 100–133: Board variable initialization — column pattern string, move record, separator string, and the 8×8 piece array
f$seeded with starting positions. - Line 200–201: Player color selection (black = uppercase letters, white = lowercase).
- Lines 1000–1140: Board redraw routine: prints the text grid, overlays the checkerboard pattern using
OVER 1, then prints piece legend and move history. - Lines 3000–3030: Piece rendering dispatch and move input loop.
- Line 4000–4030: Screen capture to buffer at 50000, save routines, and terminal handoff instructions.
- Lines 8000–8010: Subroutine to print one row of pieces onto the board.
- Lines 8500–8580: Algebraic notation parser — converts move string (e.g., “a2 to a4”) into array indices.
UDG / Sprite Loading
Lines 20–32 define DATA blocks for six chess piece sprites in two sets (one per player), plus a board square pattern. Each DATA line begins with a destination address followed by 8 bytes of bitmap data. Line 40 loops over DATA lines 20–32, RESTOREing each line in turn, reading the target address into loc, then POKEing 8 bytes sequentially. This technique avoids needing a separate machine code loader — pure BASIC handles the transfer.
| Line | Address | Piece | Set |
|---|---|---|---|
| 20 | 64272 | Bishop | 1 |
| 21 | 64344 | King | 1 |
| 22 | 64368 | Knight | 1 |
| 23 | 64384 | Pawn | 1 |
| 24 | 64392 | Queen | 1 |
| 25 | 64400 | Rook | 1 |
| 26–31 | 64528–64656 | All six | 2 |
| 32 | 64024 | Square pattern | — |
Board Representation
The board state is held in f$(8,8), an 8×8 string array where each cell contains a single character: uppercase letters for black pieces (R, N, B, Q, K, P) and lowercase for white (r, n, b, q, k, p), with a space representing an empty square. Initial positions are set directly by assigning string slices at lines 130–133. Only the back ranks and pawn ranks are populated; the middle four rows default to spaces from DIM.
Checkerboard Overlay with OVER 1
Lines 1036–1111 use OVER 1 (XOR plotting mode) to print the dark-square pattern string c$ (” # # # #”) at alternating rows and column offsets across the board area. Because OVER 1 XORs characters onto whatever is already on screen, the piece letters printed later in the rendering pass coexist with the pattern without being erased. OVER 0 is restored at line 1111.
UDG Font Switching via POKE 23607
The system variable at address 23607 (UDG pointer high byte) is manipulated at lines 1035, 1115, 3000, and 3005. POKEing 249 shifts the UDG table to point to the loaded sprite data (in the 64000s range), causing the piece characters to render as graphical sprites. POKEing 60 restores the default UDG base, switching back to normal characters for text output. This allows the same character codes to display either as letters or as chess piece bitmaps depending on context.
Algebraic Notation Parser (Lines 8500–8580)
The subroutine at line 8500 parses a move string of the form “a2 to a4” stored in i$. It performs four sequential linear searches through strings “abcdefgh” and “12345678” to convert characters at positions 1, 2, 7, and 8 of i$ into integer indices a, b, c, d. Each search uses a FOR/IF/GO TO pattern with a fall-through NEXT on a separate line — a common BASIC idiom for early-exit loops. The resulting indices directly address f$() to move a piece.
Screen Capture and BBS Buffer
Line 4000 iterates over rows 1–17 and columns 0–30 of the display using SCREEN$, POKEing each character’s CODE into a buffer starting at address 50000, with CHR$ 13 (carriage return) appended after each row. This produces a 533-byte plain-text representation of the board suitable for uploading to a BBS message. The program then saves this buffer as "chess"CODE 50000,533 and saves itself as "chessgame" LINE 1. Instructions in lines 4012–4020 describe loading the code at address 26710 in Mterm II, followed by specific POKEs to 23627/23628 and a RANDOMIZE USR 54016 call to trigger a terminal upload routine.
Bugs and Anomalies
- Lines 8000–8010 control flow: The subroutine at line 8000 contains an
IF ... THEN ... NEXT l: RETURNconstruct that only advancesvertand loops when the condition is true. Line 8005 handles the false branch (piece present but not lowercase), and line 8010 provides the sharedNEXT l: RETURN. However, when the condition at 8000 is false, execution falls through to 8005 without branching to 8010’sNEXTfirst — theNEXT lat 8010 would need to be reached for the loop to continue. This is a structural anomaly that may cause incorrect rendering for uppercase (black) pieces in graphical mode. - Color selection branch: Line 200 branches to
GO TO 1000only if the player enters “u” (intending white/lower case), but setsd$="white (lower case)". The logic seems inverted — the white player would normally play lowercase pieces, yet the branch skips board initialization at lines 130–133 which is already done. The color labeling may confuse players. - Move input prompt: Line 3010 expects the STOP sentinel as the string
" STOP "(with spaces), which requires the player to type exactly that string including surrounding spaces, making it easy to miss. - Uninitialized
graphon continue: When loading a saved game (GO TO 1000from line 70),graphis never set, so it retains whatever value it had — or may be uninitialized on a fresh load, potentially causing issues at line 1035’s conditional POKE.
Content
Source Code
10 PRINT FLASH 1;"Loading DATA"
20 DATA 64272,24,56,118,60,24,24,60,126: REM BISHOP
21 DATA 64344,24,60,24,126,60,60,126,255: REM KING
22 DATA 64368,18,62,111,255,207,31,60,126: REM KNIGHT
23 DATA 64384,0,0,24,60,24,24,60,126: REM PAWN
24 DATA 64392,90,60,60,60,60,60,126,255: REM QUEEN
25 DATA 64400,0,0,219,126,60,60,126,255: REM ROOK
26 DATA 64528,24,56,118,60,24,24,60,126: REM BISHOP
27 DATA 64600,24,60,24,126,60,60,126,255: REM KING
28 DATA 64624,18,62,111,255,207,31,60,126: REM KNIGHT
29 DATA 64640,0,0,24,60,24,24,60,126: REM PAWN
30 DATA 64648,90,60,60,60,60,60,126,255: REM QUEEN
31 DATA 64656,0,0,219,126,60,60,126,255: REM ROOK
32 DATA 64024,165,0,165,0,0,165,0,165: REM square
40 FOR j=20 TO 32: RESTORE j: READ loc: FOR k=1 TO 8: READ num: POKE loc,num: LET loc=loc+1: NEXT k: NEXT j
50 LET graph=1: PAPER 7: INK 0: BORDER 7: CLS : PRINT AT 2,11;"BBS Chess"''TAB 6;"by Charles Stelding"''TAB 7;"<S>tart a new game"''TAB 7;"<C>ontinue a game"
60 PRINT AT 10,0;" This utility allows you to play a game of chess on any BBS by enabling you to create a game, move the chessmen and saveit to a buffer ready to upload to a message board. The opponentplays the game by replying on the message board. You update the board with this program and upload the revised chess board to your opponent."
70 INPUT i$: IF i$="c" OR i$="C" THEN GO TO 1000
100 LET c$=" # # # #"
105 DIM m$(8): LET m$="?? to ??"
110 LET x$=" !-!-!-!-!-!-!-!-!"
120 DIM f$(8,8)
130 LET f$(8)="RNBQKBNR"
131 LET f$(7)="PPPPPPPP"
132 LET f$(2)="pppppppp"
133 LET f$(1)="rnbqkbnr"
200 INPUT "Are you (black) upper case or (white) lower case? ";i$: IF i$="u" THEN LET d$="white (lower case)": GO TO 1000
201 LET d$="black (upper case)"
1000 CLS : PRINT '" =a=b=c=d=e=f=g=h="
1030 FOR j=8 TO 1 STEP -1: PRINT j;" ! ! ! ! ! ! ! ! !"'x$: NEXT j: PRINT AT 17,0;" =a=b=c=d=e=f=g=h="
1035 IF graph THEN POKE 23607,249
1036 OVER 1
1040 PRINT AT 2,4;c$
1050 PRINT AT 4,2;c$
1060 PRINT AT 6,4;c$
1070 PRINT AT 8,2;c$
1080 PRINT AT 10,4;c$
1090 PRINT AT 12,2;c$
1100 PRINT AT 14,4;c$
1110 PRINT AT 16,2;c$
1111 OVER 0
1115 POKE 23607,60
1120 PRINT AT 1,20;"Leave me a";AT 2,20;"message as";AT 3,20;"""a2 to a4.""";AT 4,21;"You are";AT 5,22;d$( TO 5);AT 6,19;d$(7 TO )
1130 PRINT AT 8,22;"K=king";AT 9,22;"Q=queen";AT 10,22;"B=bishop";AT 11,22;"N=knight";AT 12,22;"R=rook";AT 13,22;"P=pawn"
1140 PRINT AT 15,19;"My move was:";AT 16,21;m$
2999 REM print pieces to board
3000 IF graph THEN POKE 23607,249
3005 LET horiz=2: LET row=8: FOR j=1 TO 8: LET vert=3: GO SUB 8000: LET row=row-1: LET horiz=horiz+2: NEXT j: POKE 23607,60: IF NOT graph THEN GO TO 4000
3010 INPUT ("Your opponent is ";d$( TO 5)'"STOP to put in buffer or enter a move>");i$: PRINT AT 20,0;i$: INPUT "Correct? y/n ";z$: IF z$="n" THEN GO TO 1000
3014 IF i$<>" STOP " THEN LET m$=i$
3015 IF i$=" STOP " THEN LET graph=0: GO TO 1000
3020 GO SUB 8500: LET f$(d,c)=f$(b,a): LET f$(b,a)=" "
3030 GO TO 1000
4000 PRINT #1; FLASH 1;"Screen now going to 50000": LET buf=50000: POKE buf,32: LET buf=buf+1: POKE buf,13: LET buf=buf+1: FOR j=1 TO 17: FOR k=0 TO 30: POKE buf,CODE SCREEN$ (j,k): LET buf=buf+1: NEXT k: POKE buf,13: LET buf=buf+1: NEXT j
4010 CLS : PRINT "Game is now loaded at 50000,533."
4012 PRINT '"You will now save the code as ""chess""CODE 50000,533 and the game as ""chessgame"" LINE 1. After the save, load Mterm II. Get to BASIC and load the code as LOAD""chess""CODE 26710."
4020 PRINT '"Then POKE 23627,107: POKE 23628,106: RANDOMIZE USR 54016."
4030 PRINT ''''"(Press any key to save game)": PAUSE 0: SAVE "chess"CODE 50000,533: SAVE "chessgame" LINE 1: STOP
8000 FOR l=1 TO 8: IF f$(row,l)<>" " AND f$(row,l)>"a" THEN INK 4: PRINT AT horiz,vert;f$(row,l): INK 0: LET vert=vert+2: NEXT l: RETURN
8005 IF f$(row,l)<>" " THEN PRINT AT horiz,vert;f$(row,l)
8010 LET vert=vert+2: NEXT l: RETURN
8500 LET h$="abcdefgh": FOR j=1 TO 8: IF i$(1)=h$(j) THEN GO TO 8510
8505 NEXT j
8510 LET a=j
8520 LET h$="12345678": FOR j=1 TO 8: IF i$(2)=h$(j) THEN GO TO 8530
8525 NEXT j
8530 LET b=j
8540 LET h$="abcdefgh": FOR j=1 TO 8: IF i$(7)=h$(j) THEN GO TO 8550
8545 NEXT j
8550 LET c=j
8560 LET h$="12345678": FOR j=1 TO 8: IF i$(8)=h$(j) THEN GO TO 8570
8565 NEXT j
8570 LET d=j
8580 RETURN
9999 SAVE "Chess BBS" LINE 1
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.


