diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-16 01:22:24 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-16 01:22:24 -0500 |
| commit | b00c419780cb6b15972e3aae3e584677da2c40e3 (patch) | |
| tree | 37315f345ead53d0ef941a044494fc91af74b169 /scripts/setup-chess-README.md | |
| parent | f53de255ffb94f72339b3922520dfb0579520779 (diff) | |
| download | archsetup-b00c419780cb6b15972e3aae3e584677da2c40e3.tar.gz archsetup-b00c419780cb6b15972e3aae3e584677da2c40e3.zip | |
Install setup-chess prerequisites automatically
Diffstat (limited to 'scripts/setup-chess-README.md')
| -rw-r--r-- | scripts/setup-chess-README.md | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/scripts/setup-chess-README.md b/scripts/setup-chess-README.md new file mode 100644 index 0000000..4199c6f --- /dev/null +++ b/scripts/setup-chess-README.md @@ -0,0 +1,116 @@ +# setup-chess.sh + +## Overview + +Single-shot installer for a chess analysis stack on Arch Linux: the En Croissant GUI, Stockfish, Lc0, and the nine Maia personality engines (1100–1900 Elo). All artifacts land under `$HOME/.local/`; no root-owned files. The script is idempotent — re-runs replace broken components, preserve user-tuned settings in `engines.json`, and keep custom engine IDs stable across invocations. + +Run it once on a fresh Arch install to get a working chess setup, or run it again later (with `--force` or `--component <name>`) to repair a single component without rebuilding the rest. + +## Usage + +``` +./setup-chess.sh # full install / refresh +./setup-chess.sh --force # re-download and rebuild everything +./setup-chess.sh --component lc0 # repair just lc0 +./setup-chess.sh --component lc0 --force # force re-install of just lc0 +``` + +Valid `--component` names: `prereqs`, `en-croissant`, `lc0`, `maia`, `stockfish`, `engines-json`, `desktop`. + +## What the script does + +Each section below maps to one numbered block in `setup-chess.sh`. + +### 1. Prerequisites + +Checks for the tools and libraries used downstream and installs missing pacman packages with `pacman -S --needed --noconfirm` via `sudo` when not running as root. Always-required: `git`, `curl`, `tar`, `coreutils`, `grep`, `desktop-file-utils`, `fuse2`. The build-toolchain deps (`base-devel`, `meson`, `ninja`, `python`, `pkgconf`, `protobuf`, `zlib`, `openblas`, `eigen`) are installed when a healthy system `lc0` is unavailable, since the AUR path can still fail and fall back to a source build. + +### 2. En Croissant AppImage + +Downloads the pinned version of the En Croissant AppImage to `~/.local/bin/en-croissant.AppImage`, verifies its SHA256, and marks it executable. Skipped when the AppImage already exists, unless `--force` is set. + +### 3. Lc0 + +Tries paths in order of speed and durability, gating each on a UCI handshake smoke test (`echo uci | timeout 5 <bin> | grep '^id name Lc0'`): + +1. **Existing `~/.local/bin/lc0` passes** — keep it as-is. +2. **System `/usr/bin/lc0` passes** — symlink it into `~/.local/bin/lc0`. This is the steady state for an AUR install. +3. **AUR helper available** — `yay -S --needed --noconfirm lc0 lc0-network-sm` (or `paru` if that's what's installed), then symlink. Pacman-managed binaries get re-resolved automatically when Abseil, Protobuf, or OpenBLAS bump SONAMEs — see the BLAS conflict note below. +4. **Source build** — clone the upstream `v0.32.1` tag and build with the project's own `build.sh`. Slower (several minutes), and the resulting binary is dynamically linked, so a later library bump can break it. Used only as the last-resort fallback. + +The final binary is run through the smoke test again. If it fails, the script aborts with a pointer to running `lc0` manually to read the load-time error. + +### 4. Maia weights and wrappers + +Downloads the nine `maia-{1100..1900}.pb.gz` files from the CSSLab Maia release `v1.0` into `~/.local/share/maia/`, verifying each against a pinned SHA256. Existing files are re-validated against the pin; a mismatch triggers a re-download. + +Then generates the nine wrapper scripts at `~/.local/bin/maia-{1100..1900}`. Each is a one-line shell script that execs the lc0 binary with the matching `--weights=` flag. Wrappers are regenerated unconditionally so they always point at the current `~/.local/bin/lc0` (handy if step 3 swapped the binary out from under them). + +### 5. Stockfish + +Probes `/proc/cpuinfo` and selects the best Stockfish binary for the CPU — in order, `vnni512`, `avx512`, `avxvnni`, `avx2`, `bmi2`, `sse41-popcnt`, `x86-64`. Downloads the matching tarball from the pinned Stockfish release (`sf_18`), verifies its SHA256, extracts it into `~/.local/share/org.encroissant.app/engines/stockfish/`, and runs a UCI handshake to confirm the binary works. + +### 6. engines.json + +Writes `~/.local/share/org.encroissant.app/engines/engines.json` with Stockfish plus the nine Maia entries. Before writing, backs up the existing file to `engines.json.bak.<timestamp>`. + +The Python that builds the JSON does three things worth knowing: + +- **Engine IDs are preserved by name.** If an entry named `Stockfish` already exists, its UUID is reused; otherwise a fresh one is generated. Same for each Maia engine. This keeps any per-engine state En Croissant tracks (analysis history, custom names) stable across re-runs. +- **User-tuned settings are preserved.** The script ships conservative defaults (`Stockfish: Threads=1, Hash=16, MultiPV=1`), but if the existing entry has different settings, those are kept instead of clobbered. Re-running the script never resets a tuned engine to defaults. +- **Unknown engines are preserved.** Any entry in the existing file whose name isn't one of the ten managed ones (Stockfish + 9 Maias) is appended to the new file as-is. Hand-added engines like Komodo or a second Stockfish build survive a re-run. + +### 7. Desktop file + +Writes `~/.local/share/applications/en-croissant.desktop` so En Croissant appears in app launchers (rofi, fuzzel, Wayland app drawers, etc.) and runs `update-desktop-database` to refresh the cache. + +## Known issues + +### BLAS provider conflict + +The AUR `lc0` package depends on `openblas`, which on Arch is provided by the `blas-openblas` package. `blas-openblas` is mutually exclusive with the reference netlib BLAS bundle (`blas` + `cblas` + `lapack`). A system that has the netlib trio installed will see pacman refuse the lc0 transaction: + +``` +:: blas-openblas-0.3.33-1 and blas-3.12.1-2 are in conflict. Remove blas? [y/N] +error: unresolvable package conflicts detected +``` + +The script's `lc0` section detects this state before invoking the AUR helper (because `--noconfirm` would just abort), prints a warning with the resolution command, and falls through to the source-build path for that run. + +To resolve once and for all: + +``` +sudo pacman -S blas-openblas +``` + +Pacman prompts to remove `blas`, `cblas`, and `lapack` (answer `y`), then installs `blas-openblas`. `blas-openblas` provides the same `libblas.so` / `libcblas.so` / `liblapack.so` ABIs, so any package linked against BLAS (NumPy, SciPy, R, Octave, GIMP G'MIC, OpenCV, etc.) keeps working — and typically runs faster, since OpenBLAS is heavily optimized while the netlib reference impl is not. + +The swap is reversible (`sudo pacman -S blas cblas lapack` flips it back), and most Arch users with scientific software already run on `blas-openblas` by default. + +### En Croissant: Lc0/Maia hangs when playing engine as Black + +When you set up a "play vs engine" game in En Croissant with the engine as Black and yourself (the human) as White with **no clock**, En Croissant fills your `wtime` field with `4294967295` (UINT32_MAX) to signal "no time control." Lc0 parses `wtime` as a bounded integer and rejects anything above ~2.1 billion ms: + +``` +go wtime 4294967295 btime 30000 winc 0 binc 2000 +error out of range value 4294967295 +``` + +The engine never issues `bestmove`. The UI sits there waiting forever. This affects every Maia engine and any other Lc0-based engine, since they all share the same UCI parser. + +**Workaround:** when setting up the game, give White a finite time control. Anything reasonable (60 min + 0 inc, even 1 day) is well below Lc0's limit. The `go: {t: "Nodes", c: 1}` setting that ships in `engines.json` only governs analysis mode, not play mode — the time control comes from the game dialog. + +This is an En Croissant bug; a fix would either omit `wtime` entirely when a side has no clock, or cap the sentinel to a value Lc0 accepts (e.g. `2147483647`). + +## Files this script manages + +``` +~/.local/bin/en-croissant.AppImage En Croissant GUI +~/.local/bin/lc0 Lc0 engine (binary or symlink to /usr/bin/lc0) +~/.local/bin/maia-{1100..1900} Maia wrapper scripts (shell, exec lc0) +~/.local/share/maia/maia-{1100..1900}.pb.gz Maia neural network weights +~/.local/share/org.encroissant.app/engines/ + stockfish/stockfish-ubuntu-x86-64-* Stockfish binary + engines.json Engine registry read by En Croissant +~/.local/share/applications/en-croissant.desktop Launcher entry +``` |
