---
title: Can a Fruit Fly's Brain Learn Chess?
date: 2026-09-16
---

# Can a Fruit Fly's Brain Learn Chess?

There is a website where a fruit fly plays chess.

[@ErnestoSOFTWARE](https://x.com/ErnestoSOFTWARE/status/2098449947083362527) built [flychess-hq](https://flychess-hq.vercel.app/) on the wiring diagram of a real fly brain. Every legal move is played out, and each resulting board is injected as current into the fly's sensory neurons. A trained map then reads the fly's descending and motor neurons, ranks the moves against each other, and the fly plays its top pick. Two small assists sit outside the fly: it always takes an available checkmate, and it never walks into mate in one. Its creator reports that it plays at around 700 Elo.

That's a genuinely fun result for a brain that evolved for flying, finding food and courting, not for chess. It also made me wonder how much further the same brain could go.

In [The God Machine](/blog/2026/07/the-god-machine) I wrote that a single neuron is almost nothing, and that intelligence comes from how neurons are connected. So here's the question I couldn't stop thinking about. Humans didn't evolve for chess either. What we have that a fly doesn't is a large, trainable cortex sitting on top of older circuits. **What happens if you give the fly one?**

So, over a few intense days, I built six versions of that idea. The last one plays at about **1610 on Stockfish's rating scale**, and you can [play against it right now](https://demo.aanandagiri.com.np/fly-chess/).

Before going further, here's what to expect. This post explains how you can make a frozen brain simulation do a task it never evolved for, why my first results were wrong, and how to measure playing strength honestly. It does **not** show that a fly understands chess. The strongest version leans heavily on a classical search algorithm, and I'll be explicit about where the fly's contribution ends.

---

## The idea

The fly brain here is the **MaleCNS v1.0 connectome**: a complete map of the male fruit fly's central nervous system, with 166,606 neurons and 25.6 million connections, published by FlyEM at Janelia, Cambridge/MRC LMB and Google Research. A connectome is only a wiring diagram, so to make it *do* anything you simulate electrical activity flowing through it.

Here is the shape of the model. Read it from top to bottom, following one chess position:

```
chess board
    │  788 numbers describing the position, injected as current
    ▼
fly sensory neurons ──▶ frozen fly connectome (166,606 neurons)
                               │  activity read back out of the fly
                               ▼
                        small trainable "cortex"
                               │  current injected into 1,024 premotor neurons
                               ▼
                        fly motor neurons ──▶ a score for every legal move
```

The only part that learns is the small "cortex" in the middle. The fly's neurons and connections stay exactly as they were mapped.

I set four rules on day one and kept them for all six versions:

1. The connectome's wiring and synapse signs are never changed.
2. The chess board enters **only** as current injected into fly sensory neurons.
3. The cortex acts **only** by injecting current into fly premotor neurons, and the move is read out of the fly's own motor neurons.
4. Any claim that the fly contributes needs a control experiment to back it up.

Why so strict? Without rules 2 and 3, the cortex could learn to ignore the fly completely and read the board directly. You'd end up with an ordinary chess network with a fly attached for decoration. Rule 4 turned out to be the hardest one to live with.

---

## Version 1: numbers that looked like progress

The first notebook trained, played games and printed results. Then a careful review found that several of those results couldn't be trusted:

- **Move quality was scored from the wrong side of the board.** "How much worse was this move than the best one?" was calculated from the opponent's perspective, so good moves could look bad and bad moves could look good.
- **The search had a sign error.** When looking ahead, it passed scores back up the tree without flipping them to the other player's point of view, so it could prefer moves that were good *for the opponent*.
- **It reported an Elo rating that its games didn't support.**
- **A "lesion" control, which switches off part of the fly, couldn't actually prove the claim attached to it.**

The consequence was that every number from version 1 described the bugs as much as the model. So version 2 rebuilt the measurement first, and only then the model. **If your ruler is broken, improving the thing you're measuring is guesswork.**

---

## Version 2: the control experiment that humbled me

If the fly matters, taking it away should make the model worse. So version 2 trained several variants side by side, each for exactly the same number of steps, and measured how often each one picked the same move as Stockfish on 200 positions it had never seen:

| Variant | What it tests | Matched Stockfish's move |
|---|---|---:|
| Fly + cortex | the actual design | 16.5% |
| Fly + simple linear readout | similar to flychess-hq's approach | 17.5% |
| Cortex with **no fly** (same size) | is the fly needed at all? | 16.0% |
| Fly with **shuffled wiring** | does the real wiring matter? | 17.5% |
| Fly with no sensory input | does the board even get in? | 15.0% |
| A random legal move | the floor | 7.1% |

Every variant learned something, since all of them beat random guessing by more than double. But look at the spread: 15% to 17.5%, on only 200 positions. A difference of one or two percentage points on a sample that small is noise.

So what was the cortex learning from? Honestly, this experiment couldn't tell. The version without a fly did as well as the version with one, and so did the version with scrambled wiring. **At this stage, I could not claim the fly contributed anything measurable.** Writing that sentence down, instead of quietly picking the best-looking number, is the most important thing version 2 did.

---

## Versions 3 to 5.5: a smarter network still couldn't win

Version 3 looked at *why* the model was weak. Version 2 read the fly's activity from a group of central neurons, late in the simulation, and by then much of the information about material (who has which pieces) had faded. Version 3 reads activity earlier and also lets sensory neurons compete to be the source, which kept more of that information. In a bounded pilot, the model's error at judging who's winning a position dropped by 42%.

Then it played real games, and lost **all 14** against Stockfish set to 1320 and 1520. It also drew all 8 games against a simple greedy opponent.

Versions 4, 5 and 5.5 tried three different directions: a stronger training curriculum, self-play, and a variant where only the final readout trains while a short lookahead (one move and the opponent's reply) proposes four candidate moves to the fly. The version 5.5 run lost every game it completed against Stockfish, at both 1320 and 1600.

Why would a better network still lose every game? A network that chooses a move from one look at the board can't check whether that move loses a piece two moves later. Chess punishes exactly that kind of mistake, which is why every strong chess program searches ahead. Version 5.5's one-move-and-reply lookahead was too shallow to fix that.

---

## Version 6: the fly advises, the search decides

Version 6 stopped asking the network to pick moves on its own and put it inside a real search.

The search is **alpha-beta**, the classic chess algorithm. It tries a move, then the opponent's replies, then its own replies to those, up to 8 half-moves deep within a 2-second budget. It skips any line that provably can't change the final decision. It also has a handwritten evaluation of each position (material, piece placement, pawn structure and king safety).

The fly-plus-cortex network has two jobs inside that search:

- **It suggests which moves to look at first.** Alpha-beta skips far more lines when it examines good moves early, so good suggestions let it search deeper in the same time.
- **It adds a small opinion to each move's score**, capped at ±20 centipawns (one fifth of a pawn).

Stockfish is only the teacher during training and the opponent during testing. It's never consulted when the model chooses a move.

This design has an important consequence, and I want to state it plainly: **any strength this player has belongs to the combination of fly, cortex and search.** The handwritten search could be doing most of the work. Measuring how much the fly adds needs a separate experiment, which I cover below.

Version 6 is also much smaller. The cortex has **2.38 million trainable parameters**, 83% fewer than version 5's 13.8 million, and the model's GPU memory peaked at under 1 GiB during training.

### The bug that gave away pieces

The first version 6 game went strangely: the player gave away material for no reason, then drew.

The cause was in how the search compared scores. Most scores included the network's small ±20 centipawn nudge, but checkmate scores didn't. When the search compared those two kinds of numbers, a bound that should have stayed below the value of a real checkmate could rise above it. The search then replaced a genuinely winning move with a worse one. In one position from that game, it reported an evaluation of +30,267, a number that no real line supported.

After the fix, which applies the nudge consistently to every score, that same position correctly finds a **checkmate in three moves** against every defence. It's now a regression test. A search is only as trustworthy as the consistency of the numbers it compares.

### Training on free Colab

Google Colab's free GPUs disconnect without warning, so version 6 treats every hour of compute as something it might lose. It records its time budget *before* doing work, so a crash can't accidentally grant a fresh four hours. It also saves checkpoints atomically and caches expensive work, so a restart picks up where it left off.

The final run trained for four hours on a Tesla T4: 66,521 updates, matching Stockfish's move on 26.8% of validation positions. Colab's monitor showed only about 1.5 GB of the T4's 15 GB in use. The likely bottleneck was generating training labels with Stockfish, which runs on a single CPU thread and can only be changed in a fresh run.

---

## How strong is it?

This is the part I care about most, because it's the easiest part to get wrong.

### One opponent is not a rating

Before playing any games, I fixed the test: 30 pairs of openings, with the model playing both colours in each, against Stockfish at 1320, with 2 minutes plus 1 second per move. The run stopped after 18 pairs:

| Games | Won | Drawn | Lost | Score |
|---:|---:|---:|---:|---:|
| 36 | 27 | 3 | 6 | 79% |

That looks great, but what does 79% against a 1320 opponent actually tell you? It says the model is stronger than 1320, not *how much* stronger. The 95% confidence interval ran from about 1300 to infinity. And because 12 of the 30 planned pairs never ran, the release test officially **did not pass**. I decided that rule before the games, so I'm not going to bend it after them.

### A gauntlet gives a real number

To get an actual rating, the model played a gauntlet: the same openings and clock, against Stockfish at four strengths.

Elo ratings rest on one formula. It says your expected score against an opponent depends only on the gap between your ratings:

```python
expected_score = 1 / (1 + 10 ** ((opponent_rating - my_rating) / 400))
```

For example, a player rated 400 points above their opponent is expected to score about 91%. The fit searches for the single rating at which the model's *expected* total score, across every game, equals its *actual* total score. Here's how that rating's predictions compare with reality:

| Stockfish level | Games | W / D / L | Actual score | Expected at 1610 |
|---:|---:|:---:|---:|---:|
| 1320 | 40 | 32 / 3 / 5 | 83.8% | 84.2% |
| 1500 | 40 | 23 / 4 / 13 | 62.5% | 65.3% |
| 1700 | 38 | 12 / 1 / 25 | 32.9% | 37.3% |
| 1900 | 38 | 7 / 4 / 27 | 23.7% | 15.9% |

**The rating is 1610, with a 95% confidence interval of 1549 to 1666, from 156 games.**

To get that interval, I resampled the openings 2,000 times with replacement, refit the rating each time, and kept the middle 95% of results. Every opening was played at all four levels, so each resampled opening carries all of its games with it.

### What 1610 does and doesn't mean

- **It isn't a Chess.com, Lichess or FIDE rating.** Stockfish's strength setting is calibrated against CCRL Blitz, a rating list for chess engines. Please don't compare 1610 with your online rating.
- **It depends on hardware.** The search gets 2 seconds per move, so a faster machine searches deeper and plays stronger. This rating belongs to my laptop (a Ryzen 7 and an RTX 4050).
- **It doesn't isolate the fly.** I haven't yet run the same games with the network switched off, so I can't tell you how much of 1610 comes from the fly and cortex versus the handwritten search.
- **It can't be compared directly with flychess-hq's ~700.** I don't know how that number was measured, and 1610 comes from one specific setup against Stockfish. Two ratings from different setups don't share a scale.

---

## Putting it online for free

Getting the board in front of people took more attempts than training the model did.

Hugging Face Spaces came first. A Streamlit version had no free GPU option there, so each move took about 10 seconds on a CPU. A Gradio version could use Hugging Face's free ZeroGPU and replied in about 2 seconds when I tested it locally, but on my account, any Space that runs Python required a paid PRO plan.

So I hosted it myself, using one design decision that made everything else easier: **the browser keeps the game, not the server.** Every time you move, your browser sends the entire move list, and the server replays it before answering. No server remembers anything between requests.

Why does that matter? Because it means *any* machine can answer *any* move, even in the middle of a game. So a Cloudflare Worker in front of the site tries my laptop's GPU first (about 2 seconds a move) and, if the laptop is off, quietly sends the move to a small home server instead (about 13 to 15 seconds a move). You get a slower reply instead of an error, and it costs nothing.

```
your browser ──▶ Cloudflare Worker ──▶ laptop GPU      (tried first, ~2 s/move)
 (keeps the game)                  └─▶ home server CPU (fallback, ~13–15 s/move)
```

The diagram shows the only decision the Worker makes: which machine answers this move. Neither machine needs to know what happened earlier in the game, because the move list arrives with every request.

The board is [chessground](https://github.com/lichess-org/chessground), the same board component Lichess uses. Finished games are saved (name, moves and result) so I can see how people actually play against it.

---

## What's next

Three experiments would answer the questions this post leaves open:

- **Play the same games with the network switched off.** The gap between that score and 1610 is the most direct measure of what the fly and cortex add.
- **Rerun version 6 with shuffled wiring.** If a scrambled connectome plays just as well, the real wiring isn't what's helping.
- **Finish the release test**, and give the Stockfish teacher more CPU threads so the GPU isn't waiting on it.

---

## What I learned

- **To know whether a component matters, remove it and measure the difference.** Version 2's controls were humbling, but they're the only reason I can say anything about the fly at all.
- **To trust a benchmark, fix its rules before the games are played**, and report an unfinished run as unfinished.
- **To get a rating, play several opponent strengths.** A single opponent only tells you whether you're above or below it.
- **To host a machine-learning demo for free, keep the server stateless**, so any machine can answer any request.

---

## Try it

- ♟️ **Play:** [demo.aanandagiri.com.np/fly-chess](https://demo.aanandagiri.com.np/fly-chess/)
- 🐙 **Code:** [github.com/Aananda-giri/fly-chess](https://github.com/Aananda-giri/fly-chess)
- 🤗 **Model:** [huggingface.co/Aananda-giri/fly-chess](https://huggingface.co/Aananda-giri/fly-chess)
- 🪰 **Where it started:** [fly-haven](https://github.com/Aananda-giri/fly-haven), a live simulation of a fly brain living in a forest
- 💡 **Original post:** [@ErnestoSOFTWARE on flychess-hq](https://x.com/ErnestoSOFTWARE/status/2098449947083362527)

**Credits:** the MaleCNS v1.0 connectome by FlyEM / Janelia, Cambridge / MRC LMB and Google Research (CC BY); [@ErnestoSOFTWARE](https://x.com/ErnestoSOFTWARE/status/2098449947083362527)'s [flychess-hq](https://flychess-hq.vercel.app/) for the inspiration; the Lichess evaluation and puzzle databases; Stockfish; and chessground and chess.js for the board.


![Image](/api/images/a7a7b192-cfa2-4fe5-a31f-117caffcb4cb.png)

