Skip to main content

A minimal Python library for Uma Musume turn evaluation

Project description

UmaLite

image

UmaLite is a small Python library for scoring Uma Musume turn actions.

You give it a snapshot of the current state, a run context, and a list of candidate actions. It returns ranked results with a score breakdown for each action.

The library does not read the game or run automation. It scores actions from what the caller knows right now.

The goal is to keep evaluation logic isolated and reusable so other tools can use the same scoring engine.

UmaLite is snapshot-first. The more visible state the caller supplies, the more accurate scenario-specific scoring becomes. Missing optional data should reduce precision, not be silently invented.


Quick start

Most callers now use a scenario client.

The preferred entrypoint is:

from umalite import UmaLiteClient

umalite = UmaLiteClient()
ura_client = umalite.ura
unity_client = umalite.unity
trackblazer_client = umalite.trackblazer

Each scenario client exposes:

  • .snapshots
  • .contexts
  • .profiles
  • .actions

For URA and Unity, the normal path is evaluate_turn(...). For Trackblazer, the normal path is plan_turn(...).

from umalite import CheckpointContext, CheckpointKind, MoodLevel, RaceGrade, StatType, UmaLiteClient

ura_client = UmaLiteClient().ura

snapshot = ura_client.snapshots.minimal(
    stats={
        StatType.SPEED: 420,
        StatType.STAMINA: 360,
        StatType.POWER: 340,
        StatType.GUTS: 250,
        StatType.WIT: 390,
    },
    energy=58,
    mood=MoodLevel.NORMAL,
    fans=42000,
)

context = ura_client.contexts.basic(
    checkpoint=CheckpointContext(
        kind=CheckpointKind.GOAL_RACE,
        turns_remaining=8,
    ),
)

career_profile = ura_client.profiles.basic(
    target_stats={
        StatType.SPEED: 1200,
        StatType.STAMINA: 800,
        StatType.POWER: 1000,
        StatType.GUTS: 400,
        StatType.WIT: 1100,
    },
    minimum_training_mood=MoodLevel.GOOD,
)

actions = [
    ura_client.actions.train(
        "speed_training",
        training_type=StatType.SPEED,
        stat_gains={StatType.SPEED: 18, StatType.POWER: 9},
        sp_gain=5,
        fail_rate=0.15,
    ),
    ura_client.actions.race(
        "g3_race",
        race_grade=RaceGrade.G3,
        fan_gain=5000,
    ),
    ura_client.actions.rest("rest", mood_change=1),
]

result = ura_client.evaluate_turn(
    snapshot=snapshot,
    context=context,
    actions=actions,
    career_profile=career_profile,
)

print(result.best_action_id)

for bid in result.bids:
    print(bid.action.action_id, bid.score)

Reusing an evaluator

If you're evaluating many turns, construct an evaluator once.

from umalite import Evaluator, ScenarioName

engine = Evaluator(scenario=ScenarioName.URA)

result = engine.evaluate(snapshot, context, actions, career_profile=career_profile)

Scenario support

Scenario Public entrypoint Status Notes
URA Finale UmaLiteClient().ura Implemented Evaluator-first baseline model
Unity UmaLiteClient().unity Implemented Evaluator-first with optional Unity-specific terms
Trackblazer UmaLiteClient().trackblazer Experimental Planner-first with preparation steps

Scenarios are implemented as plugins so each mode can adjust reward projection and evaluation logic without modifying the core engine. Scenario clients provide the recommended public surface.


Core models

Evaluation uses three primary inputs.

  • TurnSnapshot - current visible state of the run
  • RunContext - checkpoint horizon, local urgency, risk settings
  • ActionOption - candidate action and its payload

CareerProfile is the run-intent object.

It is used by both evaluate_turn(...) and plan_turn(...). It currently carries:

  • final target stats
  • milestone target stats
  • minimum training mood
  • year-specific training mood floors
  • maximum training fail rate

If both CareerProfile and RunContext.target_stats are provided, the explicit context targets win.

The output is a ranked list of ActionBid results.


Action contract

Action inputs follow the same rule across scenarios:

  • the caller supplies visible facts
  • UmaLite projects hidden outcomes when needed

Training is mostly observable. Callers usually provide visible stat gains, visible SP gain, fail rate, and training_type. energy_delta is optional. If omitted, UmaLite falls back to a bootstrap default. Wit is the only training lane whose shared fallback energy_delta is non-negative. The default Wit fallback is +5 energy.

Race is partly projected. Callers usually provide race_grade and visible fan_gain. If explicit race rewards are omitted, UmaLite projects a baseline reward bundle from the grade.

Rest is projected by default. Callers do not need to hardcode a fixed recovery amount unless they want an explicit override.

Recreation remains an explicit reward action.

The raw action builders remain available:

  • train_action(...)
  • race_action(...)
  • rest_action(...)
  • recreation_action(...)

Scenario clients wrap the same builders behind .actions.


Minimal snapshot

The smallest useful snapshot:

from umalite import MoodLevel, ScenarioName
from umalite.models import TurnSnapshot

snapshot = TurnSnapshot.minimal(
    scenario=ScenarioName.URA,
    stats={
        StatType.SPEED: 420,
        StatType.STAMINA: 360,
        StatType.POWER: 340,
        StatType.GUTS: 250,
        StatType.WIT: 390,
    },
    energy=58,
    mood=MoodLevel.NORMAL,
    fans=42000,
)

Additional fields such as bonds, facilities, turn metadata, conditions, and scenario state are optional enrichment.

String values are also accepted for convenience, but enums are the preferred public API.


Raw API

The raw API is still available:

result = evaluate_turn(
    snapshot,
    context,
    actions,
    config=None,
    career_profile=None,
    milestone=None,
)
plan = plan_turn(
    snapshot,
    context,
    actions,
    config=None,
    career_profile=None,
    milestone=None,
)

Use the raw API when you want direct control over snapshots, contexts, and action payloads.


Precision model

UmaLite does not require perfect state.

Required core state should always be present. Optional enrichment improves scoring quality. If optional scenario data is missing, the evaluator should fall back to a reduced path instead of inventing hidden game state.

In practice this means:

  • minimal snapshots are valid
  • enriched snapshots score better
  • scenario-specific terms activate only when the needed state exists

Projection defaults are bootstrap library approximations, not final scenario truth.


Configuration

Most usage can rely on defaults.

If needed you can supply your own config:

from umalite.config import EvaluationConfig, UtilityConfig

config = EvaluationConfig(
    utility=UtilityConfig(...),
)

Or attach the config to an evaluator instance.

Configuration is intended for policy, such as weights, urgency shaping, and risk tolerance. Core game semantics should remain owned by the library.


Examples

See the examples/ directory for:

  • minimal URA usage
  • enriched URA usage
  • reusable evaluator pattern
  • minimal Unity usage
  • enriched Unity usage
  • minimal Trackblazer usage
  • enriched Trackblazer usage

The scenario client examples are the recommended starting point.


Developing locally

Clone the repo and install dependencies.

git clone https://github.com/yourusername/umalite.git
cd umalite
python -m venv .venv
source .venv/bin/activate  # or .venv\Scripts\activate on Windows
pip install -e ".[dev]"

Run tests.

pytest

Run linters and type checks.

ruff check .
ruff format --check .
mypy .

Install pre-commit hooks for automatic checks on commit.

pre-commit install

The project uses ruff for formatting and linting, mypy for type checking, and pytest for tests.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

umalite-0.1.0.tar.gz (68.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

umalite-0.1.0-py3-none-any.whl (83.4 kB view details)

Uploaded Python 3

File details

Details for the file umalite-0.1.0.tar.gz.

File metadata

  • Download URL: umalite-0.1.0.tar.gz
  • Upload date:
  • Size: 68.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for umalite-0.1.0.tar.gz
Algorithm Hash digest
SHA256 671571cb816a1dda95c54e0796ac444628ee67986802d65a21c236888acf54a5
MD5 ad1d5a38c7346a58ffd5963ec13e9f6b
BLAKE2b-256 39fc22593f1b4e90e4d3d7c6d839fe9c838db57d1cf96104c95e7cf87d1cd16a

See more details on using hashes here.

File details

Details for the file umalite-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: umalite-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 83.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for umalite-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bc2df472540f8eafeb17d23f9bc274cfb0f9060e5d544fee2a99361159060072
MD5 7a77ddbee04bf21809d3ba17a8968311
BLAKE2b-256 45704c9cb7d6f4986cc8ea2cc1821a7877486034a0bc3a0c3afdcd89f97a58ed

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page