Introduction
Sunfish is a simple, but strong chess engine, written in Python. With its simple UCI interface, and removing comments and whitespace, it takes up just 142 lines of code! (tools/build/clean.sh sunfish.py | wc -l).
Yet it plays at ratings above 2000 at Lichess.
Because Sunfish is small and strives to be simple, the code provides a great platform for experimenting. People have used it for testing parallel search algorithms, experimenting with evaluation functions, and developing deep learning chess programs. Fork it today and see what you can do!
The name Sunfish refers to the Pygmy Sunfish, which is among the very few fish to start with the letters 'Py'. The use of a fish is in the spirit of great engines such as Stockfish, Zappa and Rybka. In terms of Heritage, Sunfish borrows much more from Micro-Max by Geert Muller and PyChess.
Play against sunfish!
The simplest way to play against sunfish is:
$ pip install sunfish && sunfish
Playing against sunfish 2023.
Do you want to be white or black? black
1 ♖ ♘ ♗ ♔ ♕ ♗ ♘ ♖
2 ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙
3
4
5
6
7 ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
8 ♜ ♞ ♝ ♚ ♛ ♝ ♞ ♜
h g f e d c b a
Score: 23, nodes: 11752, nps: 13812, time: 0.9
My move: d4
1 ♖ ♘ ♗ ♔ ♕ ♗ ♘ ♖
2 ♙ ♙ ♙ ♙ ♙ ♙ ♙
3
4 ♙
5
6
7 ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟
8 ♜ ♞ ♝ ♚ ♛ ♝ ♞ ♜
h g f e d c b a
Your move (e.g. c6 or g8h6): Nf6
Notation
The terminal interface uses algebraic notation for inputting moves. Here is a brief overview of how it works: From white's perspective, the columns are labeled a-h from left to right and the rows are labeled 1-8 from the bottom to the top. Each square is named with its respective letter than number (eg. a2, c3, h8). A move is communicated by the first letter of the moving piece followed by the destination square (the P for pawn moves is omitted and N is used for knights). If more than one of the same piece can move to a square, specify the file of the moving piece. If that is still ambiguous, specify the column.
In order to use the terminal interface, the notation used must be of a specific format, otherwise the entered move will not be read correctly. An "x" is sometimes used to denote a capture, but must be omitted (eg. Bd4 not Bxd4). Do not use a "+" to denote a check (eg. Bf7 not Bf7+). Do not use an "=" to denote pawn promotion (eg. e8Q not e8=Q) To denote a pawn capture the required notation is starting file followed by the ending square (eg. gf4 not gf). Castling must be denoted with lowercase 'o's (eg. o-o and o-o-o). Specifying a file or column must be after stating the piece (eg. Rae1 not aRe1). When notating en passant, the destination square should be the square the pawn ends up on, not the square of the pawn that was captured (eg. ef6 not ef5).
The terminal interface also supports explicit notation. This is where the source square is stated followed by the destination square (eg. e2e4).
(From a repo checkout: sunfish_ui/fancy.py -cmd ./sunfish.py. GUIs and tournament managers should use the raw UCI engine: sunfish-uci, or ./sunfish.py from a checkout.)
For a true minimalist experience, first we can "pack" sunfish into a compressed executable (less than 3KB!) and run it directly:
$ tools/build/pack.sh sunfish.py packed.sh Total length: 2953 $ ./packed.sh go wtime 1000 btime 1000 winc 1000 binc 1000 info depth 1 score cp 0 pv d2d4 bestmove d2d4
(See the UCI specification for the full set of commands.)
Troubleshooting
./sunfish.py automatically runs with pypy3 if installed (recommended, much stronger), otherwise python3.
If the engine fails to start, run sunfish_ui/fancy.py with -debug to see the underlying error,
and make sure python3 is on your PATH. On Windows, .py engines are launched
through your current Python interpreter automatically.
Playing with a graphical interface
It is also possible to run Sunfish with a graphical interface, such as PyChess or Arena.
Finally you can play sunfish now on Lichess or play against Recursing's Rust port, also on Lichess, which is about 100 ELO stronger.
NNUE version
There is an experimental version using an Efficiently updatable neural network. It is not yet fast enough to be stronger than classic sunfish, so it lives on the nnue branch until it works well.
Features
- Built around the simple, but efficient MTD-bi search algorithm, also known as C*.
- Filled with classic "chess engine tricks" for simpler and faster code.
- Efficiently updatable evaluation function through Piece Square Tables.
- Uses standard Python collections and data structures for clarity and efficiency.
Testing
Sunfish uses pytest for testing. To run the tests:
python3.12 -m pytest
You can also run specific test files:
python3.12 -m pytest tests/test_mate_puzzles.py
Or even specific tests:
python3.12 -m pytest tests/test_mate_puzzles.py::test_mate_in_one
Make sure you have installed the required dependencies (defined in pyproject.toml):
uv sync # or: pip install chess tqdm pytest pytest-asyncio
Limitations
Sunfish supports all chess rules, except the 50-move draw rule.
There are many ways in which you may try to make Sunfish stronger. First you could change from a board representation to a mutable array and add a fast way to enumerate pieces. Then you could implement dedicated capture generation, check detection and check evasions. You could also move everything to bitboards, implement parts of the code in C or experiment with parallel search!
The other way to make Sunfish stronger is to give it more knowledge of chess. The current evaluation function only uses piece square tables - it doesn't even distinguish between midgame and endgame. You can also experiment with more pruning - currently only null move is done - and extensions - currently none are used. Finally Sunfish might benefit from a more advanced move ordering, MVV/LVA and SEE perhaps?
An easy way to get a strong Sunfish is to run with the PyPy Just-In-Time interpreter. In particular, the Python 2.7 version of PyPy gives a 250 ELO boost compared to the CPython (2 or 3) interpreters at fast time controls:
Rank Name Elo +/- Games Score Draws
1 pypy2.7 (7.1) 166 38 300 72.2% 19.7%
2 pypy3.6 (7.1) 47 35 300 56.7% 21.3%
3 python3.7 -97 36 300 36.3% 20.7%
4 python2.7 -109 35 300 34.8% 24.3%
Family
The sunfish family keeps growing. Here is a (very incomplete) list of interesting derivatives:
- μSunfish - A heavily reworked MicroPython Sunfish derivative for ESP32-class microcontrollers, with bounded memory, stronger search, configurable skill levels, and UCI support.
- Numbfish - A compact Sunfish-based Python engine that adds an incrementally updated NumPy NNUE evaluation.
- sunfish_rs - A Rust port of Sunfish that preserves much of its search architecture while using more native Rust representations.
- Carnatus - A small Go port of Sunfish intended to keep the engine minimal but readable.
- Sunfish.js - A JavaScript port of Sunfish designed to run under Node.js or directly in a browser via a web worker.
- Chess.Mojo - A Sunfish-based UCI chess engine used as a proof of concept for the Mojo programming language.
- sunfish.lua - A direct human translation of the classic Sunfish implementation from Python into Lua.
- Solefish - A C++ port that deliberately follows the original Sunfish program structure closely as a learning exercise.
- sunfishNNUE - A Sunfish derivative that replaces its classical evaluation with NNUE evaluation using Stockfish-style neural networks.
- Moonfish - A Sunfish-derived engine adapted from Western chess to Chinese chess/Xiangqi with UCCI support.
- ParallelChessAI - A Sunfish-derived experiment investigating parallelization of chess-engine search.
- numworks_usunfish - A μSunfish adaptation designed to run as a playable chess engine on NumWorks calculators.
- chess-badger2040 - A standalone offline chess game that embeds a MicroPython Sunfish port on the RP2040-based Badger 2040 e-ink device.
- micropython-sunfish - An early port of Sunfish to MicroPython for running the engine on constrained embedded hardware.
- peterhinch/micropython-sunfish - Another independent MicroPython adaptation that makes Sunfish usable as an embedded chess-engine component.
- Vector-Anki-Sunfish - A project integrating Sunfish with the Anki Vector robot to let the robot participate in chess.
- chess-genetic-algorithm-sunfish - An experimental Sunfish derivative using genetic algorithms to evolve or tune chess-engine parameters.
- sunfishDDA - A Sunfish experiment exploring dynamic difficulty adjustment rather than simply maximizing engine strength.
- Blindfold-Sunfish - A Sunfish modification aimed at blindfold chess and alternative ways of interacting with the engine.
- Moonfish - A tiny C chess engine originally inspired by Sunfish that subsequently developed its own substantially different implementation and search approach.
License
Metadata
Release files for sunfish 2026
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sunfish-2026.tar.gz | 94.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sunfish-2026-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 145.8 kB
Release files / sunfish-2026.tar.gz
| Download URL | sunfish-2026.tar.gz |
|---|---|
| Size | 94.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8055daf21f1030f5ddff9748cdbd6a499da33876eb2fb4810e9e1c46bb9e7c8e
|
|
BLAKE2b-256 checksum How to use checksums |
f530ac91a0b5403af20a1197e4a15ccb226c06228472dbdc50585a43afeafa22
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency logRelease files / sunfish-2026-py3-none-any.whl
| Download URL | sunfish-2026-py3-none-any.whl |
|---|---|
| Size | 51.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
510d30c261c64a5300765e3ace79f4c7748f9b74d8c537b49066661b8e2fcb30
|
|
BLAKE2b-256 checksum How to use checksums |
b6bcca6747c34f11175361a909c47cce26a5300ca6a716413aa3bc85031f7228
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.
Transparency log