Reverse-engineering notes on Sargon V: World Class Chess (Mediagenic, 1991) — the last of the line Dan and Kathe Spracklen started in 1978 with a Z80 program written for a computer chess tournament, and the only one whose PC front end this repository is about.
The About box splits the credit itself:
Chess Engine: Dan & Kathe Spracklen
P.C. Engine: Kevin E. Leavelle
Everything here is the second half — the container, the codec, the display layer, the position records, the tutorial system. The search itself is a black box this project has not opened.
Documentation only. No game assets, no extracted art, no audio, no
executable code is committed here. The tools in tools/ reproduce
every figure, table and image from your own legally obtained copy.
| Doc | Contents |
|---|---|
| 00-overview.md | The release, the two disagreeing copyright lines, the eight shipped files |
| 01-executable.md | SARGON5.EXE: the LZEXE wrapper, the 32-copy copyright fence, the data segment, the command line, EMS, the build |
| 02-container-and-codec.md | The 16-byte directory and the LSB-first LZW that five of the eight files share |
| 03-graphics.md | SCREENE.HUH: eight frames, 182 sprites, the bottom-centre anchor, the piece-set loader |
| 04-palettes-and-16-colour.md | The VGA palette and the 768-byte table that lets one asset set serve four displays |
| 05-fonts.md | FONTS.FNT: six proportional faces, and the tail of the character range |
| 06-display-drivers.md | WAZZOO.DRV: VGA, EGA, Tandy — and a register-level Tandy 1000 SL/TL driver |
| 07-audio.md | Six standard MIDI files, seven device records, and the card with no switch |
| 08-opening-book.md | OPENE.BOK: 338 opening names, and what can be said about the tree |
| 09-position-records.md | The 512-byte record every game, lesson and puzzle uses; the move stream |
| 10-annotated-lessons.md | .ANN coaching trees, and the .ANT sources that shipped by accident |
| 11-text-board-format.md | The plain-text board importer nothing in the release uses |
| 12-easter-eggs-and-leftovers.md | Dr. Destructo, Hamster Gone Bad Productions, and what happens to the white king |
| 13-open-questions.md | Everything unresolved, with the measurements behind it |
| notes/resource-inventory.md | All 219 blocks across the five containers, grouped and sized |
| notes/tutorial-inventory.md | 335 lessons and games, the two numbering gaps, the census |
| notes/string-inventory.md | The credits, the messages, the file names, the device names |
Five files with four different extensions are one format. SCREENE.HUH,
SMORE.HUH, FONTS.FNT, WAZZOO.DRV and OPENE.BOK share a directory of
16-byte entries with no magic number, no signature and no entry count — the
first entry's data offset is the directory length, so the count is that
offset divided by sixteen. All 219 blocks across the five files are contiguous,
and every one decodes to exactly its declared size.
The codec is LZW read backwards. Nine to twelve bits, 256 clear, 257 end —
and packed least-significant bit first, where GIF, TIFF and Unix compress
all pack MSB-first. Attacking the first block the usual way is not obviously
wrong: it runs, and produces 955 plausible bytes before the dictionary walks
off. Read the same bytes LSB-first and it lands on exactly 64,000 — one 320×200
frame. On an 8086 the LSB-first accumulator is a shift and a mask; MSB-first
needs a rotate through a width that changes under you.
One asset set serves four displays. There is no EGA art and no Tandy art in the release. Every sprite and every screen is 8-bit indexed, and each palette block carries 768 bytes of VGA DAC values plus 768 more — three bytes, six nibbles per colour — that express the same 256 colours for the 16-colour drivers. Substitute any one of those six nibble planes for the whole image and the picture stays legible. That single decision is why the sprites are chunky rather than planar and why the EGA driver is the biggest of the four.
WAZZOO.DRV is video, not audio. Four blocks, thirty entry points each — one interface, four implementations. Driver 1 is the one worth reading: it never calls the BIOS, and instead writes nineteen 6845 CRTC registers, five video-array registers through 0x3DA/0x3DE, and a page register at 0x3DF before clearing 64,000 bytes at A000. That is Tandy 1000 SL/TL 640×200 in 16 colours, programmed by hand, as a separate driver from the ordinary Tandy one. Somebody on the team had the machine.
Every game, lesson, puzzle and endgame is the same 512-byte record. Four
extensions — .SAR, .ILL, .CMB, .ENG — and one format: a 256-byte move
stream, then a 32-slot piece list of types and 0x88 squares that is never
compacted, so a captured man keeps its slot and gets square 0x80. The trailer's
one interesting byte is a cursor, not a length: class013.sar has a
63-byte stream with the cursor at 16, so 47 bytes of that game are recorded but
not yet played. The shipped saved games are recordings wound back, not
truncated.
The move stream is one byte per half-move, and the opening statistics decode it. Bit 7 is the side; the low seven bits are a 1-based index into the move list the engine generates. 113 records start from the initial position, and their first byte takes exactly four values — 12 (80 times), 14 (26), 1 (4), 16 (3). Those are 1.e4, 1.d4, 1.Nf3 and 1.c4, in the right proportions. The second byte takes nine values, which come out as e5, c5, Nf6, d5, e6, d6, c6, f5 and Nh6 — the Sicilian, the Indian defences, the Queen's Gambit, the French, the Pirc, the Caro-Kann and the Dutch, again in the right proportions. The generator emits knight moves first, king's knight before queen's, then pawns from the h-file to the a-file, one-square push before two. Where it stops is in chapter 13, stated with the number: a replay gets 2,290 of 4,631 half-moves.
A tutorial lesson is a decision tree, not a recording. sicw.ann carries
318 move entries for a twenty-turn game. Twenty are the correct moves, twenty
the machine's replies, twenty a catch-all — and the other 258 are anticipated
mistakes, each with its own sentence. Turn 1 of frenchb.ann names four rival
openings by the first move that gives them away; turn 3 enumerates twenty-six
wrong moves, including every pawn advance on the board under one message,
"A waste of a precious move".
The lessons' source code shipped, and the game cannot see it. WHITE.ANT
and BLACK.ANT are the plain-text authoring format the .ANN files were
compiled from — move lines, wildcards, XXX as a section break. The file
dialog filters on *.ANN. Two authoring files, in the retail game directory,
invisible to the program that shipped them. The typo in "a sample black
anotated game" is in the retail file.
There is a plain-text board importer nobody used. A routine at 0x16CED
accepts a file that begins with a plus sign, reads a two-character piece code
every five bytes and every 86 bytes a new rank, matching against
WPWRWBWNWKWQBPBRBBBNBKBQ plus two spaces for empty. Every constant in it
resolves to an ASCII board drawn with +----+ separators and | BR | cells,
CRLF throughout. No .TXT ships, nothing demonstrates it, and it is strict
enough that one character out of place rejects the file.
The programmer is credited as "Dr. Destructo". Four of the thirteen job titles in the About box are jokes — Interloper, Cool Boss, Grunt-work — but only one replaces a person's name, on the line directly under Dan and Kathe Spracklen.
Hold h while the About box is open. A sprite appears at (210, 163) and
two lines of text at (154, 87): Hamster Gone Bad / Productions! The routine
is the About dialog's own draw procedure, it checks the keyboard state array
for ASCII h, and each time it fires it increments a counter. Do it three
times, then hold q in two further dialogs, and a hook inside the piece-set
loader comes alive: on the fifth of the twelve sprites it loads — the
white king — it substitutes block 192 or block 193 instead. Which one is
decided by a sixteen-bit LFSR with taps 0xB400, one time in four. Block 193 is
a digitised bespectacled human face. Block 192 is a hamster holding something
that has nothing to do with chess. Either of them then plays the game as
White's king.
A card with a driver and no switch. The executable carries seven audio
device records: AdLib, IBM PS/1, Roland MT-32, Internal Speaker, Tandy 1000,
Null Device — and Game Blaster PC Music Board, Creative's 1987 CMS card,
which no command-line switch selects and the help box never lists. Conversely
there is no "Sound Blaster" string anywhere in the image: /S reaches the
AdLib record, because a Sound Blaster's music side is an OPL2.
Two numbering gaps ship in the retail data. end22.eng is missing from an
otherwise unbroken 1–58, and opngs007 through opngs010 from 1–69. The
surrounding files are present and intact.
Pure Python 3. pillow is needed for the rendering paths and capstone only
for the driver disassembler.
tools/s5lib.py the container, the LZW, sprites, palettes
tools/s5res.py list, verify and extract any container
tools/s5gfx.py screens, sprite sheets, piece sets, the 16-colour test
tools/s5font.py FONTS.FNT
tools/s5drv.py the four display drivers
tools/s5music.py the six MIDI files
tools/s5book.py OPENE.BOK and its 338 opening names
tools/s5pos.py positions from .SAR, .ILL, .CMB and .ENG, as diagrams and FEN
tools/s5ann.py .ANN lessons, as readable coaching transcripts
tools/s5unpack.py the LZEXE 0.91 wrapper
tools/s5strings.py text out of the unpacked image
tools/s5export.py one shot: all of the above into one directory
python tools/s5export.py "<install>" ./outor piecemeal:
python tools/s5res.py "<install>" verify
python tools/s5res.py "<install>" list SCREENE.HUH
python tools/s5gfx.py "<install>" screens ./screens
python tools/s5gfx.py "<install>" pieces piece-sets.png
python tools/s5gfx.py "<install>" ega 20 title-16.png
python tools/s5font.py "<install>" sheet fonts.png
python tools/s5drv.py "<install>" info
python tools/s5music.py "<install>" dump ./music
python tools/s5book.py "<install>" names
python tools/s5pos.py board "<install>/tutorial/bg01.cmb"
python tools/s5ann.py text "<install>/tutorial/frenchb.ann"
python tools/s5unpack.py "<install>" s5.bin
python tools/s5strings.py s5.bin<install> is the directory holding SARGON5.EXE, with games/ and
tutorial/ beside it.
The container and its codec are solved and verified block by block — all 219
of them, across all five files. SCREENE.HUH, FONTS.FNT, SMORE.HUH and
WAZZOO.DRV are decoded end to end. The 512-byte position record is solved
except for the move stream's generator ordering, which is decoded far enough to
read every opening move in the corpus and no further. The opening book's tree
is not decoded. Chapter 13 lists all of it, with
the numbers.