Sunfish: a Python Chess Engine in 111 lines of code
3,275
stars
785
commits
Lean
primary language
Aug 27, 2026
updated

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 126 lines of code!
There is also a (somewhat) stronger NNUE based sunfish, which you can also play against on Lichess. It's only 4096 bytes for the whole engine, so the neuron network is very small.
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.
The easiest way to play against sunfish is @sunfish-engine on Lichess, where you can also play against the stronger @sunfish-nnue-engine (see more below.)
The second easiest way is to play in your terminal:
$ pip install sunfish $ sunfish

Or, from a repo checkout, just run sunfish_ui/fancy.py -cmd ./sunfish.py.
The engine speaks UCI: point any tool at sunfish-uci (after
pip install sunfish) or ./sunfish.py (from a checkout).
UCI GUIs (Arena,
Cute Chess, PyChess,
BanksiaGUI): add an engine, protocol UCI, command sunfish-uci.
WinBoard / XBoard: use the
PolyGlot adapter with the
shipped config tools/polyglot.ini
(tested with PolyGlot 2.0.4; CI drives a real adapter session).
Command-line matches with fastchess or cutechess-cli:
fastchess -engine cmd=sunfish-uci name=sunfish \
-engine cmd=<other> name=other \
-each proto=uci tc=30+1 -rounds 10 -games 2
(see docs/TESTING.md for the full methodology).
./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.
Sunfish can also be packed into a single self-extracting executable of about 3kb:
$ tools/build/pack.sh sunfish.py packed.sh Total length: 3310 $ ./packed.sh go wtime 1000 btime 1000 winc 1000 binc 1000 info depth 1 score cp 0 pv d2d4 bestmove d2d4
The packed version uses a simplified UCI protocol by the TCEC 4k rules.
nnue_4k/ is a sunfish whose evaluation is classic's exact piece-square score plus a trained neural residual — with the whole accumulator and evaluation head packed into one Python integer, so a wide net costs a handful of big-int operations per node. It is measured about +200 Elo over classic at tournament time controls, the engine still packs to a few kilobytes, and every quantized net is certified (lane-exactness, incremental == from-scratch, exact antisymmetry) before it plays a game. See nnue_4k/README.md for the architecture, the training pipeline, and the measured results.
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
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 it with the
PyPy Just-In-Time interpreter — the launcher at the top
of sunfish.py picks pypy3 automatically when installed. Measured on the
current engine (fixed-depth battery, identical node counts): PyPy 3.11
searches ~2.7x faster than CPython 3.14 (81 vs 30 knps), worth on the
order of 100 Elo at fast time controls.
(Historical footnote: sunfish once ran fastest under PyPy 2.7, and an old version of this table said so. Modern sunfish requires Python >= 3.8 — the code uses the walrus operator — and modern PyPy 3 has long since closed the gap.)
The sunfish family keeps growing. Here is a (very incomplete) list of interesting derivatives:
Lean
50.6%
TeX
20.7%
Python
20.7%
Shell
8.0%
Sunfish: a Python Chess Engine in 111 lines of code
3,275
stars
785
commits
Lean
primary language
Aug 27, 2026
updated

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 126 lines of code!
There is also a (somewhat) stronger NNUE based sunfish, which you can also play against on Lichess. It's only 4096 bytes for the whole engine, so the neuron network is very small.
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.
The easiest way to play against sunfish is @sunfish-engine on Lichess, where you can also play against the stronger @sunfish-nnue-engine (see more below.)
The second easiest way is to play in your terminal:
$ pip install sunfish $ sunfish

Or, from a repo checkout, just run sunfish_ui/fancy.py -cmd ./sunfish.py.
The engine speaks UCI: point any tool at sunfish-uci (after
pip install sunfish) or ./sunfish.py (from a checkout).
UCI GUIs (Arena,
Cute Chess, PyChess,
BanksiaGUI): add an engine, protocol UCI, command sunfish-uci.
WinBoard / XBoard: use the
PolyGlot adapter with the
shipped config tools/polyglot.ini
(tested with PolyGlot 2.0.4; CI drives a real adapter session).
Command-line matches with fastchess or cutechess-cli:
fastchess -engine cmd=sunfish-uci name=sunfish \
-engine cmd=<other> name=other \
-each proto=uci tc=30+1 -rounds 10 -games 2
(see docs/TESTING.md for the full methodology).
./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.
Sunfish can also be packed into a single self-extracting executable of about 3kb:
$ tools/build/pack.sh sunfish.py packed.sh Total length: 3310 $ ./packed.sh go wtime 1000 btime 1000 winc 1000 binc 1000 info depth 1 score cp 0 pv d2d4 bestmove d2d4
The packed version uses a simplified UCI protocol by the TCEC 4k rules.
nnue_4k/ is a sunfish whose evaluation is classic's exact piece-square score plus a trained neural residual — with the whole accumulator and evaluation head packed into one Python integer, so a wide net costs a handful of big-int operations per node. It is measured about +200 Elo over classic at tournament time controls, the engine still packs to a few kilobytes, and every quantized net is certified (lane-exactness, incremental == from-scratch, exact antisymmetry) before it plays a game. See nnue_4k/README.md for the architecture, the training pipeline, and the measured results.
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
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 it with the
PyPy Just-In-Time interpreter — the launcher at the top
of sunfish.py picks pypy3 automatically when installed. Measured on the
current engine (fixed-depth battery, identical node counts): PyPy 3.11
searches ~2.7x faster than CPython 3.14 (81 vs 30 knps), worth on the
order of 100 Elo at fast time controls.
(Historical footnote: sunfish once ran fastest under PyPy 2.7, and an old version of this table said so. Modern sunfish requires Python >= 3.8 — the code uses the walrus operator — and modern PyPy 3 has long since closed the gap.)
The sunfish family keeps growing. Here is a (very incomplete) list of interesting derivatives:
Lean
50.6%
TeX
20.7%
Python
20.7%
Shell
8.0%