BBS Chess

Developer(s): Charles Stelding
Date: 198x
Type: Program
Platform(s): TS 2068
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.

LineAddressPieceSet
2064272Bishop1
2164344King1
2264368Knight1
2364384Pawn1
2464392Queen1
2564400Rook1
26–3164528–64656All six2
3264024Square 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.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

BBS Chess

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.

Scroll to Top