Saihai (采配) β€” a classical game-AI agent for gateball

πŸ‡ͺπŸ‡Έ Leer en espaΓ±ol

Saihai is the AI "kantoku" (team manager) of a gateball game. It is not a language model and not a neural network. It is a classical game-AI agent:

  1. Planning by simulation. For every stroke it generates candidate strokes (gates, touches on rival balls, sparks, re-entries, waiting plays…), simulates each one with the real rules engine and physics, including the execution error of the player, and keeps the best few.
  2. Evaluation with learned weights. Each simulated outcome is scored by a hand-built evaluation function (points, risk of being hit, touches, sparks, positioning…) whose 31 numbers were learned by self-play with sep-CMA-ES (a derivative-free evolution strategy).
  3. Kantoku rules. On top of that sit explicit, readable rules a manager would apply: when to take a ball to the pole (agari), how to bring a far ball closer by chaining touches (tsunagi), how to treat the last turns of the match, and how to avoid leaving balls exposed.

The code (rules engine, physics, planner, training and measurement tools) is in the GitHub repository; this Hugging Face repo hosts the weights and this card.

What is in this repo

File What it is
saihai-v1.4.json The weights of model saihai-v1.4 (identical to src/game/cpuWeights.json at tag v1.4.2). 45 values in total: 31 learned genes (sep-CMA-ES) = 21 base weights + 8 phase multipliers (4 key terms Γ— opening and endgame) + the 2 balance slopes leadSlope and clockSlope (the latter learned at 0, i.e. neutral). The other 14 are fixed values or configuration: 5 rule constants in rules (contAttack, heapRisk, heapValue, heapSparkP, rivalSupport; genes in v3, kept fixed in v4), 5 riskWeights (all 1), 2 planner settings (sims), the advanced switch and version.
attackTable.json A precomputed lookup table, not learned weights: how often a rival's touch attempt on one of my balls ends in each outcome (valid touch and spark, my ball knocked out, both out…), simulated with the real physics for a grid of distances to the court line, shot angles and shot distances. One table for a human-like rival and one for the CPU. Generated by npm run lineplay -- --write.

The files are plain JSON, read by the TypeScript package; they are not loadable with transformers or any ML framework.

How it was trained

  • Algorithm: sep-CMA-ES (diagonal-covariance CMA-ES), chosen because the fitness is noisy (each match depends on luck on the grass and on execution errors) and there are only ~30 parameters. The released weights are the mean of the final generation, not the best candidate.
  • Population: 24 candidates per generation, starting from hand-set weights.
  • Fitness: wins (a draw counts Β½) + 0.02 Γ— point difference per match, plus a small term from a battery of behaviour checks (behavior).
  • Each generation: matches in color-swapped pairs with shared random draws against hand-set weights and against the rest of the population; β‰ˆ40 % of the pairs start from end-of-match positions taken from a bank of generated positions.
  • Execution error: a realistic human-level error (aim 0.056 m, power 0.022, direction 0.022), scaled per player and per distance by randomly drawn "certainty" profiles, so it learns a general rule and not a fixed team.
  • Lineage: saihai-v1.4 = the weights of the v4 training run (24 generations of a population of 24 candidates) + fixed kantoku rules, added both before and after the v4 training, up to v1.4. The weights were not retrained after the later additions. The rules are fixed and were defined by the author's own judgement as a gateball player and kantoku, not learned. A brief list: attacking after a gate, defending the line, openings, taking a ball to the pole (agari) at the right time, tsunagi, double angle, touches on teammates, re-entries, the last turn, spark that avoids own balls, and clustering/advancing depending on who plays again. Some rule constants are candidates to become learned genes in a future retraining.

Full history and honest notes on every change, including those that did not help: TRAINING.md (Spanish).

Results

All figures are for saihai-v1.4 with the default seeds of the repository tools, a goal pole of 0.025 m and the certainty of the "Kantoku IA" level of the demo game. Matches are played in color-swapped pairs. "Β±" is the 95 % interval reported by the repository's tools. The reference baseline and commands are in the repository's CLAUDE.md.

Measurement Condition Result
h2h β€” head to head against the weights of the previous model, saihai-v1.3 200 matches, --seed 8300000 46.5 % (85 wins / 16 draws / 99 losses), βˆ’0.38 points per match. Statistically even (interval β‰ˆ Β±6.9): v1.4 did not become measurably stronger than v1.3 in self-play; it changed how it plays in specific documented situations.
humanduel β€” against a human-like rival (plays well, but with the execution error of a good human and extra power on touch attempts) 200 matches, default seed 84.5 % score (draws count Β½), +7.00 points per match
behavior β€” battery of situations taken from real matches 4 seeds per scenario 98 % of the checks pass
selfplay --games 8 --levels 4,1 --seed 1 small sanity run 5 wins / 2 draws / 1 loss, 20.1–16.4 points
Time per stroke (bench:plan --kantoku) Node, one core β‰ˆ 55–60 ms

Note: the first measurements of v1.4 used a 0.05 m goal pole (h2h 49.8 %, humanduel 87.3 %); after the pole was set to 0.025 m the same weights give the figures above. The weights did not change.

Limitations

  • Calibrated against a model of a human rival, not against real people at scale. opponent: 'human' makes Saihai assume the execution error of a good human player; the humanduel rival is a simulated human (a planner executing with human error). It has been validated against real players only in matches played by the author, who is both the player and the gateball kantoku.
  • Tied to this engine. The weights make sense only with this rules engine, physics and the two-bar execution mechanic. If the rules, the physics or the error model (CONFIG values) change, the weights should be re-validated or retrained.
  • Known weak spots are documented, not hidden. Situations taken from the author's real matches (named after the turn in which they appeared, e.g. T12, a re-entering ball that stayed glued to a rival ball) were fixed with explicit rules and are covered by the behavior battery and the tests. Other situations of the same kind may exist that nobody has seen yet.
  • Self-play strength has plateaued. The latest versions improved specific behaviours but did not beat the previous one head to head.
  • Game design choices (e.g. a match always ends after a White ball has played) are listed in RULES.md.

How to use it

Install the package from GitHub (the weights are bundled in it; you do not need to download these files to use Saihai):

npm install github:ckomiya/saihai-gateball#v1.4.2
import { createMatch, Saihai, playShot } from 'saihai-gateball';

const match = createMatch({ seed: 42 });            // new match (seeded randomness)
const saihai = new Saihai({ opponent: 'human' });   // judges its rival as a person would

while (match.stage !== 'done') {
  const shot = saihai.chooseShot(match);            // { startX, aim, power, accuracy, plan }
  playShot(match, shot);                            // applies the stroke and lets the balls roll
  match.proceed();                                  // next stroke or turn
}
console.log(match.teamScore(0), match.teamScore(1));

The full API, the events table and the glossary of gateball terms are in the GitHub README. Texts can be Spanish or English (lang: 'es' | 'en').

Links

Author and license

Christian Komiya. Code and weights under the MIT license. No assets, code or text from any commercial game are used; the project is an original implementation.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support