Worked scenario

The route that becomes worse when it is chosen

A dispatcher must send one high-value parcel through the north or south corridor. Historical incident data favour the north route. Its average travel time is lower and, on yesterday's frequencies, its expected loss is smaller. The dispatcher chooses north every morning.

Now add one fact. A watcher sees the dispatcher's policy before placing a scanner. The physical corridors have not changed. The parcel, vehicle and objective have not changed. Only the source of uncertainty has changed: the scanner's location is no longer drawn from a fixed distribution. It is selected by another decision-maker whose reward increases when the parcel is intercepted.

This small alteration reverses the logic of optimisation. Against weather, component failure or an honest randomiser, the dispatcher can average over probabilities. Against a watcher who adapts, yesterday's frequency is partly a record of yesterday's policies. A route's value now depends on the response it invites. The north route can be best under a passive distribution and worst under an active best response.

Dispatcher payoff per trip, synthetic units
Dispatcher actionWatcher covers northWatcher covers southWorst credible response
Route north-30+10-30
Route south+7-12-12

If scanner placement were exogenous and north were covered only 20 per cent of the time, routing north would have expected value +2, while routing south would have expected value -8.2. But a responsive watcher covers north whenever north is announced. The pure minimax decision is therefore south because -12 is better than -30. That answer is safer, yet it still leaks a regularity. If the dispatcher always chooses south, the watcher moves south.

The stronger answer is a mixed policy. Let p be the probability of choosing north. The dispatcher selects p so that neither scanner location gives the watcher a better way to reduce the dispatcher's payoff. For this matrix, p is 19/59, about 0.322. The watcher mixes as well. Neither side can improve by unilaterally changing its policy.

The core answer is that strategic search evaluates policies through responses, not states alone. In perfect-information, two-player, zero-sum games this leads naturally to minimax. Efficient search can preserve the same answer through alpha-beta pruning. Under hidden information, the tree must include information sets and beliefs. When the opponent itself is learned, a second control problem appears: how much robustness may be exchanged for exploitation?

That is the burden of this paper. It does not claim that every disagreement is a zero-sum game, that every person is an adversary, or that minimax is a universal decision rule. It asks a narrower question: what must change in a machine's reasoning when part of its environment is another chooser who can observe, conceal, learn and respond?

Part one

A response changes the objective

Ordinary optimisation often begins with a set of actions, a distribution over states and a utility function. The agent chooses the action with the highest expected utility. That is appropriate when the state distribution is not strategically changed by revealing or repeating the action. A storm does not usually move because a controller has favoured one flight path. A bearing does not become more likely to fail because the maintenance model predicts it will survive.

a* = arg maxa E[U(a, S)]

a is an available action, S is an uncertain state and U is the agent's utility. Changing the probability of a state changes the average, but the state does not choose in response to a.

Adversarial search replaces that exogenous state with another policy. In its cleanest form, player A chooses an action, player B chooses a response, and A's gain is B's loss. A robust action maximises the value remaining after B selects the most damaging legal response.

a* = arg maxa minb U(a, b)

b is the opponent's response. The inner minimum is not pessimism about every imaginable event. It is a claim about the strongest response available to a particular opponent under a specified game.

Minimax is only as sensible as the game boundary that makes the minimum credible. If the opponent cannot observe the action, cannot reach a branch, values a different outcome, or pays a prohibitive cost to respond, treating every legal response as equally credible can be wastefully conservative. Conversely, replacing a strategic response with a historical frequency can be dangerously optimistic.

Thought experiment 1: the same scanner, one changed cause

Run the parcel case twice. In world A, a faulty scheduler places the scanner north with probability 0.2 and south with probability 0.8. In world B, a watcher uses exactly those frequencies during a calibration week but receives the dispatcher's policy before the next week begins. Every observed number is initially the same. Only the causal mechanism differs.

An expected-value agent treats the worlds as equivalent. It chooses north in both. A strategic agent asks whether the distribution is policy-dependent. In world A, repeated north routing does not alter tomorrow's scanner probability. In world B, repetition supplies information to the watcher and changes tomorrow's response. The right distinction is therefore not “random versus deterministic”. It is exogenous uncertainty versus endogenous response.

Search is a proof about alternatives

A finite perfect-information game can be represented as a tree. Nodes specify whose turn it is, edges are legal actions and leaves carry payoffs. A maximising node selects the largest child value; a minimising node selects the smallest. Propagating these values backwards produces a minimax value at the root. Claude Shannon's early chess programme already framed machine play as selective look-ahead over legal continuations rather than a direct score for the present board.[1]

The phrase “search deeper” can hide an important distinction. A deeper tree is useful only if the evaluation and transition model remain meaningful. A wrong terminal utility, missing legal response or distorted state can be propagated with perfect computational discipline. Search does not repair a mis-specified game; it amplifies its assumptions.

Alpha-beta pruning improves efficiency without changing the minimax answer. While traversing a tree, the algorithm records the best value already available to the maximiser, alpha, and the best upper bound still available to the minimiser, beta. When beta is no greater than alpha, the remaining children cannot alter an ancestor's choice. Knuth and Moore analysed how move ordering governs the amount of pruning.[2]

A pruned branch is not judged uninteresting; it is proved decision-irrelevant under the current bounds. This is why alpha-beta is a valuable conceptual model for efficient reasoning. It spends computation on distinctions that can still change the decision. It does not merely sample fewer branches and hope.

Alpha-beta pruning removes a branch without changing the root value A maximising root compares three minimising children. After the first child establishes alpha equal to three, a second child with an upper bound of two is pruned. The third child yields four, which becomes the root value. A bound can make an unseen branch irrelevant MAX root value = 4 MINMINMIN 352946 beta = 2 ≤ alpha = 3 pruned MIN returns 3MIN returns 4
Mechanism cutawayFigure 2. Alpha-beta pruning preserves the answer. Values are illustrative leaf utilities. Once the second MIN node exposes a child worth 2, its remaining child cannot make that branch beat the root's existing option worth 3. The crossed branch is eliminated by a bound, not by an approximate relevance score.

Why a pure minimax move can still advertise itself

The parcel matrix has no pure saddle point. South has the better worst case, but always choosing south lets the watcher always cover south. Mixed strategies resolve this by choosing a distribution over actions. The dispatcher seeks a distribution p whose expected value remains as high as possible under the watcher's best response.

p* = arg maxp minb E[U(p, b)]

p is a probability distribution over the dispatcher's actions. Increasing randomness is not inherently intelligent; the useful distribution is the one that makes profitable prediction harder without surrendering unnecessary value.

For the synthetic matrix, indifference gives 7 - 37p = 22p - 12, so p = 19/59. The watcher covers north with probability 22/59. The game value is -290/59, about -4.92. Randomising 50:50 would be less carefully justified. Randomising according to yesterday's route frequency would confuse description with strategy.

The durable intuition is that a strategy can be valuable partly because it withholds predictability. This does not mean opacity is always desirable. In governed systems, actions still require traceability, authority and evidence. What may need to remain mixed is the selection among equally authorised actions, not the identity of the actor or the record of what occurred.

A route can lead under passive uncertainty and lose under strategic response Two panels compare expected route values when scanner location is fixed by chance and worst-case route values when a watcher responds. North changes from the better choice to the worse choice. One causal change reverses the ranking Passive scanner distribution Responsive watcher north covered with fixed probability 0.2 watcher selects the most damaging cover +2.0-8.2 northsouth -30-12 northsouth Vertical direction indicates dispatcher payoff in synthetic units. Baselines differ only to keep labels legible; compare values, not bar lengths across panels.
Controlled comparisonFigure 3. The same action table supports two different decisions. Numbers are calculated from the synthetic route matrix. Under a fixed 0.2 scanner probability, north has higher expected value. Under a best response, south has the higher floor. The intervention is the scanner's causal status, not its observed frequency.
Part two

Hidden information changes the state

Minimax on a visible tree assumes that the player knows which node it occupies when choosing. Chess has an enormous tree, but both players see the same board. Poker is smaller in some local descriptions yet conceptually harder because each player sees a different slice of the state. A search procedure that gives the agent access to the opponent's private card can produce excellent play in the wrong game.

Harold Kuhn's extensive-form treatment made information patterns explicit by grouping decision nodes a player cannot distinguish into an information set.[3] A strategy must prescribe the same action distribution at every node in that set because the player does not know which node is real. The hidden state is not merely missing input awaiting retrieval. It may be unavailable by design.

Under imperfect information, the unit of choice is an information set, not a fully observed node. The agent needs a belief over compatible histories, but that belief is shaped by earlier actions. A bet is both an action that changes the pot and a signal that changes the opponent's posterior. Strategic action and information production become coupled.

Thought experiment 2: reveal one card

Consider a three-card poker game with Jack, Queen and King. Each player receives one card. There is one betting round. In version A, both cards are face up. In version B, each player sees only their own card. Rules, payoffs, action order and card frequencies are identical. Only visibility changes.

In version A, a player with the higher card can value-bet and a player with the lower card can fold. Bluffing has no function because the opponent knows the relevant state. Standard minimax search over visible nodes is sufficient. In version B, a bet with the Jack may be useful precisely because the opponent cannot tell whether the bettor holds Jack or King. A policy that never bluffs makes its value bets easy to identify. A policy that bluffs too often makes calling profitable.

The causal feature varied is private information. Nothing “more intelligent” was added to the player. Yet the adequate strategy space changes from actions at visible states to probability distributions at information sets. A search algorithm that ignores that change can illegally condition on hidden facts or fail to represent deception at all.

Information sets bind hidden nodes into one legal decision A player holding a Queen can be at one of two hidden nodes depending on whether the opponent holds a Jack or King. The nodes are enclosed by a dashed information-set lens, so the same action distribution must be used at both. The player sees one decision, although the game contains two nodes Your private card: Queen opponent's card remains hidden QQ world node: opponent has Jworld node: opponent has K one information set passbetpassbet The strategy cannot select a different distribution using the hidden card.
Information geometryFigure 4. An information set is a legal constraint on conditioning. The card identities are illustrative. The player holding Queen cannot distinguish the two world nodes, so both must share one behaviour strategy. A model that acts differently has used information the player does not possess.

Counterfactual regret turns hidden alternatives into a learning signal

Counterfactual regret minimisation, or CFR, repeatedly traverses an extensive-form game and asks how much better each action would have been at an information set, weighted by the probability that other players and chance would reach it. Positive cumulative regret increases the future probability of an action. Averaging the strategies across iterations converges towards a Nash equilibrium in finite two-player zero-sum games under the method's conditions. Zinkevich et al. introduced counterfactual regret and demonstrated the approach on large poker abstractions.[4]

The word “counterfactual” matters. A rarely reached information set still needs a learning signal. CFR separates the player's own contribution to reaching that set from the reach probability contributed by chance and the opponent. It can therefore ask, in effect: had this information set been reached by the rest of the world, which local action would have reduced regret?

RT(I, a) = Σt=1..T π-it(I) [vt(I, a) - vt(I)]

I is an information set, a an action, π-i the reach contribution of chance and the other player, and v the counterfactual value. Larger positive regret makes action a more likely under regret matching.

This is not a claim that regret is a psychological feeling or that the machine experiences missed opportunities. It is an accounting device over alternative policies. The distinction matters because fluent anthropomorphic descriptions can obscure the exact signal being optimised.

Modern systems scale beyond tabular CFR through abstraction, value approximation, depth-limited solving, continual re-solving and self-play. DeepStack combined continual re-solving, learned value estimates and a restricted look-ahead to achieve expert-level heads-up no-limit poker results.[5] Libratus used blueprint strategies and nested subgame solving;[6][13] Pluribus extended superhuman results to six-player no-limit poker, where the clean two-player zero-sum guarantees no longer transfer unchanged.[7] DeepNash addressed Stratego through regularised self-play in a vast imperfect-information game,[8] while Student of Games combined search, learning and game-theoretic reasoning across both perfect and imperfect-information games.[9]

Published evidence

These results show that strategic reasoning can be engineered at large scale in specified games. They do not establish a single universal algorithm for negotiation, markets, cyber defence or social interaction. Each result inherits the rules, observability, payoff definition and evaluation protocol of its game.

The negative control: difficult uncertainty without an opponent

Imagine the same route network under volatile weather, delayed telemetry and uncertain bridge capacity. The state is partially observed and sequential. The dispatcher may need Bayesian filtering, a partially observable Markov decision process, robust control or information gathering. Yet weather does not improve its policy after studying the dispatcher's routes.

This is a serious negative control because it can make adversarial machinery look useful when ordinary uncertainty modelling is enough. Minimax against an imaginary hostile weather process may produce a route that sacrifices too much expected value. Opponent modelling may “discover” patterns in noise. Bluffing may simply hide useful information from collaborators.

Hard, uncertain and sequential does not imply strategic. Evidence for an opponent requires policy-dependent response: the other process must select actions in a way that depends on its objectives, information and beliefs about the agent. Without that dependence, expected utility, robust optimisation or POMDP methods may be the better fit.

A decision map separates chance, hidden state and strategic response A two-axis map places methods according to whether uncertainty is policy-dependent and whether the state is publicly observable. Expected value and POMDP methods occupy non-strategic regions, while minimax and information-set equilibrium methods occupy strategic regions. Choose the uncertainty model before the solver response dependence on your policy → state hidden from the chooser → Visible, exogenousexpected utilitydynamic programmingrobust control Visible, strategicminimaxalpha-betamixed equilibrium Hidden, exogenousBayesian filteringPOMDP planninginformation gathering Hidden, strategicinformation setsCFR / equilibrium solvingsafe opponent modelling ? mixed cases require an explicit decomposition, not one blended “uncertainty” score
Negative-control mapFigure 5. Strategic methods occupy only part of the uncertainty landscape. The placement is a design inference, not a measured taxonomy. The decision use is diagnostic: first ask whether another chooser changes its policy in response to yours, then ask what each chooser can observe.
Part three

Adaptation creates a second risk

An equilibrium strategy in a two-player zero-sum game protects the game value: a fully informed opponent cannot gain by unilaterally deviating. That robustness can look unsatisfying against a weak opponent. A poker player who folds far too often creates an opportunity to bet more aggressively. A defender who repeats a response creates a route around it. A pricing agent with a stable bias can be anticipated.

The tempting design is simple: estimate the opponent's policy, compute a best response and deploy it. The first problem is statistical. The observed sample may be small, censored or confounded by the agent's own previous strategy. The second is strategic. Once the agent changes its policy, the opponent may notice and adapt. The third is operational. A best response to the wrong model can be highly exploitable.

Opponent modelling trades model error for additional reward. The relevant question is not whether the model predicts the past. It is whether the predicted deviation persists under the new policy, and whether the resulting vulnerability remains acceptable if it does not.

Research on restricted Nash responses and safe opponent exploitation makes this trade explicit. A strategy can move towards a best response while retaining a lower bound against other opponents. Ganzfried and Sandholm characterised safe exploitation in normal-form and sequential games;[10] later work continues to study exploitation under uncertain or untrusted beliefs.[11] The general lesson is broader than any one algorithm: exploitation needs a budget and a fallback.

A decision rule, not a theorem

For an operating system, the following inequality is a useful release gate:

P(persistence | evidence) × Gexploit > Lvulnerability + Cchange

P is the assessed probability that the opponent's deviation persists, Gexploit the incremental gain if it does, Lvulnerability the expected loss created by moving away from the robust policy, and Cchange the cost of validation, release, monitoring and rollback.

This is design inference, not a proved game-theoretic identity. Its purpose is to force four quantities into the same decision. A large apparent gain is insufficient if it rests on fragile persistence. A low exploitability estimate is insufficient if the estimate uses the same mistaken opponent model. A cheap policy change is not cheap if outcome detection is delayed.

The safe baseline should be evaluated independently of the exploitation model. In a small game, exact best responses can measure exploitability. In a large game, one may use lower bounds, adversarial populations, holdout opponents, policy-space response oracles, red-team strategies and uncertainty intervals. The metric must be tied to the game boundary. “Win rate increased” does not reveal whether the deployed strategy became catastrophically vulnerable to one reachable response.

The exploitation gain rises with a vulnerability budget, but the worst-case loss rises too An illustrative chart shows expected gain against a modelled weak opponent saturating as deviation from equilibrium increases, while worst-case loss rises. A bounded release zone lies where evidence-adjusted gain exceeds vulnerability and change cost. Exploitation is a controlled departure from a robust policy allowed deviation from robust strategy → value or loss → illustrative release limitgain clears evidence-adjusted cost gain against modelled opponent worst-case vulnerability equilibriumbest response
Illustrative relationshipFigure 6. More exploitation usually buys more model dependence. Curves are illustrative, not empirical. The robust equilibrium sits at the left. Moving right can increase reward against the modelled opponent, but it also opens responses that the baseline protected against. The correct release point depends on evidence, consequence and recovery cost.

Why “the opponent will adapt” is not enough

It is easy to invoke adaptation so broadly that no model can be trusted. That is not useful. Some opponents are constrained by slow processes, limited observability, regulation, physical costs or fixed software. Their deviations may persist long enough to justify bounded exploitation. Other opponents may adapt within one interaction. The time constant belongs in the model.

Three clocks matter. The observation clock determines how quickly the agent obtains reliable evidence of a deviation. The opponent clock determines how quickly the other policy changes after the agent responds. The release clock determines how quickly a new policy can be validated, deployed and withdrawn. Exploitation is most promising when observation is faster than opponent adaptation and rollback is faster than harmful accumulation.

An opponent may also manipulate the evidence. It can deliberately play weakly to induce an exploitable best response, then switch. In security language this resembles a baiting attack; in games it is a change of strategy across phases. A policy trained on pooled history can miss the switch because its average model remains accurate while its current model is wrong.

Explicit failure boundary

The mechanism in this paper breaks when the game cannot be bounded well enough to define players, legal actions, information, utilities and recovery. It also ceases to help when utilities are non-zero-sum but are forced into a single adversarial score, when multiple parties can collude, or when the opponent changes faster than evidence and rollback can track.

A failure surface maps model completeness against opponent adaptation speed A contour map has model completeness on the horizontal axis and opponent adaptation speed on the vertical axis. Robust search occupies the lower right, bounded exploitation the lower middle, monitoring-only the upper middle, and model refusal the upper left. Fast adaptation and weak game models defeat exploitation first completeness of game and evidence model → opponent adaptation speed → refuse strategic claimplayers, payoffs or observability are too vague monitor, do not exploitopponent can switch before recovery bounded exploitationindependent validation and rollback robust search / equilibrium baseline
Failure surfaceFigure 7. Opponent modelling has a narrower safe region than robust search. The regions are a design inference. As adaptation becomes faster or the game model becomes less complete, the system should first withdraw exploitation, then withdraw the strategic claim itself. A credible refusal is better than a precise solution to an invented game.
Part four

Build a bounded strategic agent

A game-playing model is not yet an operating agent. To act safely, the system must bind the proposed move to identity, current world state, legal authority, evidence and outcome verification. This matters even in a synthetic game because it exposes which responsibilities belong to search and which must remain deterministic.

Consider a production-shaped but synthetic setting: a fraud-testing service schedules decoy transactions across two monitored channels to estimate which attack policy is active. The attacker can observe aggregate patterns but not each decoy's identity. A model proposes the next channel and amount band. A deterministic authority kernel checks the campaign purpose, stake ceiling, jurisdiction, channel availability and duplicate identifier. After execution, a readback confirms whether the decoy was accepted exactly once. The outcome observer records the attack response without promoting it directly into a permanent opponent model.

The strategic solver owns a narrow question: which authorised experimental action best distinguishes or responds to the current opponent hypotheses? It does not own permission to create transactions, alter customer records or expand the campaign. Search proposes within a game; authority determines whether the game may touch the world.

A bounded strategic agent separates proposal, authority, evidence and recovery Ten horizontal layers show intent, identity, world state, context, reasoning, authority, action, evidence, outcome and release or recovery. A stochastic proposal passes through a deterministic authority membrane before action. The stochastic move is one layer in a governed action 1 Intent2 Identity3 World state4 Context5 Reasoning6 Authority7 Action8 Evidence9 Outcome10 Release and recovery bounded campaign objective and utilityrequester, session and accountable operatorauthoritative public state, legal actions and versionprivate observation, beliefs and evidence freshnessminimax, CFR or bounded opponent response proposaltyped action contract, permission, stake and expiry checksone idempotent effect through an approved interfacepolicy version, model fit, Nash gap and decision receipteffect receipt, readback and verified payoff signalrevert to robust baseline, quarantine evidence, compensate proposal crosses authority membrane readback can trigger reconstruction
System boundaryFigure 8. A strategic solver does not confer authority. The architecture is a design inference. Probabilistic reasoning occupies one layer. Identity, legal actions, typed effects, evidence and recovery remain explicit. The decision use is to prevent “the game agent chose it” becoming an authorisation claim.

What the agent must record

A defensible strategic action needs more than a move and a score. The decision receipt should contain the game specification and version, public state, information set, belief source, candidate actions, selected policy, random seed when sampling, robust baseline, opponent-model version, expected gain, exploitability estimate, authority decision and expiry. The effect receipt records what the external system accepted. Readback records the resulting world state.

These are different ledgers. Workflow state says what step is active. Episodic memory records prior interactions. Enterprise knowledge contains reusable facts and rules. World state describes the current authoritative situation. Evidence ledgers preserve why a claim or action was justified. Calling all five “memory” makes it difficult to decide what may be updated by a model and what requires independent verification.

The opponent model should begin as evidence, not truth. Observations need provenance, sampling context and effective time. A change-point detector or rolling window can flag that recent behaviour no longer fits the promoted model. That flag should reduce the exploitation budget or return the policy to its robust baseline. It should not ask the same model that proposed exploitation to reassure itself that the opponent remains weak.

Production-shaped worked example

Suppose the decoy service has two legal actions: place a low-value decoy in channel A or B. A red-team simulator has three attack policies: concentrate on A, concentrate on B or probe both. The service first computes a robust mixed policy across the supported attack population. After 400 independently labelled observations, it detects a persistent over-concentration on A. A candidate response shifts more decoys to B, where they are less likely to be noticed and may reveal lateral movement.

The candidate is evaluated against four sets: the fitted attacker, a holdout period, the original attack population and a switch attacker that behaves weakly for 200 rounds before changing. It improves detection against the fitted and holdout policies, but its worst-case loss against the switch attacker exceeds the campaign's tolerance. The authority kernel therefore permits only a capped shift for 50 actions, attaches an expiry and requires readback after every action. When recent evidence crosses the change threshold, the orchestrator restores the robust mixture.

This is bounded autonomy. The model proposes a response; deterministic controls constrain stake and duration; independent evaluation estimates vulnerability; operating evidence determines whether the assumption still holds; recovery is designed before release. The example is synthetic. It demonstrates the architecture, not a claim about a deployed fraud control.

Decision instrument

The strategic adequacy audit

Run these questions in order. A “no” does not mean the system is simple. It means a different uncertainty or control mechanism should carry the decision.

  1. 1. Is there another chooser?
    Identify the actor, objective, legal actions and response costs. Do not infer an adversary from volatility alone.
  2. 2. Is response policy-dependent?
    State what the other chooser observes and how your repeated or disclosed policy can change its action distribution.
  3. 3. What can each player know?
    Separate public state, private observations, beliefs and facts unavailable to the acting player. Define information sets.
  4. 4. What game class is justified?
    Perfect or imperfect information; zero-sum or general-sum; sequential or simultaneous; fixed or changing rules; two players or many.
  5. 5. What is the robust baseline?
    Measure best-response value, Nash gap or an appropriate adversarial lower bound before adding an opponent model.
  6. 6. Is exploitation evidence strong enough?
    Estimate persistence, incremental gain, vulnerability, validation cost, observation lag and rollback time.
  7. 7. Who authorises the effect?
    Bind identity, purpose, permissions, legal actions, stake limits, freshness, idempotency and expiry outside the stochastic solver.
  8. 8. How will the assumption be withdrawn?
    Define model-fit sentinels, readback, a robust fallback, quarantine rules and the exact trigger for rollback.
The strategic adequacy audit routes a problem to an appropriate method A branching decision path asks whether there is a chooser, whether response depends on the agent's policy, whether information is hidden, and whether opponent deviation is evidenced. It routes to expected utility, minimax, information-set equilibrium or bounded exploitation. Route the problem before optimising the policy Another chooser with a defined objective?actor, actions, payoffs, response costs no yes Exogenous uncertaintyexpected utility, robust control, POMDP Can each player observe the true node?legal conditioning, not model access yes no Perfect-information gameminimax, alpha-beta, mixed strategy Imperfect-information gameinformation sets, CFR, subgame solving Persistent deviation with a vulnerability budget?only then add bounded opponent exploitation
Decision pathFigure 9. The solver is downstream of the game classification. This figure condenses the strategic adequacy audit. It is a practitioner decision instrument. The important refusal path is on the left: difficult uncertainty without a chooser should not be forced into adversarial search.
Executable artefact

A game agent that exposes its own vulnerability

The following Python programme implements tabular CFR for Kuhn poker using only the standard library. It trains an average strategy, calculates exact expected utility across all six card deals and enumerates all 64 pure behaviour policies per player to obtain exact best responses. That enumeration produces a Nash gap, the amount by which unilateral best responses can improve across the profile.

The positive case creates a synthetic player 1 who folds too often to an opening bet. A best response exploits that stable weakness. The negative case then replaces the weak opponent with the learned robust strategy. The exploitative policy loses more and exposes a much larger Nash gap. The artefact measures the benefit and the liability of adaptation in the same units.

Assumptions are deliberately narrow: finite two-player zero-sum Kuhn poker, perfect recall, exact game rules, stationary training environment and no external side effects. Expected output can vary slightly with iteration count, but the theoretical first-player value is -1/18 ante.

Runnable Python: CFR, exact best responses, positive and negative cases
kuhn_cfr_game_agent.pyPython 3.10+ · standard library only
from __future__ import annotations

from dataclasses import dataclass, field
from itertools import permutations, product
from typing import Dict, Iterable, Mapping, Sequence, Tuple

PASS, BET = 0, 1
ACTIONS = (PASS, BET)
CARDS = (0, 1, 2)  # J, Q, K
CARD_NAME = {0: "J", 1: "Q", 2: "K"}
TERMINALS = {"pp", "bp", "bb", "pbp", "pbb"}


@dataclass
class Node:
    regret_sum: list[float] = field(default_factory=lambda: [0.0, 0.0])
    strategy_sum: list[float] = field(default_factory=lambda: [0.0, 0.0])

    def strategy(self, reach_weight: float) -> tuple[float, float]:
        positive = [max(r, 0.0) for r in self.regret_sum]
        total = sum(positive)
        current = [x / total for x in positive] if total > 0 else [0.5, 0.5]
        for action in ACTIONS:
            self.strategy_sum[action] += reach_weight * current[action]
        return current[0], current[1]

    def average_strategy(self) -> tuple[float, float]:
        total = sum(self.strategy_sum)
        if total == 0:
            return 0.5, 0.5
        return self.strategy_sum[0] / total, self.strategy_sum[1] / total


Policy = Dict[str, tuple[float, float]]


def terminal_utility_p0(cards: Sequence[int], history: str) -> float:
    """Return player 0's net payoff, measured in antes."""
    if history not in TERMINALS:
        raise ValueError(f"Non-terminal history: {history}")
    if history == "bp":       # P0 bet, P1 folded
        return 1.0
    if history == "pbp":      # P1 bet, P0 folded
        return -1.0
    winner_is_p0 = cards[0] > cards[1]
    stake = 1.0 if history == "pp" else 2.0
    return stake if winner_is_p0 else -stake


def info_key(card: int, history: str) -> str:
    return f"{CARD_NAME[card]}:{history or 'root'}"


def cfr(
    cards: Sequence[int],
    history: str,
    reach0: float,
    reach1: float,
    nodes: Dict[str, Node],
) -> float:
    if history in TERMINALS:
        return terminal_utility_p0(cards, history)

    player = len(history) % 2
    key = info_key(cards[player], history)
    node = nodes.setdefault(key, Node())
    own_reach = reach0 if player == 0 else reach1
    strategy = node.strategy(own_reach)

    action_utility: list[float] = [0.0, 0.0]
    for action in ACTIONS:
        next_history = history + ("p" if action == PASS else "b")
        if player == 0:
            action_utility[action] = cfr(
                cards, next_history, reach0 * strategy[action], reach1, nodes
            )
        else:
            action_utility[action] = cfr(
                cards, next_history, reach0, reach1 * strategy[action], nodes
            )

    node_utility = sum(strategy[a] * action_utility[a] for a in ACTIONS)
    opponent_reach = reach1 if player == 0 else reach0
    for action in ACTIONS:
        # P0 maximises u0; P1 maximises -u0.
        regret = (
            action_utility[action] - node_utility
            if player == 0
            else node_utility - action_utility[action]
        )
        node.regret_sum[action] += opponent_reach * regret
    return node_utility


def train(iterations: int = 100_000) -> Policy:
    nodes: Dict[str, Node] = {}
    deals = list(permutations(CARDS, 2))
    for _ in range(iterations):
        for cards in deals:
            cfr(cards, "", 1.0, 1.0, nodes)
    return {key: node.average_strategy() for key, node in sorted(nodes.items())}


def action_probability(policy: Mapping[str, tuple[float, float]], key: str) -> tuple[float, float]:
    return policy.get(key, (0.5, 0.5))


def expected_utility_for_deal(
    cards: Sequence[int], history: str, policy0: Mapping[str, tuple[float, float]],
    policy1: Mapping[str, tuple[float, float]],
) -> float:
    if history in TERMINALS:
        return terminal_utility_p0(cards, history)
    player = len(history) % 2
    key = info_key(cards[player], history)
    strategy = action_probability(policy0 if player == 0 else policy1, key)
    return sum(
        strategy[action]
        * expected_utility_for_deal(
            cards,
            history + ("p" if action == PASS else "b"),
            policy0,
            policy1,
        )
        for action in ACTIONS
    )


def expected_utility(policy0: Mapping[str, tuple[float, float]], policy1: Mapping[str, tuple[float, float]]) -> float:
    deals = list(permutations(CARDS, 2))
    return sum(expected_utility_for_deal(cards, "", policy0, policy1) for cards in deals) / len(deals)


def player_info_sets(player: int) -> list[str]:
    histories = ("", "pb") if player == 0 else ("p", "b")
    return [info_key(card, history) for card in CARDS for history in histories]


def pure_policies(player: int) -> Iterable[Policy]:
    keys = player_info_sets(player)
    for action_choices in product(ACTIONS, repeat=len(keys)):
        yield {
            key: (1.0, 0.0) if action == PASS else (0.0, 1.0)
            for key, action in zip(keys, action_choices)
        }


def best_response_value(
    responding_player: int,
    opponent_policy: Mapping[str, tuple[float, float]],
) -> tuple[float, Policy]:
    candidates = []
    for candidate in pure_policies(responding_player):
        u0 = (
            expected_utility(candidate, opponent_policy)
            if responding_player == 0
            else expected_utility(opponent_policy, candidate)
        )
        objective = u0 if responding_player == 0 else -u0
        candidates.append((objective, u0, candidate))
    _, u0, policy = max(candidates, key=lambda item: item[0])
    return u0, policy


def nash_gap(policy0: Mapping[str, tuple[float, float]], policy1: Mapping[str, tuple[float, float]]) -> float:
    br0_u0, _ = best_response_value(0, policy1)
    br1_u0, _ = best_response_value(1, policy0)
    return br0_u0 - br1_u0


def split_policy(profile: Mapping[str, tuple[float, float]]) -> tuple[Policy, Policy]:
    p0_histories = {"root", "pb"}
    p0, p1 = {}, {}
    for key, strategy in profile.items():
        history = key.split(":", 1)[1]
        (p0 if history in p0_histories else p1)[key] = strategy
    return p0, p1


def biased_player1() -> Policy:
    """Synthetic opponent: sensible after a check, but folds too often to an opening bet."""
    policy: Policy = {}
    for card in CARDS:
        # After P0 checks: bluff J sometimes, value-bet K, mix Q.
        after_check = {
            0: (0.75, 0.25),
            1: (0.55, 0.45),
            2: (0.10, 0.90),
        }[card]
        # After P0 bets: excessive folding, including with K.
        versus_bet = {
            0: (0.98, 0.02),
            1: (0.90, 0.10),
            2: (0.70, 0.30),
        }[card]
        policy[info_key(card, "p")] = after_check
        policy[info_key(card, "b")] = versus_bet
    return policy


def print_policy(policy: Mapping[str, tuple[float, float]]) -> None:
    for key in sorted(policy):
        p_pass, p_bet = policy[key]
        print(f"  {key:7s}  pass/fold={p_pass:6.3f}  bet/call={p_bet:6.3f}")


def main() -> None:
    profile = train(100_000)
    equilibrium_p0, equilibrium_p1 = split_policy(profile)
    value = expected_utility(equilibrium_p0, equilibrium_p1)
    gap = nash_gap(equilibrium_p0, equilibrium_p1)

    weak_p1 = biased_player1()
    weak_value_with_equilibrium = expected_utility(equilibrium_p0, weak_p1)
    _, exploitative_p0 = best_response_value(0, weak_p1)
    exploit_value_weak = expected_utility(exploitative_p0, weak_p1)
    exploit_value_robust = expected_utility(exploitative_p0, equilibrium_p1)
    equilibrium_value_robust = expected_utility(equilibrium_p0, equilibrium_p1)

    print("CFR average strategy")
    print_policy(profile)
    print(f"\nSelf-play value to P0: {value:+.5f} antes (theory: {-1/18:+.5f})")
    print(f"Nash gap:             {gap:.5f} antes")
    print("\nPositive case: persistent over-folding opponent")
    print(f"Equilibrium P0 value: {weak_value_with_equilibrium:+.5f}")
    print(f"Best-response value:  {exploit_value_weak:+.5f}")
    print("\nNegative case: opponent reverts to robust play")
    print(f"Equilibrium P0 value: {equilibrium_value_robust:+.5f}")
    print(f"Exploitative P0 value:{exploit_value_robust:+.5f}")
    print(f"Exploitative policy Nash gap vs robust P1: {nash_gap(exploitative_p0, equilibrium_p1):.5f}")


if __name__ == "__main__":
    main()
Self-play value to P0: -0.05555 antes (theory: -0.05556) Nash gap: 0.00127 antes Positive case: persistent over-folding opponent Equilibrium P0 value: +0.05804 Best-response value: +0.77000 Negative case: opponent reverts to robust play Equilibrium P0 value: -0.05555 Exploitative P0 value:-0.11263 Exploitative policy Nash gap vs robust P1: 0.44539
The included game agent gains against a weak opponent and loses robustness Measured bars from the included Kuhn poker programme show the equilibrium policy earning 0.058 against a weak player and the best response earning 0.770. Against a robust player, equilibrium earns negative 0.056 while the exploitative policy earns negative 0.113. Its Nash gap is 0.445. A large exploit gain can conceal a larger robustness debt Against synthetic over-folderAgainst learned robust player +0.058+0.770 equilibriumbest response -0.056-0.113 equilibriumexploitative exploitative policy Nash gap: 0.445 Utilities are measured by the included programme in net antes per hand after 100,000 CFR iterations.
Measured synthetic resultFigure 10. The best response wins the positive case and fails the negative case. Values are reproduced by the included Python programme over all six Kuhn poker deals. The high reward against the over-folder is real within the synthetic game. So is the exploitability created when the opponent changes.

How to evaluate beyond the toy game

First, keep a matched non-strategic baseline. If a robust optimiser or simple randomised policy performs as well, the opponent model has not earned its complexity. Second, evaluate against populations rather than a single training opponent. Non-transitive strategy cycles can make self-play progress look monotonic when it is merely rotating. Third, separate model fit from policy value. A model can predict common actions accurately while missing the rare response that dominates worst-case loss.

Fourth, run switch tests. Hold the opponent fixed, then change it after exploitation begins. Vary the observation delay and rollback delay independently. Fifth, test illegal information leakage by giving the evaluator access to private state and checking whether the agent's behaviour changes when that access is removed. Sixth, replay the decision from the evidence available at the time, not from facts learned after the outcome.

OpenSpiel provides a broad research framework containing perfect and imperfect-information games, search and reinforcement-learning algorithms, and analysis metrics.[12] It is a useful next environment after the self-contained artefact, especially for matched comparisons across game classes. A framework, however, does not supply the user's real game boundary, authority model or consequence tolerance. Those remain design decisions.

Open hypothesis

For compound AI systems operating against adaptive misuse, a release gate based jointly on independent exploitability estimates, opponent change detection and rollback latency should outperform gates based on average task reward alone. This prediction needs controlled testing across switch opponents and delayed outcome regimes.

Compact glossary

Best response
A policy that maximises a player's value against a specified opponent policy.
Exploitability
How much a suitable best response can gain because a strategy departs from equilibrium protection.
Information set
Decision nodes a player cannot distinguish with the information legally available at that moment.
Minimax
A rule that selects the policy with the best value under the opponent's strongest legal response.
Nash equilibrium
A strategy profile in which no player improves by changing policy alone.
Nash gap
The sum of unilateral best-response improvements; zero at an exact equilibrium in the relevant game.
Opponent model
An evidence-bounded estimate of another chooser's policy or type, not an authorisation source or permanent fact.
Conclusion

Choose the game before choosing the move

Solitary optimisation asks which action scores highest across uncertain states. Strategic intelligence begins one level later: which policy retains value after another chooser observes, conceals, selects and adapts? That shift creates three obligations. Responses must enter the objective. Information constraints must enter the state representation. Adaptation must enter the risk model.

The architecture decision is therefore upstream of the search algorithm. Establish whether uncertainty is exogenous or policy-dependent. Define what each player can observe. State whether the interaction is zero-sum, general-sum or partly cooperative. Name the robust baseline. Only then choose minimax, alpha-beta, information-set equilibrium methods or a bounded opponent response.

The research decision changes as well. A convincing strategic agent is not demonstrated by a high win rate against one opponent. It needs a negative control without an opponent, a best-response or exploitability measure, hidden-information tests, switch opponents, matched budgets and recovery evidence. A policy that wins more while becoming silently fragile has not completed the experiment.

The operating decision is the most concrete. Keep the model proposal separate from authority. Record the information set, belief evidence, baseline and vulnerability budget. Verify the effect and outcome. Withdraw exploitation when persistence fails. A strategic system earns autonomy by showing not only that it can anticipate a response, but also that it knows when its model of the responder has ceased to deserve action.

Source ledger

Open the source register and extended notes
  1. Primary Claude E. Shannon, “Programming a Computer for Playing Chess”, first published in Philosophical Magazine, 1950. Used for the early computational formulation of selective game-tree search.
  2. Primary Donald E. Knuth and Ronald W. Moore, “An Analysis of Alpha-Beta Pruning”, Artificial Intelligence, 1975. Used for the proof-preserving pruning mechanism and move-ordering boundary.
  3. Primary Harold W. Kuhn, “Extensive Games and the Problem of Information”, 1953. Used for extensive-form information patterns and information sets.
  4. Primary Martin Zinkevich, Michael Johanson, Michael Bowling and Carmelo Piccione, “Regret Minimization in Games with Incomplete Information”, NeurIPS 2007. Used for counterfactual regret and equilibrium convergence in self-play.
  5. Primary Matej Moravčík et al., “DeepStack: Expert-level Artificial Intelligence in Heads-Up No-Limit Poker”, Science, 2017. Used for continual re-solving with learned value estimates.
  6. Primary Noam Brown and Tuomas Sandholm, “Superhuman AI for Heads-Up No-Limit Poker: Libratus Beats Top Professionals”, Science, 2018. Used for blueprint and subgame-solving evidence.
  7. Primary Noam Brown and Tuomas Sandholm, “Superhuman AI for Multiplayer Poker”, Science, 2019. Used for the multiplayer boundary and empirical result.
  8. Primary Julien Perolat et al., “Mastering the Game of Stratego with Model-Free Multiagent Reinforcement Learning”, Science, 2022. Used for large imperfect-information self-play.
  9. Primary Martin Schmid et al., “Student of Games: A Unified Learning Algorithm for Both Perfect and Imperfect Information Games”, Science Advances, 2023. Used for the modern combination of search, learning and game-theoretic reasoning.
  10. Primary Sam Ganzfried and Tuomas Sandholm, “Safe Opponent Exploitation”, ACM Transactions on Economics and Computation, 2015. Used for the safety-exploitation trade-off.
  11. Primary Tongxin Li et al., “Safe Exploitative Play with Untrusted Type Beliefs”, NeurIPS 2024. Used as a recent limitation-aware treatment of uncertain opponent beliefs.
  12. Official implementation Marc Lanctot et al., “OpenSpiel: A Framework for Reinforcement Learning in Games”, with the official Google DeepMind repository. Used for implementation and evaluation pathways beyond the self-contained Kuhn poker artefact.
  13. Primary Noam Brown and Tuomas Sandholm, “Safe and Nested Subgame Solving for Imperfect-Information Games”, NeurIPS 2017. Used to check the boundary between perfect-information decomposition and imperfect-information subgames.
  14. Design inference The strategic adequacy audit, bounded adaptation inequality, authority cutaway, production-shaped decoy scenario and release controls are original synthesis in this article. They are proposals to test, not reported deployments.