A crossword board game solver. It may be the best one in the world (so far).
Current master build status:
A crossword board game is a board game where you take turns creating crosswords with one or more players. Some examples are:
- Scrabble™️ Brand Crossword Game
- Words with Friends
- Lexulous
- Yahoo! Literati (defunct)
See the manual and information here:
https://domino14.github.io/macondo
To generate pb files, run this in the macondo directory:
go generate
Make sure you have done
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
(Notes mostly for myself)
Tag the release; i.e. git tag vX.Y.Z, then git push --tags. This will kick off a github action that builds and uploads the latest binaries. Then you should generate some release notes manually.
If you want to use the neural network model, I recommend you use Triton server rather than the default Go server. It's much faster, but it's not trivial to run locally. You need Docker and the NVIDIA Container Toolkit (for GPU access from Docker).
-
Build the engines, once per machine. Triton runs each model as a TensorRT engine (
model.plan), compiled from the committedmodel.onnxfor your GPU. Engines are not in git because one only loads on the GPU generation and TensorRT version that built it. This builds every missing or out-of-date engine inside the same Triton image the server uses, so the versions always match (about 20 s per model):pytorch/build-engines.shRun it again after changing GPUs or the Triton image (set
TRITON_IMAGEif you use a different one than below;FORCE=1rebuilds everything). -
Start Triton. If your macondo directory is at
$HOME/code/macondo:docker run --gpus all --rm -p 8000:8000 -p 8001:8001 -p 8002:8002 -v $HOME/code/macondo/data/strategy/default/models/:/models nvcr.io/nvidia/tritonserver:26.08-py3 tritonserver --model-repository=/models -
Point macondo at it: set the
MACONDO_TRITON_USE_TRITONenvironment variable totrue(andMACONDO_TRITON_URLif Triton's gRPC port is notlocalhost:8001).
The model is chosen with triton-model-name and triton-model-version in
the config (or MACONDO_TRITON_MODEL_NAME / MACONDO_TRITON_MODEL_VERSION).
With --model-control-mode=explicit, Triton must also be told to load it
(--load-model=<name> or pytorch/triton-models.sh load <name>).
Three value nets ship in data/strategy/default/models/. All are the same
transformer (8 layers, d_model 192, a token per square), scoring each of the
top 50 static-equity candidates by win probability:
| name | trained on | vs HastyBot | head to head |
|---|---|---|---|
macondo-tf (default) |
81M HastyBot self-play games, 6 passes, one position per game per pass | 58.14% ± 0.18 | beats the same recipe on 54M games 50.63% ± 0.16 |
macondo-tf-selfplay |
the 54M-game net fine-tuned on 3M of its own games (mixed 50/50 with 3M HastyBot games) | 57.07% ± 0.18 | beats the 54M-game net 50.37% ± 0.16 |
macondo-tf-csw (Collins lexica) |
81M CSW24 HastyBot self-play games, 6 passes | 58.06% ± 0.18 (CSW24) | beats the same recipe on 54M games 50.62% ± 0.16 |
Win rates are 100k game pairs, ties counted half, with a 95% interval, in
NWL23 unless marked. The self-play net exploits HastyBot a little less but beats its parent head to
head. Training runs and matches are logged in pytorch/RUNS.md and
pytorch/experiments.md. To rebuild them, or train one for another lexicon
(any alphabet: see pytorch/features.py), follow pytorch/TRAINING.md.
To pick one for a whole session, set triton-model-name (e.g.
MACONDO_TRITON_MODEL_NAME=macondo-tf-selfplay). In autoplay,
-tritonmodel1 / -tritonmodel2 give each player its own model, so the two
can play each other.
Each lexicon family can have its own net. The model name is a base: a game
plays with <base>-csw in the Collins lexica, and <base>-<distribution>
(-german, -french, ...) in other alphabets, when that model exists in
the repository (or as an ONNX file). English lexica without their own model
fall back to the base model; another alphabet without one cannot use the
net, since a net only reads the alphabet it was trained on. Triton in its
default mode loads every model in the repository, a few hundred MB of GPU
memory each.
Each model folder holds:
model.onnx: the model itself, its graph and full-precision (fp32) weights, in the portable ONNX format. This is what is committed. The CPU path below runs it directly.model.plan(built bypytorch/build-engines.sh, not committed): the TensorRT engine Triton serves, the same net compiled for your GPU in half precision (fp16), which is much faster on NVIDIA tensor cores and changes the outputs only by rounding (win probabilities by about 0.002).config.pbtxt: Triton's description of the model's inputs and outputs.
Without Triton (triton-use-triton false), macondo runs the same model's
model.onnx on the CPU with ONNX Runtime.
Slower than a GPU, but enough for mleval and the occasional game.
- Download ONNX Runtime 1.29 for your platform from its
releases page
(e.g.
onnxruntime-linux-x64-1.29.0.tgz) and unpack it anywhere. On macOS,brew install onnxruntimealso works if it is 1.29. - Point macondo at the library, in the config or the environment:
onnxruntime-lib: /path/to/onnxruntime-linux-x64-1.29.0/lib/libonnxruntime.so(MACONDO_ONNXRUNTIME_LIB). Optional:onnx-threads(MACONDO_ONNX_THREADS), threads per evaluation; ONNX Runtime picks one per core by default. - Pick the model as above (
triton-model-name); macondo loadsdata/strategy/default/models/<name>/<version, default 1>/model.onnx.
This needs a cgo build (the default when building from source on the target machine).
Wolges-awsm is Copyright (C) 2020-2022 Andy Kurnia and released under the MIT license. It can be found at https://github.com/andy-k/wolges-awsm/. Macondo interfaces with it as a server.
KLV and KWG are Andy Kurnia's leave and word graph formats. They are small and fast! See more info at https://github.com/andy-k/wolges
Some of the code for the endgame solver was influenced by the MIT-licensed Chess solver Blunder. See code at https://github.com/algerbrex/blunder