# The SAN Kit — User Guide

The SAN Kit is a C source toolkit for chess programming, written by Steven J.
Edwards starting in 1993/1994. It is not a chess engine by itself but a
**library plus a small interactive test driver** (`san`) that exercises the
library: board representation, legal move generation, SAN/FEN/PGN/EPD
notation, a command interpreter, and a handful of pluggable "move selection
strategies" (from a trivial random mover up to simple search engines).

This guide covers the `san` test-driver program that this repository builds:
how to compile and run it, its interactive command language, and the file
formats it understands, with worked examples taken from actually running the
program.

---

## 1. Building

```sh
cd SAN_SRC
make
```

This produces an executable called `san` in the `SAN_SRC` directory (on a
modern Linux/GCC toolchain — see `PORTAGE_LINUX.txt` in this archive for the
small portability fixes that were needed). There are no command-line
options; `san` refuses to start if it is given any arguments:

```
$ ./san --help
san: no command line arguments
```

## 2. Starting the program

Just run it with no arguments:

```
$ ./san
Welcome to the SAN Kit.
Revised: 1994.02.22

: 
```

The `: ` at the end is the command prompt. On startup `san` also silently
tries to read and execute a batch file called `init.ci` from the current
directory (see §7, "Batch files") if one exists; it is fine if it doesn't.

The game starts, as you'd expect, from the normal opening position, with
White to move.

Type `exit` (or send end-of-file, e.g. Ctrl-D) to quit.

## 3. The two ways to make a move

### 3.1 Typing a move directly

If you type something that isn't a recognized command, `san` tries to parse
it as a move in **Standard Algebraic Notation** (SAN) and, if it's legal,
plays it — and then, unless you've turned this behavior off (see the `napr`
option below), the program immediately answers with a move of its own,
chosen by whichever "search strategy" is currently active for that side
(the built-in default is `eat`, described in §6):

```
: e4
  1. e4
bRbNbBbQbKbBbNbR
bPbPbPbPbPbPbPbP
  ::  ::  ::  ::
::  ::  ::  ::  
  ::  ::wP::  ::
::  ::  ::  ::  
wPwPwPwP  wPwPwP
wRwNwBwQwKwBwNwR
  1.  ...   Nh6
bRbNbBbQbKbB  bR
bPbPbPbPbPbPbPbP
  ::  ::  ::  bN
::  ::  ::  ::  
  ::  ::wP::  ::
::  ::  ::  ::  
wPwPwPwP  wPwPwP
wRwNwBwQwKwBwNwR
:
```

Each played move is echoed on its own line (with a move number for White,
`...` for Black), and the resulting board is displayed automatically. The
board display uses two characters per square: color (`w`/`b`) and piece
letter (`P`, `N`, `B`, `R`, `Q`, `K`), or `::`/spaces for empty squares —
this is a plain-text ASCII board, not a graphical one.

### 3.2 The `exsm` command (execute supplied move)

`exsm` plays a move without triggering an automatic reply from the engine.
This is the normal way to enter *both* sides' moves yourself, e.g. to set up
or replay a specific game:

```
: exsm e4
  1. e4
[board...]
: exsm e5
  1.  ...   e5
[board...]
: exsm Nf3
  2. Nf3
[board...]
```

SAN input understood by the parser includes ordinary piece/pawn moves
(`e4`, `Nf3`, `Bb5`, `Qxd5`, `Nbd7` when disambiguation is needed),
castling (`O-O`, `O-O-O`), promotion (`e8=Q`), and check/mate suffixes
(`+`, `#`) — see `SAN_DOC/Standard` in the original distribution for the
full, formal grammar the SAN Kit implements (SAN was essentially
standardized by this project).

## 4. Inspecting the position

| Command | Effect |
|---|---|
| `dvcb` | display value: chess board (ASCII diagram, as shown above) |
| `dvfe` | display value: current position in FEN (Forsyth–Edwards Notation) |
| `stat` | status report: side to move, castling rights, en-passant square, half/full-move counters, game status, playing level, response time, active options |
| `dvts` | display value: timestamp |

Example:

```
: dvfe
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
: stat
actc: 0   cast: 15   epsq: -1   hmvc: 0   fmvn: 1
census: 0  status: 0  setup: 0  level: 31  response time: 10
Active options:
```

## 5. Setting up a position

You don't have to play from the start — you can load any legal (or even
illegal, for testing) position with a **FEN string**, given as six
space-separated tokens (the command itself takes 6 arguments, one per FEN
field):

```
: svfe rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
```

Other position-editing commands, useful for constructing test positions
piece by piece:

| Command | Effect |
|---|---|
| `newg` | start a brand-new game from the standard opening position |
| `cvcb` | clear value: chess board (empty the board) |
| `svsq <color><piece><file><rank> ...` | set value: square — place a piece, e.g. `svsq wKe1 bKe8` |
| `cvsq <square> ...` | clear value: square (empty specific squares) |
| `svac <w\|b>` | set value: active color (whose move it is) |
| `svca <K\|Q\|k\|q> ...` | set value: castling availability |
| `cvca` | clear value: castling availability |
| `svep <square>` | set value: en-passant target square |
| `cvep` | clear value: en-passant target square |
| `svfn <n>` | set value: fullmove number |
| `svhc <n>` | set value: halfmove clock (for the 50-move rule) |

## 6. Move selection strategies (letting the computer play)

The SAN Kit ships with a small set of interchangeable "strategy modules",
each identified by a three-letter name:

| Name | Description |
|---|---|
| `eat` | best simple capture (falls back to a plausible non-capturing move if none is available) — this is the default for both sides |
| `gtp` | Gillogly TECH program strategy |
| `ran` | pure random legal move |
| `sc0` | Stanback Chess Program, internal variant |
| `sc1` | Stanback Chess Program, external variant |

None of these is a strong engine — they exist mainly as worked examples for
people writing their own strategy (see `SAN_DOC/DIY` in the original
distribution, and §9 below).

Set the strategy for White and Black (in that order) with `svss`:

```
: svss ran ran
: dvss
w: ran
b: ran
```

`dvss` (display value: search strategies) shows what's currently active.

Once a strategy is selected, you can let the program play against itself:

```
: play 4
  1. g3
[board]
  1.  ...   b5
[board]
  2. a4
[board]
  2.  ...   h5
[board]
```

`play <n>` selects and plays `n` half-moves total (omit `n` for one
half-move); `game` plays out an entire game to completion (checkmate,
stalemate, or another terminal condition); `rtmv <n>` retracts (unmakes)
the last `n` half-moves.

`auto <w|b>` runs the SAN Kit's built-in "automatic competition" mode for
the given color (used for engine-vs-engine test matches; see
`SAN_MSC/gsx.c` and `SAN_MSC/srch.c` in the original distribution for
related tooling).

## 7. Searching for/verifying a move

`srch` asks the active strategy to pick a move and then checks whether the
result matches one (or more) target moves you supply — handy for
regression-testing a strategy against known-good moves from an opening book
or test suite:

```
: newg
: svop nabd
: e4
: srch e5
Selected: exf5
*srch: 0: failure
```

(Here Black's automatic `f5` reply to `1.e4` meant `1...e5` was no longer
even a legal move to search for from that position — the point is simply to
show the pass/fail report format: `*srch: 1: success` or `*srch: 0:
failure`.)

## 8. Options

`svop <name> ...` turns options on (there's no explicit "off" — clear the
whole option set or start a new session if needed); `cvop` clears options;
`dvtf`/general status shows their state through `stat`.

| Option | Meaning |
|---|---|
| `nabd` | **n**o **a**uto **b**oard **d**isplay — stop printing the board after every move |
| `namd` | **n**o **a**uto **m**ove **d**isplay — stop echoing the move notation after every move |
| `napr` | **n**o **a**uto **p**rogram **r**esponse — when you type a move directly (§3.1), don't have the engine automatically reply |
| `emde` | extraordinary move disambiguation effort |
| `nmde` | no move disambiguation effort |
| `dbug` | debugging |
| `test` | testing |
| `trpt` | trace: processing time (prints elapsed time for each command) |
| `verb` | verbosity |

For a quiet, script-friendly session (no board spam, no unwanted replies),
a typical batch file starts with:

```
svop nabd namd napr
```

## 9. File formats: PGN, EPD, and "translation" commands

The SAN Kit understands three standard chess file formats, all of which it
also helped define as public specifications:

- **PGN** (Portable Game Notation) — human-readable game scores with
  `[Tag "value"]` headers, as used by essentially every chess database.
- **EPD** (Extended Position Description) — one FEN-like position per line,
  with optional operation fields, commonly used for test suites.
- **PGC** — the SAN Kit's own compact internal "games to code" format.

`san` can batch-convert a whole PGN file into any of these with the `tfg*`
family of commands, each taking an input filename and an output filename:

| Command | Effect |
|---|---|
| `tfgg <in> <out>` | translate file: games to games — i.e. PGN normalized back to PGN (re-formats/validates a PGN file) |
| `tfge <in> <out>` | translate file: games to EPD |
| `tfgc <in> <out>` | translate file: games to PGC |
| `tfgv <in> <out>` | translate file: games to (SAN) variations, one game per line |

Example, using a PGN collection of Bobby Fischer games:

```
: tfge RJF60.PGN games.epd
```

produces `games.epd` with one line per position reached in every game in
`RJF60.PGN`. (Set `svop nabd namd` first if you don't want the board of
every intermediate position scrolling past as the file is processed —
translation works by internally replaying each game move by move.)

Related single-game commands:

| Command | Effect |
|---|---|
| `lfer <file>` | load file: event report (read one game/report into memory) |
| `sfer <file>` | save file: event report |
| `sfcr <file>` | save file: correspondence report |
| `dver` | display value: event report |
| `dvcr` | display value: correspondence report |
| `svtf <tag> [value]` | set value: tag field — set a PGN header tag, e.g. `svtf White "Fischer, Robert J."` |
| `cvtf <tag> ...` | clear value: tag field |
| `dvtf` | display value: tag field |
| `dvte` | display value: tag environment (all tags) |

## 10. Batch (command) files

Any sequence of commands you'd type interactively can be put in a plain
text file and run with `call <filename>`; batch files can call other batch
files (nested), and `rtrn` returns early from the current one:

```
# quiet.ci — a small batch file
svop nabd namd
newg
```

```
: call quiet.ci
```

As mentioned in §2, a file named `init.ci` in the working directory is
loaded automatically every time `san` starts, so it's a natural place to
put your preferred default options.

## 11. Miscellaneous commands

| Command | Effect |
|---|---|
| `help` | list every command with a one-line description |
| `echo <text>` | print the given text back (useful in batch files, e.g. for progress messages) |
| `beep` | emit an ASCII BEL character |
| `noop` | do nothing (accepts and ignores any arguments) |
| `afdo <file>` / `ofdo <file>` / `cfdo` | append/open/close a "dribble" file that logs a transcript of the session |
| `enum <n>` | enumerate all legal move sequences ("perft"-style) `n` half-moves deep from the current position, with a running total — useful for validating the move generator |
| `dvhg` | display value: hash generation tables |
| `dvas` | display value: hash address and signature (Zobrist-style position hashing) |
| `test` | developer test hook (a no-op in the stock distribution) |

Example of `enum` (perft) from the opening position:

```
: enum 1
[... 20 lines, one per legal first move, each followed by ": 1"]
: : Total: 20
```

## 12. Quick reference: a full sample session

```
$ ./san
Welcome to the SAN Kit.
Revised: 1994.02.22

: svop nabd namd
: newg
: exsm e4
: exsm c5
: exsm Nf3
: exsm d6
: exsm d4
: exsm cxd4
: exsm Nxd4
: exsm Nf6
: exsm Nc3
: dvfe
rnbqkb1r/pp2pppp/3p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R b KQkq - 0 5
: svss eat ran
: play 6
[white plays "eat" strategy moves, black plays random moves...]
: stat
actc: 1   cast: 15   epsq: -1   hmvc: ...   fmvn: 8
...
: exit
```

## 13. Extending the SAN Kit (writing your own strategy)

Because the source is provided, you can plug in a real search/evaluation
routine. In outline: each strategy implements eight hook functions (init,
term, new-game, select, play, unplay, set-position, config), registers
itself in `sansss.c`, gets a slot in `sandef.h`'s strategy table, and a
`Makefile` rule for its own `.c`/`.h` pair. The full step-by-step recipe,
with a copy-paste template, is in `SAN_DOC/DIY` in the original
distribution — the short version is: copy one of the existing `x_*.c`
strategy files (e.g. `x_ran.c`, the simplest one) and modify it.

## 14. Where to look next in the source

- `sandef.h` — global constants/typedefs; the best starting point for
  reading the code.
- `sancmd.c` / `sandci.c` — the command table and command implementations
  (this is where every command in this guide is actually defined).
- `sanmne.c` / `sanmnd.c` — SAN move encoding / decoding.
- `sanfen.c` — FEN encoding/decoding.
- `sanpgn.c` / `sanrdr.c` — PGN writing / PGN reading.
- `x_eat.c`, `x_gtp.c`, `x_ran.c`, `x_sc0.c`, `x_sc1.c` — the example
  strategy modules discussed in §6 and §13.

Or, from inside `SAN_SRC`:

```sh
grep -e ">>>" *.[hc]   # one-line description of every file
grep -e "-->" *.c      # one-line abstract of every function
```
