=== OpenKropki AI engines ====================================================

This document explains how each built-in computer opponent thinks. It is meant
for curious players and for people who want to tune or extend the engines. You
do not need to be a programmer to follow the ideas; code-level names are only
mentioned where they help someone reading the sources.


=== Shared plumbing ==========================================================

Every AI receives the same kind of question from the game:

  "Here is the current board as an OKP string. Whose turn is it? Which empty
   intersection should I play?"

OKP (OpenKropki Protocol) is a compact text snapshot of the grid, scores and
side to move. Each engine:

  1. rebuilds an internal board from that snapshot,
  2. chooses coordinates (x, y),
  3. returns them to the UI.

The live board is never edited by the AI thread itself. The main program waits
for the answer and only then places the stone. That keeps the display, sound
and "Resume" save consistent, and it means two AIs never rewrite the same
board at once - they take turns like humans.

Some engines keep a little private memory between moves (recent hotspots, a
transposition table). Starting a new game resets that memory. Engines do not
share memory with each other: Dumbo cannot confuse Viktor, Bender cannot
overwrite Tigran's scratch pads, and so on.


=== Dumbo ====================================================================

Role: beginner opponent. Fast, shallow, easy to beat once you know the rules.

Personality: "look near the action, grab an easy point if you see one, and
try not to do something obviously suicidal."

How a move is chosen:

  1. Build a small rectangle of "interesting" intersections around the stones
     that were played recently (the fight zone). Dumbo does not stare at the
     far corner of an empty A4 sheet.
  2. Inside that box, run a short MiniMax-style look-ahead a couple of plies
     deep. At each step it pretends both sides only care about the raw score
     difference (how many enemy dots each has captured).
  3. To stay cheap, the look-ahead is split across two worker threads (one
     exploring "my best", one exploring "opponent's best" in a simplified way).
  4. A hard-wired veto rejects dumping a lonely stone into three or more
     enemy neighbours with no friendly support - a classic beginner trap.

Strengths: instant replies; teaches you captures and local contact.
Weaknesses: no real plan for large surrounds; forgets the rest of the board;
easy to outflank.


=== Tigran ===================================================================

Role: classic "thinking" opponent from OpenKropki v0.4. Predictable and solid.

Personality: "examine a short list of candidate intersections near recent
moves; for each candidate, simulate a fixed-depth tree of replies; pick the
line whose worst-case score for me is best."

How a move is chosen:

  1. Remember the last few moves (a ring buffer). Around each of them, collect
     a spiral of empty neighbours - the "interesting field" list. Duplicates
     are removed. Obviously dead intersections (no liberties and no immediate
     capture) are dropped.
  2. For every remaining candidate, spawn a short MiniMax search (fixed depth,
     multi-threaded over the root candidates, and never more workers than the
     machine can spare for the window). The search is also capped at about 2
     seconds so a single-core PC cannot freeze for minutes. The leaf value is
     simply my_score - opponent_score after the simulated stones.
  3. At every node the engine tracks both a "worst" and a "best" outcome. The
     root move with the highest worst-case is preferred; ties break on best-
     case and on how many positions were examined.
  4. Empty-board opening: play the centre and clear the move memory.

Strengths: honest tactical depth on a small move list; good teaching tool for
"what if I play here?".
Weaknesses: the candidate list is local, so long-distance surround races are
often invisible; depth is fixed, so midgame slows without getting much wiser
(and on a slow CPU the 2-second cap may cut the tree short); no quiescence
for hanging captures beyond the ply limit.


=== Bender ===================================================================

Role: fast territorial specialist.

Personality: "kropki is mostly about efficient surrounds. Paint the board with
how tasty each empty intersection is for finishing a pocket, then play the
hottest spot - but never ignore a free capture or a one-move threat."

How a move is chosen:

  1. Tactical overrides (always first):
       - If some empty cell captures enemy dots right now, take the biggest
         capture (or prefer it over a smaller threat).
       - Else if the opponent could capture on their next turn by playing a
         certain cell, occupy that cell (defend) - or counter-capture if we
         have a capture of our own.
  2. Surround-efficiency influence map (the dots4all idea):
       - For every live friendly stone, grow a virtual pocket: start from the
         connected group and its liberties (empty orthogonal neighbours).
         Groups that already touch the map border are ignored (they cannot be
         cleanly sealed the usual way).
       - Score a pocket as roughly
             (value of what is being surrounded) / (fence length)^3
         Tight mouths around rich prey score high; huge loose shapes score
         low. OpenKropki only awards points for enemy dots, so Bender weights
         enemy stones inside the prey more heavily than empty sealed space.
       - Then greedily expand the virtual fence through liberties, always
         choosing the next empty cell that most improves that ratio, and paint
         the score onto candidate empties. Keep the maximum score seen at each
         empty cell across all seeds.
       - Repeat the same growth starting from every live enemy stone (so the
         map encodes both attacking and defending surrounds).
  3. Liberty urgency:
       - Groups with a single liberty (atari) splash a large bonus on that
         liberty. Two-liberty groups get a medium bonus. Own groups are boosted
         a little more than enemy ones (saving yourself slightly outranks
         the same-size attack).
  4. Soft veto: do not play a lone stone into three-plus enemy neighbours with
     no friendly support (same idea as Dumbo's veto).
  5. Quiet boards / openings: first move of the game goes to the centre; if
     the map is still cold, play near the last stone instead of a random corner.
  6. Ties between equal heat break toward contact with existing stones and
     proximity to the last move.

Strengths: very fast even on large sheets; plans long surrounds that shallow
search never sees; feels "purposeful" in the midgame.
Weaknesses: no deep reading of forcing sequences beyond one-move tactics; can
misjudge exotic multi-base fights; the cubic fence heuristic is a taste, not a
proof.

The influence map itself lives in a shared module (ai_influence). Bender still
owns the "play the hottest cell" personality on the sharp tactical map
(/ fence_length^3). Viktor borrows a milder strategic map (/ length^2) only as
a scout for long-range candidates - see below.


=== Viktor ===================================================================

Role: strong tactical fighter. Built on the same MiniMax skeleton as Tigran,
then extended with new ideas.

Personality: "fight up close. Capture when you can, answer real threats, make
threats of your own, and only then dig into a timed search with a smarter
leaf evaluation. When the local fight is quiet, listen to Bender's map for
where a long wall might still matter."

How a move is chosen:

  1. Build a richer candidate set than Tigran: recent-move spirals, liberties
     of frontier groups, contested contact points, and intersections that
     capture or threaten to capture.
  2. Bender-intuition seeds: after the local list is ready, Viktor builds a
     milder "strategic" surround-efficiency heat map (same growth as Bender,
     but / fence_length^2 instead of ^3, and softer liberty urgency) and
     injects its top dozen hottest empty cells - even if they sit far from the
     last few moves. Early long walls therefore light up for scouting without
     changing how Bender itself finishes tight mouths. The idea is a clean
     division of labour: Bender-style heat proposes where to look; Viktor still
     decides with tactics and search. Those seeds get a modest "shape" floor
     so they are not immediately discarded when the root list is capped for
     the time budget.
  3. Dead-pattern pruning removes obviously hopeless empties when no tactics
     are present.
  4. Hard short-circuits (skip the deep search when the answer is obvious):
       - take a real capture whenever one exists (before defending — the take
         often dissolves the local risk),
       - otherwise defend only when the move truly reduces the coming capture
         (futile "defences" that feed a lost base are ignored or punished),
       - otherwise, if we can create our own immediate capture threat, do that,
       - otherwise, if a live fence around one of our real bases (enclosed
         opponent dots) does not yet touch the board edge but a short empty
         orthogonal path still exists to the edge or to another already-safe
         own group (side-by-side only; diagonals do not count), play along that
         path before arming quiet 4-dot traps. Floating stone groups with no
         base are not bridged to the wall,
       - otherwise, in the late game (few empties left), prefer a non-cage safe
         fill over walking into the opponent's 4-dot traps; completed enemy
         cages are vetoed unless they somehow capture.
  5. If still undecided, run iterative deepening (depth 2 upward, capped) under
     a time budget (about 2 seconds). Root candidates are searched in
     parallel. A Zobrist transposition table remembers positions already seen
     in this game so deeper iterations and later moves can reuse work. Table
     generations are invalidated when a new game starts, so scores from a
     previous colour assignment cannot leak into the next match.
  6. At the search horizon, a short capture quiescence may play out hanging
     takes before evaluating.
  7. Leaf evaluation is not score alone: it adds a bounded structural tip for
     pockets, pressure on enemy liberties, bridges and local contact, plus a
     cutting-set term: each live group that does not touch the border is scored
     by prey size versus how many distinct empty liberties (the "mouth") still
     keep it open. Shrinking a long wall's gaps therefore shows up in the leaf
     before capture is forced. Real captures still dominate the scale.
  8. Root selection maximises the worst-case value, then breaks ties with
     best-case, capture potential, threat creation, shape and distance to the
     last move.

Strengths: sharp at capturing races and short forcing lines; refuses many
beginner blunders (feeding a dead group); uses thinking time well early on;
can notice long-range surround work thanks to Bender's heat seeds, and the
leaf eval now rewards shrinking almost-closed mouths (cutting sets), instead
of only staring at the last fight.
Weaknesses: on crowded midgame boards the time budget often only finishes a
shallow depth, so even a well-seeded long race may not be read deeply enough;
heavier CPU use than Bender or Dumbo; the heat map is still a heuristic scout,
not a proof that the pocket will close.


=== Choosing an opponent =====================================================

  Dumbo   - learning the rules, teaching a friend, quick games.
  Tigran  - a fair "classic computer" that reads a few moves ahead locally.
  Bender  - wants a fast game that feels about territory and cages.
  Viktor  - wants a tactical scrap and is willing to wait a second per move;
            also peeks at Bender's territorial heat for long-range candidates.

AI versus AI is supported. Because each engine is isolated and the UI applies
moves on the main thread, sparring matches exercise the same code paths as
human play.


=== See also =================================================================

  openkropki.txt  - player manual (rules, controls, menus)
  history.txt     - release notes
  ai_*.c          - source files for each engine (Dumbo, Bender, Tigran, Viktor)
  ai_influence.*  - shared heat map (tactical ^3 for Bender, strategic ^2 scout)
