=== 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). 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;
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.


=== 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."

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. Dead-pattern pruning removes obviously hopeless empties when no tactics
     are present.
  3. Hard short-circuits (skip the deep search when the answer is obvious):
       - take a real capture if it is at least as good as any saving defence,
       - 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.
  4. If still undecided, run iterative deepening (depth 2 upward, capped) under
     a time budget (about 1.5 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.
  5. At the search horizon, a short capture quiescence may play out hanging
     takes before evaluating.
  6. Leaf evaluation is not score alone: it adds a bounded structural tip for
     pockets, pressure on enemy liberties, bridges and local contact (GNU
     Kropki-inspired), then scales so real captures still dominate.
  7. 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.
Weaknesses: on crowded midgame boards the time budget often only finishes a
shallow depth, so long surround races can look "shape-random" against a calm
territorial player; heavier CPU use than Bender or Dumbo.


=== 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.

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)
