--- title: "BBS Chess" id: 51116 type: "computer_media" slug: "bbs-chess" url: "http://localhost/computer_media/bbs-chess/" markdown_url: "http://localhost/computer_media/bbs-chess.md" published_at: "2023-07-12T22:35:12+00:00" modified_at: "2026-03-30T21:41:05+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2023/07/BBS-Chess-1.png" excerpt: "A correspondence chess program that renders a full board with custom piece graphics, captures the screen to a memory buffer, and saves it ready for BBS upload." 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 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" indiv: - name: "Charles Stelding" slug: "charles-stelding" taxonomy: "indiv" url: "http://localhost/indiv/charles-stelding/" genre: - name: "BBS" slug: "bbs" taxonomy: "genre" url: "http://localhost/type/bbs/" - name: "Game" slug: "game" taxonomy: "genre" url: "http://localhost/type/game/" media_type: "Program" programmers: - name: "Charles Stelding" slug: "charles-stelding" taxonomy: "indiv" url: "http://localhost/indiv/charles-stelding/" download_url: "https://archive.org/download/timex-sinclair-software-archive/BBS%20Chess%20%28198x%29%28Stelding%2C%20Charles%29%28US%29%28TS2068%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2023/07/BBS-Chess-1.png" - url: "http://localhost/wp-content/uploads/2023/07/BBS-Chess-2.png" - url: "http://localhost/wp-content/uploads/2023/07/BBS-Chess-3.png" media_type_tags: "BBS, Game" --- 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: 1. **Lines 10–40:** Title screen flash and UDG/sprite data loading via POKE. 2. **Lines 50–70:** Main menu and introductory text display; branch to continue or start new game. 3. **Lines 100–133:** Board variable initialization — column pattern string, move record, separator string, and the 8×8 piece array `f$` seeded with starting positions. 4. **Line 200–201:** Player color selection (black = uppercase letters, white = lowercase). 5. **Lines 1000–1140:** Board redraw routine: prints the text grid, overlays the checkerboard pattern using `OVER 1`, then prints piece legend and move history. 6. **Lines 3000–3030:** Piece rendering dispatch and move input loop. 7. **Line 4000–4030:** Screen capture to buffer at 50000, save routines, and terminal handoff instructions. 8. **Lines 8000–8010:** Subroutine to print one row of pieces onto the board. 9. **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: RETURN` construct that only advances `vert` and loops when the condition is true. Line 8005 handles the false branch (piece present but not lowercase), and line 8010 provides the shared `NEXT l: RETURN`. However, when the condition at 8000 is false, execution falls through to 8005 without branching to 8010’s `NEXT` first — the `NEXT l` at 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 1000` only if the player enters “u” (intending white/lower case), but sets `d$="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 `graph` on continue:** When loading a saved game (`GO TO 1000` from line 70), `graph` is 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. ## 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;"tart a new game"''TAB 7;"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 ```