← All posts
Bot AI

Teaching a bot to imitate people

How we behavioural-clone a small neural net so one of our opponents plays like a blend of real recreational players.


Most of our poker opponents are hand-written: a transparent set of rules tuned to play a particular way. That is great for a teaching app — the bot can explain itself — but it has a ceiling. Real people are not a single rule set. They are a noisy mixture of tendencies that shifts spot to spot. So we built one opponent, Regular Reggie, who is not programmed at all. He is learned.

Behavioural cloning, in one sentence

Show a model a lot of (situation → action) examples from the players you want to imitate, and train it to predict the action from the situation. That is behavioural cloning, and it is the most direct, lowest-cost way to make a bot play like a population rather than play optimally.

The features: only what a fair player can see

The model reads a 21-number snapshot of the moment — and, critically, every number comes from public information: the bot's own two cards, the shared board, the pot, the bet it faces, its position, the street. Never an opponent's cards. (We wrote a whole post on why that matters.)

equity        // Monte-Carlo win chance for our own hand
potOdds       // price to call as a fraction of the resulting pot
position      // 1 = in position, 0 = first to act
holeSuited    // are our two cards the same suit?
strongDraw    // flush / open-ended straight draw?
boardPaired   // is there a pair on the board?
A few of the 21 features the learned bot reads each decision.

The data: a population of styles

Where do the examples come from? We self-play thousands of hands where every seat is a random draw from our five personalities — the calling station, the maniac, the disciplined regular, and so on — and record what each one does at every decision. The result is not one archetype; it is a realistic blend. The network learns the average recreational player, smoothed across styles.

The model: deliberately tiny

The network is a ~600-parameter multilayer perceptron (21 inputs → 24 hidden → 4 actions: fold, check/call, small bet, big bet). It is small on purpose: it trains in seconds, ships as a 12 KB file, and runs instantly in your browser with no server round-trip.

Sampling, not argmax

At the table we do not pick the single most-likely action. We samplefrom the network's probability distribution (after masking out illegal moves). That keeps Reggie's strategy mixed and unpredictable — the way a real player's choices vary — instead of robotically deterministic.

// mask to legal moves, then sample — a mixed strategy
const probs = forward(extractFeatures(state, playerId, equity));
const cls = sampleFrom(maskIllegal(probs, legal));

Does it work?

On held-out hands the clone matches the demonstrated action ~66% of the time. You can never hit 100% imitating a stochastic mixture — the players themselves are not deterministic — but it strongly recovers the patterns: it folds trash, it calls in position, it bets its good hands. The point was never raw accuracy; it was a believable, non-robotic opponent that we can later point at real people. Reggie is step one.

Keep reading