A minimal chess engine written in C++ — from scratch, no dependencies beyond the STL.
English · Українська · Русский
Final position of the built-in demo — the white queen has just delivered mate on d7.
- What is this?
- Quick start
- Use as a library
- Features
- Usage
- API reference
- How it works
- Project structure
- Roadmap
- Contributing
- License
A small, readable chess engine with no libraries under the hood — every rule is hand-rolled on top of the C++ standard library. It knows how the pieces move, validates moves, understands algebraic notation, and renders the board right in your terminal.
It's a learning project first: the code is written to be read. If you ever wondered how chess programs generate moves, src/chessEngine.hpp is a ~250-line answer.
Prebuilt binaries — grab one from the releases page: Linux (x86_64 / arm64), Windows (x86_64 / arm64), macOS (universal). The repo also ships one at bin/chess-engine (macOS universal — Apple Silicon & Intel):
git clone git@github.com:ByteMe6/chess-engine.git
cd chess-engine
./bin/chess-engineBuild from source (any platform with CMake ≥ 3.16 and a C++17 compiler):
cmake -B build
cmake --build build
./build/chess-engineThe demo plays a short game that ends in checkmate — watch the last lines:
$ ./bin/chess-engine
a b c d e f g h
8 r n b q k b n r 8
7 p p p p p p p p 7
6 6
5 5
4 4
3 3
2 P P P P P P P P 2
1 R N B Q K B N R 1
a b c d e f g h
Pawn e2: [ [ 5, 4 ], [ 4, 4 ] ]
Game over: White won
The game is over
a b c d e f g h
8 r k b n r 8
7 p p p Q p p p p 7
6 B 6
5 p 5
4 P 4
3 P 3
2 P P P P P P 2
1 R N B K N R 1
a b c d e f g hUppercase = white, lowercase = black. Old-school FEN vibes.
The whole engine is a single header. Pick your flavor, then just #include <chessEngine.hpp>.
CMake FetchContent — for minimalists, no package manager at all:
include(FetchContent)
FetchContent_Declare(chess-engine
GIT_REPOSITORY https://github.com/ByteMe6/chess-engine.git
GIT_TAG v1.1.0)
FetchContent_MakeAvailable(chess-engine)
target_link_libraries(your-app PRIVATE chess-engine::chessEngine)vcpkg — the repo ships an overlay port:
git clone https://github.com/ByteMe6/chess-engine.git
vcpkg install chess-engine --overlay-ports=chess-engine/portsConan — from a clone of this repo:
conan create .# then in your project's conanfile.txt
[requires]
chess-engine/1.1.0- ✅ Move generation for every piece — king, queen, rook, bishop, knight, pawn
- ✅ Sliding pieces done right — queen/rook/bishop walk each ray until blocked; captures end the ray, friendly fire is not allowed
- ✅ Full pawn logic — single push, double push from the start rank, diagonal captures only when an enemy is actually there
- ✅ Algebraic notation in and out —
makeMove("e2", "e4")just works - ✅ Move validation — illegal moves are rejected
- ✅ Turn order —
currColortracks whose move it is; moving out of turn is rejected - ✅ Check, checkmate & stalemate — moves that leave your own king in check are illegal; the game ends with
Game over: White wonorGame over: draw - ✅ Castling & en passant — full rules: rights are tracked and lost when the king or a rook moves, the e.p. window lasts exactly one move
- ✅ Chess960 castling — king and rooks can start anywhere on the back rank; castle by playing king-takes-own-rook, Shredder-FEN rights (
HAha) supported - ✅ Draw rules — the fifty-move rule, threefold repetition and insufficient material all end the game with
Game over: draw - ✅ Pawn promotion — a pawn on the last rank becomes whatever you pass to
promote(); keep playing without it and it's a queen by default - ✅ FEN import/export — start from any custom position with
loadFen()orBoard(fen), dump the current one withtoFen(); castling rights and the e.p. square are real FEN fields - ✅ ASCII board rendering — with file/rank coordinates
- ✅ Clean modern C++17 —
enum classpieces, structured bindings, an exhaustiveswitchwith a defensivethrow, STL only
| Piece | Letter | Movement |
|---|---|---|
| ♔ King | K |
one square in any direction |
| ♕ Queen | Q |
any distance along rank, file or diagonal |
| ♖ Rook | R |
any distance along rank or file |
| ♗ Bishop | B |
any distance along a diagonal |
| ♘ Knight | N |
L-shape jump — the only piece that jumps over others |
| ♙ Pawn | P |
one forward (two from the start rank), captures diagonally |
#include "src/chessEngine.hpp"
// board setup — see src/main.cpp for the full starting position
board.printBoard(); // render the board to the console
board.makeMove("e2", "e4"); // moves are plain algebraic notation
board.makeMove("e7", "e5");
board.makeMove("g1", "f3"); // illegal moves are simply rejected
Piece knight = board.board[5][5]; // the knight that just landed on f3
board.getPossibleMoves(knight); // -> e5 (capture!), g5, d4, h4, g1
// or start from any custom position
Board endgame("6k1/5ppp/8/8/8/8/8/R3K3 w - - 0 1");
endgame.makeMove("a1", "a8"); // back rank mate -> "Game over: White won"
board.makeMove("a7", "a8"); // pawn reaches the last rank...
board.promote(FigureName::Knight); // ...pick a piece, or skip for a queen| Method | Signature | What it does |
|---|---|---|
makeMove |
void makeMove(const std::string& from, const std::string& to) |
Applies a move given in algebraic notation; validates it first |
getPossibleMoves |
std::vector<std::array<int, 2>> getPossibleMoves(const Piece& piece) |
Every square the piece can legally move to |
printBoard |
void printBoard() |
Renders the position as ASCII with coordinates |
translateCoords |
std::array<int, 2> translateCoords(const std::string& square) |
"e2" → {6, 4}; throws on an invalid square |
translateToNotation |
std::string translateToNotation(std::array<int, 2> coords) |
{6, 4} → "e2" |
isInsideBoard |
bool isInsideBoard(int row, int col) |
Bounds check for the 8×8 board |
isInCheck |
bool isInCheck(PieceColor side) |
Is this side's king under attack right now |
isMate |
bool isMate(PieceColor side) |
Checkmate: in check and no legal move left |
isStalemate |
bool isStalemate(PieceColor side) |
Stalemate: not in check, but no legal move either |
promote |
void promote(FigureName name) |
Picks the piece for a pending promotion; skip it and the pawn queens on the next move |
loadFen |
void loadFen(const std::string& fen) |
Loads a position from FEN (also available as the Board(fen) constructor) |
toFen |
std::string toFen() |
The current position as FEN |
Board representation. The board is a plain 8×8 std::vector of Piece objects. Row 0 is rank 8 (black's back rank), row 7 is rank 1 (white's back rank):
board[row][col]
col: 0 1 2 3 4 5 6 7
a b c d e f g h
row 0 → rank 8 ┌─ black's back rank
row 7 → rank 1 └─ white's back rank
"e2" → board[6][4]
Move generation. Each piece type gets its own case in one switch. The queen, rook and bishop share addSlidingMoves(): walk in each direction step by step — an empty square keeps the ray going, an enemy piece is captured and ends it, a friendly piece blocks it. Knights and kings check a fixed set of offsets; pawns get their own rules for pushes and diagonal captures.
Validation. makeMove translates the notation, finds the piece, and only applies the move if the target square is in getPossibleMoves — otherwise nothing happens.
Type safety. Pieces are an enum class, so square contents can't be confused with plain chars, and the piece switch ends with a defensive throw for the unreachable case.
├── src/
│ ├── chessEngine.hpp # Board, Piece, move generation — the brains
│ └── main.cpp # Demo: a short game that ends in checkmate
├── tests/
│ └── tests.cpp # the test suite — run with ctest
├── bin/
│ └── chess-engine # prebuilt binary (macOS universal)
├── assets/
│ └── board.svg # the board diagram above
├── ports/
│ └── chess-engine/ # vcpkg overlay port
├── conanfile.py # Conan package
└── CMakeLists.txt # demo + tests + chess-engine::chessEngine library target
- Turn order enforcement
- Check & checkmate detection
- Stalemate
- Castling
- En passant
- Pawn promotion
- Draw rules (repetition, fifty-move, insufficient material)
- FEN import/export
- Chess960 (Fischer random) castling
- Test suite
Issues and pull requests are welcome — the roadmap is full of well-scoped ideas. See CONTRIBUTING.md for the two-minute version of the rules.
cmake -B build # setup
cmake --build build # compile (must stay warning-clean)
ctest --test-dir build # run the tests (must stay green)
./build/chess-engine # run the demoGPL-3.0 — free as in freedom.
Made with ♟️ and C++. If this repo taught you something, a ⭐ makes the pawns happy.