OnnxExpectimaxSearch

dicechess.engine.search.OnnxExpectimaxSearch
See theOnnxExpectimaxSearch companion object
final class OnnxExpectimaxSearch extends TimeBudgetedSearch, AutoCloseable

A configurable two- or three-ply expectimax bot whose leaf evaluator is an externally-trained model (LightGBM, via ONNX).

ExpectimaxSearch supplies the lookahead and OnnxEvalSearch supplies the value function, evaluated in batches at leaf decision nodes. The default two-ply tree sees the opponent's reply; searchDepth = 3 also sees our next rolled reply and therefore resolves exchanges that otherwise end on the opponent's capture.

A positive-weight rootRescore wires a second ONNX session as ExpectimaxSearch's root rescorer — see RootRescoreModel. A zero-weight configuration is treated exactly like None, including session ownership.

preRankWithModel, when true, uses this bot's own already-loaded model (batched) to pre-rank root candidates instead of material — no second session, since the model already scoring the chance-node leaves is exactly the "opinion" candidate selection should defer to. See ExpectimaxSearch's preRank parameter for why: widening candidateLimit only compensates for a crude (material) pre-ranker; a sharper one attacks the actual bottleneck.

preRankModel wires a dedicated session for candidate ordering instead — see PreRankModel for why ranking and valuing are different jobs, and why its cost is bounded by the feature schema rather than by the candidate limit. It is an alternative to preRankWithModel, not a companion: configuring both is rejected.

chanceCollapse wires a model in place of the chance-node expansion itself — the layer that costs hundreds to thousands of leaf evaluations per candidate. It is a third, independent session, and with it searchDepth, the transposition table and Star pruning have nothing left to do at the root: see ChanceCollapse.

statsSink is forwarded to the underlying ExpectimaxSearch — one RootSearchStats per move, so a production host can log how many candidates its deadline really allowed (the difference between the configured limit and the width actually searched on slow hardware).

Owns its ONNX session(s) — the main model's, the rescorer's when configured with positive weight, and the chance-collapse model's when configured; call close when done. Not safe for concurrent calls, matching every other bot here.

Attributes

Companion
object
Source
OnnxExpectimaxSearch.scala
Graph
Supertypes
trait AutoCloseable
class Object
trait Matchable
class Any
Show all

Members list

Value members

Constructors

def this(modelPath: String, config: ExpectimaxConfig = ..., extractFeatures: (GameState, Color) => Array[Float] = ..., rootRescore: Option[RootRescoreModel] = ..., preRankWithModel: Boolean = ..., statsSink: RootSearchStats => Unit = ..., tt: Option[TranspositionTable] = ..., chanceCollapse: Option[CollapseModel] = ..., preRankModel: Option[PreRankModel] = ...)

The path-based constructor every host has used so far: the leaf model as a filesystem path, the hooks as options.

The path-based constructor every host has used so far: the leaf model as a filesystem path, the hooks as options.

A leaf loaded this way carries no manifest and so gets no graph check — see OnnxExpectimaxSearch.fromPackages for the entry point that has one.

Attributes

Source
OnnxExpectimaxSearch.scala

Concrete methods

override def close(): Unit

Attributes

Definition Classes
AutoCloseable
Source
OnnxExpectimaxSearch.scala
override def findBestMove(state: GameState): Option[ScoredSequence]

Finds and returns the best full-turn path according to this strategy.

Finds and returns the best full-turn path according to this strategy.

Value parameters

state

the current dicechess.engine.domain.GameState; state.activeColor identifies the side to move

Attributes

Returns

Some([[ScoredSequence]]) when at least one legal path exists; None when the player must pass

Definition Classes
Source
OnnxExpectimaxSearch.scala
override def findBestMove(state: GameState, random: Random): Option[ScoredSequence]

Finds the best full-turn path, drawing any randomness (e.g. tie-breaking among equally-valued turns) from the supplied random. Lets a caller make a whole game reproducible from one seed — most importantly the bot arena, which otherwise gets a fresh unseeded Random per move and so is non-deterministic.

Finds the best full-turn path, drawing any randomness (e.g. tie-breaking among equally-valued turns) from the supplied random. Lets a caller make a whole game reproducible from one seed — most importantly the bot arena, which otherwise gets a fresh unseeded Random per move and so is non-deterministic.

The default ignores random and delegates to the no-arg findBestMove; randomised strategies override it to route their tie-breaking through the given source.

Attributes

Definition Classes
Source
OnnxExpectimaxSearch.scala
override def findBestMove(state: GameState, deadlineNanos: Long, random: Random): Option[ScoredSequence]

Finds the best full-turn path, stopping at deadlineNanos (a java.lang.System.nanoTime value).

Finds the best full-turn path, stopping at deadlineNanos (a java.lang.System.nanoTime value).

Value parameters

deadlineNanos

a java.lang.System.nanoTime value; the search stops once it is reached

random

the random source for the (non-deterministic) search

state

the current dicechess.engine.domain.GameState; state.activeColor identifies the side to move

Attributes

Returns

Some([[ScoredSequence]]) when at least one legal path exists — even if the deadline elapses before the search completes — or None when the player must pass

Definition Classes
Source
OnnxExpectimaxSearch.scala

Inherited methods

protected def estimateWinProbability(state: GameState): Double

Estimates the winning probability in [0.0, 1.0] for the side to move. Convenience over winProbability for offer decisions, where the deciding side is the active colour; do not override it, override winProbability.

Estimates the winning probability in [0.0, 1.0] for the side to move. Convenience over winProbability for offer decisions, where the deciding side is the active colour; do not override it, override winProbability.

Attributes

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
def shouldAcceptDouble(state: GameState, currentStake: Int): Boolean

Determines whether the bot should accept (Take) or decline (Drop) a double from the opponent, taking the side to move as the responder. Kept for source and binary compatibility; it delegates to the three-argument overload.

Determines whether the bot should accept (Take) or decline (Drop) a double from the opponent, taking the side to move as the responder. Kept for source and binary compatibility; it delegates to the three-argument overload.

Value parameters

currentStake

the proposed double stake (e.g. 2, 4...)

state

current game state (dice pool is empty)

Attributes

Returns

true to accept the double (Take), false to resign the current stake (Drop)

Note

Perspective hazard: this overload evaluates the win probability of state.activeColor. In a double decision state, state.activeColor is the player who offered the double, NOT the responder, so a caller that feeds the delivered position here asks whether the offerer should take. Callers must prefer shouldAcceptDouble(state, currentStake, responder); strategies must override that overload, not this one.

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
def shouldAcceptDouble(state: GameState, currentStake: Int, responder: Color): Boolean

Determines whether the bot should accept (Take) or decline (Drop) a double from the opponent, evaluated from the perspective of responder.

Determines whether the bot should accept (Take) or decline (Drop) a double from the opponent, evaluated from the perspective of responder.

This is the single policy point for the take/drop decision: strategies that want their own threshold or estimator override this overload. The two-argument form below only delegates here, so a policy written against it is bypassed whenever a caller names the responder explicitly (which every caller holding a doubleDecision state must, see the hazard note there).

Value parameters

currentStake

the proposed double stake (e.g. 2, 4...)

responder

the colour of the player responding to the double offer

state

current game state (dice pool is empty); its active colour is the side to move, which in a double decision is the offerer, not the responder

Attributes

Returns

true to accept the double (Take), false to resign the current stake (Drop)

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
def shouldAcceptDraw(state: GameState): Boolean

Determines whether the bot should accept a draw offered by the opponent.

Determines whether the bot should accept a draw offered by the opponent.

Value parameters

state

current game state

Attributes

Returns

true to accept the draw

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
def shouldOfferDouble(state: GameState, currentStake: Int): Boolean

Determines whether the bot should offer a double before its dice roll.

Determines whether the bot should offer a double before its dice roll.

Value parameters

currentStake

the current stake of the game

state

current game state (dice pool is empty)

Attributes

Returns

true to offer a double, false otherwise

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
def shouldOfferDraw(state: GameState): Boolean

Determines whether the bot should offer a draw in the current position.

Determines whether the bot should offer a draw in the current position.

Value parameters

state

current game state

Attributes

Returns

true to offer a draw

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala
protected def winProbability(state: GameState, color: Color): Double

Estimates the winning probability in [0.0, 1.0] of color, whichever side is to move.

Estimates the winning probability in [0.0, 1.0] of color, whichever side is to move.

This is the estimator hook: a strategy with its own equity model (for example a Monte-Carlo rollout) overrides this method, so that both the offer decision (active colour) and the take/drop decision (responder colour) see the same estimate. The default maps the centipawn evaluation to a probability with a logistic sigmoid.

Attributes

Inherited from:
SearchAlgorithm
Source
SearchAlgorithm.scala