Daniel Gentile

Chess engine in C

A chess engine written by hand. No AI in the code. Four commits in and honest about it.

2026. In progress

  • C

Problem

Everything else on this page was built with AI agents writing most of the code. I wanted one project where that is not true, so that I can tell what I actually know, and so that anyone reading this has a piece of evidence that does not depend on trusting a co-author trailer. A chess engine is the right size. It is small enough to write alone and hard enough that mistakes show up as wrong move counts.

Approach

Bitboards from the start, not a mailbox board with a rewrite later. A position is twelve 64-bit integers, one per colour and piece type, indexed by colour times six plus piece, with one occupancy board per colour and a side to move. The hot questions in an engine, which squares are attacked and which are occupied, become single bit instructions. The first milestone is perft: the engine is not correct until it counts 20, 400, 8,902, and 197,281 moves from the start position, and that same count is the first benchmark.

Tech

C, compiled with clang and the C17 standard, warnings on. No dependencies beyond the standard input and output and integer headers. One build command. Castling rights, en passant, move generation, and search are not written yet.

My contribution

All of it. The language choice over Rust and Go, bitboards over mailbox, the array of twelve boards, the per-colour occupancy, and perft as the first proof are decisions I wrote down with their reasons before writing code.

AI usage

No AI wrote the code in this engine. I used Claude as a tutor: to suggest what to study next, to check my reasoning about a design choice, and to look at a function and tell me whether my understanding of it was right. It did not write the source, and the commits carry no co-author trailer.

Lessons

Four commits in and two lessons already. A bare 1 shifted left 63 places is a 32-bit integer and overflows silently; it has to be an unsigned 64-bit literal. And a derived board, like per-colour occupancy, has to be kept in sync on every move, which I expect to be the source of my first real bug. The build log below carries the rest as it happens.

Build log

  • Twelve bitboards and a printer

    The engine now has a board. A position is twelve 64-bit integers, one per colour and piece type, indexed by colour * 6 + piece, plus one occupancy board per colour and a side to move. The start position is set by shifting bits into place, and a printer draws any board as an eight by eight grid of ones and dots with rank 8 on top. I ran it and the four grids came out right.

    Things that bit me. A bare 1 << 63 is a 32-bit int and silently overflows; it has to be 1ULL. The bitwise NOT of an int flips 32 bits, not 64, so cast before printing. And the derived occupancy boards have to be kept in sync on every move, which I already suspect will be the source of my first real bug.

    Next: perft. The move counts from the start position are 20, 400, 8,902 and 197,281, and the engine is not correct until it prints them.

Back to projects