wingspan-rl 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wingspan_rl-1.0.0/LICENSE +21 -0
- wingspan_rl-1.0.0/PKG-INFO +420 -0
- wingspan_rl-1.0.0/README.md +389 -0
- wingspan_rl-1.0.0/pyproject.toml +118 -0
- wingspan_rl-1.0.0/setup.cfg +4 -0
- wingspan_rl-1.0.0/src/wingspan/__init__.py +3 -0
- wingspan_rl-1.0.0/src/wingspan/__main__.py +134 -0
- wingspan_rl-1.0.0/src/wingspan/agents/__init__.py +20 -0
- wingspan_rl-1.0.0/src/wingspan/agents/base.py +34 -0
- wingspan_rl-1.0.0/src/wingspan/agents/cli.py +278 -0
- wingspan_rl-1.0.0/src/wingspan/agents/display.py +596 -0
- wingspan_rl-1.0.0/src/wingspan/agents/interactive.py +435 -0
- wingspan_rl-1.0.0/src/wingspan/aid/__init__.py +8 -0
- wingspan_rl-1.0.0/src/wingspan/aid/advisor.py +297 -0
- wingspan_rl-1.0.0/src/wingspan/aid/app.py +334 -0
- wingspan_rl-1.0.0/src/wingspan/aid/console.py +147 -0
- wingspan_rl-1.0.0/src/wingspan/aid/entry.py +385 -0
- wingspan_rl-1.0.0/src/wingspan/aid/hooks.py +202 -0
- wingspan_rl-1.0.0/src/wingspan/aid/models.py +193 -0
- wingspan_rl-1.0.0/src/wingspan/aid/oracle.py +287 -0
- wingspan_rl-1.0.0/src/wingspan/aid/oracle_state.py +192 -0
- wingspan_rl-1.0.0/src/wingspan/aid/placeholders.py +88 -0
- wingspan_rl-1.0.0/src/wingspan/aid/preview.py +84 -0
- wingspan_rl-1.0.0/src/wingspan/aid/relay.py +284 -0
- wingspan_rl-1.0.0/src/wingspan/aid/widgets.py +376 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/__init__.py +21 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/attention_probe.py +356 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/cli.py +424 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/head_to_head.py +56 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/layer_probe.py +233 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/models.py +268 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/probe_set.py +144 -0
- wingspan_rl-1.0.0/src/wingspan/analysis/representation.py +596 -0
- wingspan_rl-1.0.0/src/wingspan/architecture.py +884 -0
- wingspan_rl-1.0.0/src/wingspan/cards/__init__.py +82 -0
- wingspan_rl-1.0.0/src/wingspan/cards/lookup.py +187 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/__init__.py +69 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/catalog.py +67 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/fields.py +172 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/loader.py +93 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/matchers.py +779 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/pink_matchers.py +117 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/power.py +59 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/registry.py +40 -0
- wingspan_rl-1.0.0/src/wingspan/cards/parse/tags.py +38 -0
- wingspan_rl-1.0.0/src/wingspan/cards/schema.py +498 -0
- wingspan_rl-1.0.0/src/wingspan/cli.py +494 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/__init__.py +33 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/__main__.py +104 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/monitor.py +159 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/runfile.py +106 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/runner.py +295 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/s3sync.py +242 -0
- wingspan_rl-1.0.0/src/wingspan/cloud/status.py +147 -0
- wingspan_rl-1.0.0/src/wingspan/compat/__init__.py +139 -0
- wingspan_rl-1.0.0/src/wingspan/compat/v1_0.py +173 -0
- wingspan_rl-1.0.0/src/wingspan/compat/v1_3.py +229 -0
- wingspan_rl-1.0.0/src/wingspan/compat/v1_4.py +405 -0
- wingspan_rl-1.0.0/src/wingspan/data/bonus.json +1030 -0
- wingspan_rl-1.0.0/src/wingspan/data/general.json +172 -0
- wingspan_rl-1.0.0/src/wingspan/data/goals.json +618 -0
- wingspan_rl-1.0.0/src/wingspan/data/master.json +57535 -0
- wingspan_rl-1.0.0/src/wingspan/data/parameters.json +5 -0
- wingspan_rl-1.0.0/src/wingspan/data/release/last.pt +0 -0
- wingspan_rl-1.0.0/src/wingspan/data/release/manifest.json +8 -0
- wingspan_rl-1.0.0/src/wingspan/data/release/run_config_20261021-113648.json +222 -0
- wingspan_rl-1.0.0/src/wingspan/data/release/setup.pt +0 -0
- wingspan_rl-1.0.0/src/wingspan/decisions.py +850 -0
- wingspan_rl-1.0.0/src/wingspan/encode/__init__.py +172 -0
- wingspan_rl-1.0.0/src/wingspan/encode/choice_encode.py +1715 -0
- wingspan_rl-1.0.0/src/wingspan/encode/layout.py +1257 -0
- wingspan_rl-1.0.0/src/wingspan/encode/state_encode.py +726 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/__init__.py +60 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/card_feature.py +271 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/choice.py +944 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/descriptors.py +236 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/embed_rules.py +411 -0
- wingspan_rl-1.0.0/src/wingspan/encode/stripes/state.py +1124 -0
- wingspan_rl-1.0.0/src/wingspan/engine/__init__.py +20 -0
- wingspan_rl-1.0.0/src/wingspan/engine/actions.py +1038 -0
- wingspan_rl-1.0.0/src/wingspan/engine/core.py +840 -0
- wingspan_rl-1.0.0/src/wingspan/engine/forecast.py +448 -0
- wingspan_rl-1.0.0/src/wingspan/engine/helpers.py +219 -0
- wingspan_rl-1.0.0/src/wingspan/engine/ledger.py +597 -0
- wingspan_rl-1.0.0/src/wingspan/engine/log_format.py +275 -0
- wingspan_rl-1.0.0/src/wingspan/engine/playability.py +553 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/__init__.py +52 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/dispatch.py +263 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/drafting.py +268 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/egg_trade.py +211 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/grants.py +855 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/multi_actor.py +316 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/nest_aggregate.py +145 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/predator_repeat.py +222 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/registry.py +51 -0
- wingspan_rl-1.0.0/src/wingspan/engine/powers/tray_trade.py +266 -0
- wingspan_rl-1.0.0/src/wingspan/engine/reactors.py +346 -0
- wingspan_rl-1.0.0/src/wingspan/engine/scoring.py +1171 -0
- wingspan_rl-1.0.0/src/wingspan/engine/setup_flow.py +244 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/__init__.py +6 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/models.py +747 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/recorder.py +589 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/render_jsonl.py +247 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/render_text.py +86 -0
- wingspan_rl-1.0.0/src/wingspan/gamelog/summarize.py +380 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/__init__.py +26 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/config.py +148 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/dispatcher.py +243 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/events.py +301 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/handlers/__init__.py +27 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/handlers/card_visits.py +58 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/handlers/decision_logger.py +56 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/handlers/game_log_html.py +199 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/handlers/game_stats.py +193 -0
- wingspan_rl-1.0.0/src/wingspan/instrumentation/registry.py +57 -0
- wingspan_rl-1.0.0/src/wingspan/model/__init__.py +12 -0
- wingspan_rl-1.0.0/src/wingspan/model/core.py +1106 -0
- wingspan_rl-1.0.0/src/wingspan/model/hand_model.py +130 -0
- wingspan_rl-1.0.0/src/wingspan/model/mlp.py +102 -0
- wingspan_rl-1.0.0/src/wingspan/players/__init__.py +55 -0
- wingspan_rl-1.0.0/src/wingspan/players/decision_probe.py +83 -0
- wingspan_rl-1.0.0/src/wingspan/players/factory.py +347 -0
- wingspan_rl-1.0.0/src/wingspan/players/loaders.py +239 -0
- wingspan_rl-1.0.0/src/wingspan/players/spec.py +114 -0
- wingspan_rl-1.0.0/src/wingspan/players/value_sink.py +38 -0
- wingspan_rl-1.0.0/src/wingspan/release.py +63 -0
- wingspan_rl-1.0.0/src/wingspan/release_prep.py +138 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/__init__.py +13 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/card_view.py +281 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/encode_viewer.py +707 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/game_log_capture.py +655 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/game_log_csv.py +115 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/game_log_html.py +1551 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/html.py +946 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/humanize.py +319 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/inspect_cli.py +448 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/summary_cli.py +61 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/svg.py +1891 -0
- wingspan_rl-1.0.0/src/wingspan/reporting/training_summary.py +1789 -0
- wingspan_rl-1.0.0/src/wingspan/research/__init__.py +8 -0
- wingspan_rl-1.0.0/src/wingspan/research/app.py +250 -0
- wingspan_rl-1.0.0/src/wingspan/research/constants.py +46 -0
- wingspan_rl-1.0.0/src/wingspan/research/game_stats.py +235 -0
- wingspan_rl-1.0.0/src/wingspan/research/game_stats_agg.py +760 -0
- wingspan_rl-1.0.0/src/wingspan/research/models.py +525 -0
- wingspan_rl-1.0.0/src/wingspan/research/progress.py +104 -0
- wingspan_rl-1.0.0/src/wingspan/research/setup_keep.py +355 -0
- wingspan_rl-1.0.0/src/wingspan/sampling.py +24 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/__init__.py +74 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/architecture.py +447 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/candidates.py +135 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/encode.py +416 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/generate.py +204 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/record.py +60 -0
- wingspan_rl-1.0.0/src/wingspan/setup_model/stripes.py +596 -0
- wingspan_rl-1.0.0/src/wingspan/state.py +896 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/__init__.py +34 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/app.py +359 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/dashboard.py +166 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/elo.py +36 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/models.py +360 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/participants.py +227 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/picker.py +172 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/results.py +155 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/runner.py +394 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/schedule.py +76 -0
- wingspan_rl-1.0.0/src/wingspan/tournament/state.py +146 -0
- wingspan_rl-1.0.0/src/wingspan/training/__init__.py +37 -0
- wingspan_rl-1.0.0/src/wingspan/training/__main__.py +8 -0
- wingspan_rl-1.0.0/src/wingspan/training/app.py +576 -0
- wingspan_rl-1.0.0/src/wingspan/training/artifacts.py +93 -0
- wingspan_rl-1.0.0/src/wingspan/training/batched_collect.py +418 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/__init__.py +34 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/braille.py +79 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/convergence_chart.py +680 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/geometry.py +57 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/histogram.py +110 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/insets.py +270 -0
- wingspan_rl-1.0.0/src/wingspan/training/charts/text_helpers.py +84 -0
- wingspan_rl-1.0.0/src/wingspan/training/collect.py +589 -0
- wingspan_rl-1.0.0/src/wingspan/training/config.py +1366 -0
- wingspan_rl-1.0.0/src/wingspan/training/config_file.py +142 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/__init__.py +19 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/arch_diagram.py +1449 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/controller.py +838 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/fields.py +1772 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/keys.py +193 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/runs.py +398 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/screen.py +727 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/state.py +129 -0
- wingspan_rl-1.0.0/src/wingspan/training/configure/user_defaults.py +187 -0
- wingspan_rl-1.0.0/src/wingspan/training/convergence.py +215 -0
- wingspan_rl-1.0.0/src/wingspan/training/cpu_threads.py +44 -0
- wingspan_rl-1.0.0/src/wingspan/training/dashboard.py +959 -0
- wingspan_rl-1.0.0/src/wingspan/training/evaluate.py +306 -0
- wingspan_rl-1.0.0/src/wingspan/training/learner.py +1062 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop.py +378 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_anneal.py +98 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_checkpoint.py +259 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_collect.py +187 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_eval.py +314 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_metrics.py +187 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_probe.py +91 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_resume.py +367 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_setup.py +246 -0
- wingspan_rl-1.0.0/src/wingspan/training/loop_target.py +163 -0
- wingspan_rl-1.0.0/src/wingspan/training/metrics.py +361 -0
- wingspan_rl-1.0.0/src/wingspan/training/metrics_log.py +79 -0
- wingspan_rl-1.0.0/src/wingspan/training/mp_collect.py +841 -0
- wingspan_rl-1.0.0/src/wingspan/training/policy.py +246 -0
- wingspan_rl-1.0.0/src/wingspan/training/returns.py +133 -0
- wingspan_rl-1.0.0/src/wingspan/training/runmeta.py +429 -0
- wingspan_rl-1.0.0/src/wingspan/training/runstate.py +687 -0
- wingspan_rl-1.0.0/src/wingspan/training/setup_learner.py +226 -0
- wingspan_rl-1.0.0/src/wingspan/training/setup_net.py +491 -0
- wingspan_rl-1.0.0/src/wingspan/training/setup_runmeta.py +117 -0
- wingspan_rl-1.0.0/src/wingspan/training/steps.py +58 -0
- wingspan_rl-1.0.0/src/wingspan/training/sysmon.py +60 -0
- wingspan_rl-1.0.0/src/wingspan/training/theme.py +202 -0
- wingspan_rl-1.0.0/src/wingspan/training/timestamps.py +205 -0
- wingspan_rl-1.0.0/src/wingspan/version.py +308 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/PKG-INFO +420 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/SOURCES.txt +398 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/dependency_links.txt +1 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/entry_points.txt +2 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/requires.txt +17 -0
- wingspan_rl-1.0.0/src/wingspan_rl.egg-info/top_level.txt +1 -0
- wingspan_rl-1.0.0/tests/test_activation_log.py +178 -0
- wingspan_rl-1.0.0/tests/test_aid_advisor.py +456 -0
- wingspan_rl-1.0.0/tests/test_aid_console.py +94 -0
- wingspan_rl-1.0.0/tests/test_aid_counts_widgets.py +253 -0
- wingspan_rl-1.0.0/tests/test_aid_entry_widgets.py +353 -0
- wingspan_rl-1.0.0/tests/test_aid_oracle.py +582 -0
- wingspan_rl-1.0.0/tests/test_aid_relay.py +601 -0
- wingspan_rl-1.0.0/tests/test_aid_session.py +364 -0
- wingspan_rl-1.0.0/tests/test_aid_widgets.py +492 -0
- wingspan_rl-1.0.0/tests/test_analysis_probe.py +505 -0
- wingspan_rl-1.0.0/tests/test_anneal_schedule.py +472 -0
- wingspan_rl-1.0.0/tests/test_becomes_unplayable.py +865 -0
- wingspan_rl-1.0.0/tests/test_birdfeeder.py +542 -0
- wingspan_rl-1.0.0/tests/test_birds_no_eggs_integration.py +166 -0
- wingspan_rl-1.0.0/tests/test_bonus_categories.py +221 -0
- wingspan_rl-1.0.0/tests/test_bonus_linear_value.py +106 -0
- wingspan_rl-1.0.0/tests/test_bootstrap_opponent.py +370 -0
- wingspan_rl-1.0.0/tests/test_card_parse.py +153 -0
- wingspan_rl-1.0.0/tests/test_card_table_cache.py +132 -0
- wingspan_rl-1.0.0/tests/test_cards_lookup.py +166 -0
- wingspan_rl-1.0.0/tests/test_choice_landing_slot.py +246 -0
- wingspan_rl-1.0.0/tests/test_cli_multiplayer.py +202 -0
- wingspan_rl-1.0.0/tests/test_cli_setup_dialog.py +300 -0
- wingspan_rl-1.0.0/tests/test_cloud_runfile.py +75 -0
- wingspan_rl-1.0.0/tests/test_cloud_s3sync.py +73 -0
- wingspan_rl-1.0.0/tests/test_cloud_status.py +105 -0
- wingspan_rl-1.0.0/tests/test_collect_nplayers.py +90 -0
- wingspan_rl-1.0.0/tests/test_combine_gain_food.py +397 -0
- wingspan_rl-1.0.0/tests/test_commit_row_pricing.py +434 -0
- wingspan_rl-1.0.0/tests/test_compat_v1_0.py +282 -0
- wingspan_rl-1.0.0/tests/test_compat_v1_3.py +550 -0
- wingspan_rl-1.0.0/tests/test_compat_v1_4.py +1114 -0
- wingspan_rl-1.0.0/tests/test_config_file.py +170 -0
- wingspan_rl-1.0.0/tests/test_convergence_charts.py +297 -0
- wingspan_rl-1.0.0/tests/test_dagger.py +579 -0
- wingspan_rl-1.0.0/tests/test_decision_families.py +167 -0
- wingspan_rl-1.0.0/tests/test_decision_shapes.py +823 -0
- wingspan_rl-1.0.0/tests/test_device_split.py +374 -0
- wingspan_rl-1.0.0/tests/test_discard_egg_for_wild.py +222 -0
- wingspan_rl-1.0.0/tests/test_dynamic_bonus_scoring.py +101 -0
- wingspan_rl-1.0.0/tests/test_egg_goal_delta.py +264 -0
- wingspan_rl-1.0.0/tests/test_encode.py +1438 -0
- wingspan_rl-1.0.0/tests/test_encode_spec.py +403 -0
- wingspan_rl-1.0.0/tests/test_encode_viewer.py +410 -0
- wingspan_rl-1.0.0/tests/test_encoding_golden_n2.py +76 -0
- wingspan_rl-1.0.0/tests/test_encoding_layout_nplayers.py +201 -0
- wingspan_rl-1.0.0/tests/test_encoding_values_nplayers.py +273 -0
- wingspan_rl-1.0.0/tests/test_engine_agent_dispatch.py +111 -0
- wingspan_rl-1.0.0/tests/test_era_pinned_resume.py +398 -0
- wingspan_rl-1.0.0/tests/test_evaluate_core.py +90 -0
- wingspan_rl-1.0.0/tests/test_evaluate_nplayers.py +175 -0
- wingspan_rl-1.0.0/tests/test_extra_play.py +244 -0
- wingspan_rl-1.0.0/tests/test_food_payment.py +393 -0
- wingspan_rl-1.0.0/tests/test_forecast.py +312 -0
- wingspan_rl-1.0.0/tests/test_gain_food_choice.py +280 -0
- wingspan_rl-1.0.0/tests/test_game_log_csv.py +204 -0
- wingspan_rl-1.0.0/tests/test_game_log_html.py +906 -0
- wingspan_rl-1.0.0/tests/test_gamelog_jsonl.py +389 -0
- wingspan_rl-1.0.0/tests/test_gamelog_ledger.py +362 -0
- wingspan_rl-1.0.0/tests/test_gamelog_nplayers.py +181 -0
- wingspan_rl-1.0.0/tests/test_gamelog_render_text.py +186 -0
- wingspan_rl-1.0.0/tests/test_gamelog_serialize.py +301 -0
- wingspan_rl-1.0.0/tests/test_gamelog_summarize.py +395 -0
- wingspan_rl-1.0.0/tests/test_gamelog_tree.py +322 -0
- wingspan_rl-1.0.0/tests/test_goal_delta_ignoring_eggs.py +224 -0
- wingspan_rl-1.0.0/tests/test_habitat_action_track.py +535 -0
- wingspan_rl-1.0.0/tests/test_hand_pooling.py +290 -0
- wingspan_rl-1.0.0/tests/test_index_accuracy.py +209 -0
- wingspan_rl-1.0.0/tests/test_inspect_era.py +197 -0
- wingspan_rl-1.0.0/tests/test_instrumentation_config.py +82 -0
- wingspan_rl-1.0.0/tests/test_instrumentation_dispatch.py +220 -0
- wingspan_rl-1.0.0/tests/test_instrumentation_validation.py +44 -0
- wingspan_rl-1.0.0/tests/test_known_hand.py +359 -0
- wingspan_rl-1.0.0/tests/test_learner_minibatch.py +319 -0
- wingspan_rl-1.0.0/tests/test_learner_rewards.py +304 -0
- wingspan_rl-1.0.0/tests/test_loop_iteration_order.py +162 -0
- wingspan_rl-1.0.0/tests/test_loop_probe.py +384 -0
- wingspan_rl-1.0.0/tests/test_loop_setup_update.py +81 -0
- wingspan_rl-1.0.0/tests/test_main_action.py +160 -0
- wingspan_rl-1.0.0/tests/test_metrics_log.py +104 -0
- wingspan_rl-1.0.0/tests/test_model_and_self_play.py +372 -0
- wingspan_rl-1.0.0/tests/test_model_board_attention.py +1174 -0
- wingspan_rl-1.0.0/tests/test_model_nplayers.py +317 -0
- wingspan_rl-1.0.0/tests/test_move_goal_delta.py +198 -0
- wingspan_rl-1.0.0/tests/test_mp_collect.py +278 -0
- wingspan_rl-1.0.0/tests/test_multiplayer_engine.py +150 -0
- wingspan_rl-1.0.0/tests/test_play_bird_payment.py +172 -0
- wingspan_rl-1.0.0/tests/test_play_cli.py +219 -0
- wingspan_rl-1.0.0/tests/test_playability.py +625 -0
- wingspan_rl-1.0.0/tests/test_players_factory.py +146 -0
- wingspan_rl-1.0.0/tests/test_players_loaders.py +170 -0
- wingspan_rl-1.0.0/tests/test_players_spec.py +63 -0
- wingspan_rl-1.0.0/tests/test_power_coverage.py +50 -0
- wingspan_rl-1.0.0/tests/test_power_dispatch_edge_cases.py +126 -0
- wingspan_rl-1.0.0/tests/test_powers_all_lay_egg.py +570 -0
- wingspan_rl-1.0.0/tests/test_powers_all_lay_nest.py +31 -0
- wingspan_rl-1.0.0/tests/test_powers_autoaccept.py +325 -0
- wingspan_rl-1.0.0/tests/test_powers_birdfeeder_choice.py +29 -0
- wingspan_rl-1.0.0/tests/test_powers_cache_food.py +74 -0
- wingspan_rl-1.0.0/tests/test_powers_coverage_batch.py +659 -0
- wingspan_rl-1.0.0/tests/test_powers_discard_egg_gain_wild.py +24 -0
- wingspan_rl-1.0.0/tests/test_powers_discard_food_tuck.py +25 -0
- wingspan_rl-1.0.0/tests/test_powers_draft_cards.py +15 -0
- wingspan_rl-1.0.0/tests/test_powers_draw_bonus_keep.py +19 -0
- wingspan_rl-1.0.0/tests/test_powers_draw_tray_all.py +15 -0
- wingspan_rl-1.0.0/tests/test_powers_each_player_birdfeeder.py +21 -0
- wingspan_rl-1.0.0/tests/test_powers_each_player_die.py +521 -0
- wingspan_rl-1.0.0/tests/test_powers_gain_all_birdfeeder.py +21 -0
- wingspan_rl-1.0.0/tests/test_powers_gain_birdfeeder_die.py +15 -0
- wingspan_rl-1.0.0/tests/test_powers_house_wren.py +15 -0
- wingspan_rl-1.0.0/tests/test_powers_lay_egg_all_nest.py +27 -0
- wingspan_rl-1.0.0/tests/test_powers_misc_unique.py +1084 -0
- wingspan_rl-1.0.0/tests/test_powers_pink_predator_die.py +20 -0
- wingspan_rl-1.0.0/tests/test_powers_pink_reactive.py +322 -0
- wingspan_rl-1.0.0/tests/test_powers_predator_tuck.py +34 -0
- wingspan_rl-1.0.0/tests/test_powers_repeat_predator.py +11 -0
- wingspan_rl-1.0.0/tests/test_powers_trade_food.py +11 -0
- wingspan_rl-1.0.0/tests/test_powers_tuck_conditional.py +564 -0
- wingspan_rl-1.0.0/tests/test_ppo_gae.py +342 -0
- wingspan_rl-1.0.0/tests/test_quality_gate_args.py +156 -0
- wingspan_rl-1.0.0/tests/test_release.py +210 -0
- wingspan_rl-1.0.0/tests/test_report_panels.py +515 -0
- wingspan_rl-1.0.0/tests/test_reporting_humanize.py +675 -0
- wingspan_rl-1.0.0/tests/test_reporting_nplayers.py +144 -0
- wingspan_rl-1.0.0/tests/test_research_game_stats.py +608 -0
- wingspan_rl-1.0.0/tests/test_research_progress.py +110 -0
- wingspan_rl-1.0.0/tests/test_research_setup_keep.py +416 -0
- wingspan_rl-1.0.0/tests/test_returns.py +263 -0
- wingspan_rl-1.0.0/tests/test_round_goal_coverage.py +103 -0
- wingspan_rl-1.0.0/tests/test_round_goal_freeze.py +130 -0
- wingspan_rl-1.0.0/tests/test_round_goal_scoring.py +100 -0
- wingspan_rl-1.0.0/tests/test_run_config.py +433 -0
- wingspan_rl-1.0.0/tests/test_run_metadata.py +189 -0
- wingspan_rl-1.0.0/tests/test_scoring_nplayer.py +215 -0
- wingspan_rl-1.0.0/tests/test_scoring_played_with_eggs.py +327 -0
- wingspan_rl-1.0.0/tests/test_setup_actor_critic.py +433 -0
- wingspan_rl-1.0.0/tests/test_setup_arch_key_restart.py +164 -0
- wingspan_rl-1.0.0/tests/test_setup_candidates.py +98 -0
- wingspan_rl-1.0.0/tests/test_setup_collect.py +89 -0
- wingspan_rl-1.0.0/tests/test_setup_data_store_guard.py +5 -0
- wingspan_rl-1.0.0/tests/test_setup_embedders.py +172 -0
- wingspan_rl-1.0.0/tests/test_setup_encode.py +179 -0
- wingspan_rl-1.0.0/tests/test_setup_encode_pricing.py +323 -0
- wingspan_rl-1.0.0/tests/test_setup_feature_off.py +37 -0
- wingspan_rl-1.0.0/tests/test_setup_flow.py +239 -0
- wingspan_rl-1.0.0/tests/test_setup_generate.py +81 -0
- wingspan_rl-1.0.0/tests/test_setup_net.py +213 -0
- wingspan_rl-1.0.0/tests/test_setup_state_construction.py +74 -0
- wingspan_rl-1.0.0/tests/test_setup_stripes.py +178 -0
- wingspan_rl-1.0.0/tests/test_setup_train_cpu.py +67 -0
- wingspan_rl-1.0.0/tests/test_smoke.py +25 -0
- wingspan_rl-1.0.0/tests/test_split_setup_bonus.py +132 -0
- wingspan_rl-1.0.0/tests/test_split_setup_food.py +223 -0
- wingspan_rl-1.0.0/tests/test_state_food_unlock.py +177 -0
- wingspan_rl-1.0.0/tests/test_state_known_hand.py +159 -0
- wingspan_rl-1.0.0/tests/test_state_seams.py +144 -0
- wingspan_rl-1.0.0/tests/test_step_timestamps.py +189 -0
- wingspan_rl-1.0.0/tests/test_timeline_chart.py +550 -0
- wingspan_rl-1.0.0/tests/test_tournament_dashboard.py +116 -0
- wingspan_rl-1.0.0/tests/test_tournament_discovery.py +115 -0
- wingspan_rl-1.0.0/tests/test_tournament_elo.py +67 -0
- wingspan_rl-1.0.0/tests/test_tournament_regime.py +149 -0
- wingspan_rl-1.0.0/tests/test_tournament_results.py +90 -0
- wingspan_rl-1.0.0/tests/test_tournament_schedule.py +63 -0
- wingspan_rl-1.0.0/tests/test_tournament_smoke.py +142 -0
- wingspan_rl-1.0.0/tests/test_training_app_config.py +340 -0
- wingspan_rl-1.0.0/tests/test_training_configurator.py +2322 -0
- wingspan_rl-1.0.0/tests/test_training_dashboard.py +671 -0
- wingspan_rl-1.0.0/tests/test_training_iteration_n3.py +108 -0
- wingspan_rl-1.0.0/tests/test_training_summary.py +445 -0
- wingspan_rl-1.0.0/tests/test_tray_refill.py +373 -0
- wingspan_rl-1.0.0/tests/test_tray_set_embedding.py +219 -0
- wingspan_rl-1.0.0/tests/test_version.py +100 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brian Boucher
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wingspan-rl
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Wingspan board-game simulator and RL training pipeline, with a bundled trained model
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/bmboucher/wingspan
|
|
7
|
+
Project-URL: Repository, https://github.com/bmboucher/wingspan
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Topic :: Games/Entertainment :: Board Games
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: numpy>=1.24
|
|
15
|
+
Requires-Dist: torch>=2.0
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: pyyaml
|
|
18
|
+
Requires-Dist: rich>=13.7
|
|
19
|
+
Requires-Dist: psutil>=5.9
|
|
20
|
+
Requires-Dist: boto3>=1.34
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
|
|
25
|
+
Requires-Dist: pyright>=1.1.400; extra == "dev"
|
|
26
|
+
Requires-Dist: black>=24.0; extra == "dev"
|
|
27
|
+
Requires-Dist: isort>=9.0; extra == "dev"
|
|
28
|
+
Requires-Dist: boto3-stubs[s3]; extra == "dev"
|
|
29
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# Wingspan
|
|
33
|
+
|
|
34
|
+
A simulator and reinforcement-learning training pipeline for the **core-set**
|
|
35
|
+
board game [Wingspan](https://stonemaiergames.com/games/wingspan/), supporting
|
|
36
|
+
**2-4 players from the CLI** (the engine/config support up to 5; see
|
|
37
|
+
[docs/PROJECT.md](docs/PROJECT.md)). A given trained network plays at exactly
|
|
38
|
+
the seat count it was trained at (`num_players`, a per-run config field);
|
|
39
|
+
`wingspan play` seats any mix of human, random, and AI players up to that
|
|
40
|
+
count. You can play a full
|
|
41
|
+
game from the terminal, run quick automated games for logs or debugging, watch
|
|
42
|
+
a trained network play (against itself, a frozen past self, or a random
|
|
43
|
+
agent), and train a neural-network agent by self-play while watching it
|
|
44
|
+
improve on a live dashboard.
|
|
45
|
+
|
|
46
|
+
## Setup
|
|
47
|
+
|
|
48
|
+
Requires **Python 3.12+**. Install the released package from PyPI:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
pip install wingspan-rl
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
and play a game with the bundled trained model right away:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
wingspan play --html game.html
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
PyTorch is the heavy transitive dependency. For a much smaller install, put the
|
|
61
|
+
CPU-only wheel in first (see the
|
|
62
|
+
[PyTorch install selector](https://pytorch.org/get-started/locally/); e.g.
|
|
63
|
+
`pip install torch --index-url https://download.pytorch.org/whl/cpu`) and then
|
|
64
|
+
`pip install wingspan-rl`.
|
|
65
|
+
|
|
66
|
+
### Bundled model
|
|
67
|
+
|
|
68
|
+
The package ships a trained model (artifact era 1.5, trained by self-play,
|
|
69
|
+
**2-player only**). When `--p0` / `--p1` are `last` / `best` / `opponent` and
|
|
70
|
+
no such checkpoint exists in the checkpoint directory, `wingspan play` falls
|
|
71
|
+
back to the bundled model and says so; `--p0 release` selects it explicitly.
|
|
72
|
+
`--p2` / `--p3` (3-4 player tables) require a model you trained yourself.
|
|
73
|
+
`wingspan --version` shows the package version and the bundled model's run.
|
|
74
|
+
|
|
75
|
+
### Development install
|
|
76
|
+
|
|
77
|
+
To work on the code, install this checkout (editable) instead:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
pip install -e .
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This pulls in everything needed to play and to train (PyTorch, NumPy, Pydantic,
|
|
84
|
+
rich). For the test suite and developer tooling (pyright, black, isort, pytest):
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
pip install -e ".[dev]"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Training runs on **CPU**: self-play collection is CPU-bound and fans out across
|
|
91
|
+
worker processes, and the gradient update is small, so the whole pipeline is
|
|
92
|
+
designed for CPU. (A CUDA PyTorch build still works for one-off experiments, but
|
|
93
|
+
CPU is the supported path.)
|
|
94
|
+
|
|
95
|
+
## Play games
|
|
96
|
+
|
|
97
|
+
One command runs every matchup — interactive play, quick automated games, and
|
|
98
|
+
trained-AI matches. Set each seat with `--p0` / `--p1` / `--p2` / `--p3`; the
|
|
99
|
+
value is `human` (interactive play in the terminal), `random` (the
|
|
100
|
+
uniform-random agent), a named checkpoint (`last`, `best`, or `opponent`,
|
|
101
|
+
resolved against `--checkpoint-dir`), a path to a `.pt` file, or a run
|
|
102
|
+
directory (its `last.pt` is seated). `--p0` / `--p1` are always active
|
|
103
|
+
(2-seat default); `--p2` / `--p3` add a 3rd / 4th seat and must be filled
|
|
104
|
+
contiguously (`--p3` without `--p2` is rejected). A trained checkpoint can
|
|
105
|
+
only be seated at the table size it was trained at (`num_players`) — mixing,
|
|
106
|
+
say, a 2-player checkpoint into a 3-seat table is refused up front. The
|
|
107
|
+
default matchup is `last` vs `last` — the most recent trained model playing
|
|
108
|
+
itself — so the bare command needs a trained model (see **Train an agent**);
|
|
109
|
+
use `--p0 human --p1 random` to play without one:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
wingspan play # latest trained model vs itself
|
|
113
|
+
wingspan play --p0 human --p1 random # play interactively vs a random opponent
|
|
114
|
+
wingspan play --p0 human --p1 human # two humans, hotseat on one keyboard
|
|
115
|
+
wingspan play --p0 human --p1 best --seed 42 # take on the strongest checkpoint, reproducible deal
|
|
116
|
+
wingspan play --p0 random --p1 random --games 5 --log games.log # quick automated games -> games.log.0 ..
|
|
117
|
+
wingspan play --p0 best --p1 opponent --games 10 # best vs the frozen ladder rung
|
|
118
|
+
wingspan play --p0 best --p1 best --greedy --log ai.log # best vs itself, argmax play
|
|
119
|
+
wingspan play --p0 runs/exp/last.pt --p1 random # a checkpoint by path
|
|
120
|
+
wingspan play --p0 best --p1 best --html game.html # navigable HTML game-log viewer
|
|
121
|
+
wingspan play --p0 random --p1 random --p2 random --html game.html # 3-seat random game, HTML log
|
|
122
|
+
wingspan play --p0 best --p1 best --jsonl game.jsonl # flat structured log, for analysis
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
A `human` seat gets a numbered menu for every choice the rules require — pick a
|
|
126
|
+
bird, choose a habitat, pay food, lay eggs, and so on. When a seat is
|
|
127
|
+
AI-driven, every genuine decision is annotated in the game log with the
|
|
128
|
+
policy's ranked probability distribution over the legal options, turning the
|
|
129
|
+
log into a move-by-move readout of what the network was "thinking", and
|
|
130
|
+
`--greedy` makes AI seats take the argmax option instead of sampling. `--games
|
|
131
|
+
N` plays a series (game *i* deals with `--seed + i`), `--log` writes a
|
|
132
|
+
structured plaintext game log per game (sourced from the event tree — the
|
|
133
|
+
same log the `--jsonl` and `--html` outputs are built from), and `--quiet`
|
|
134
|
+
suppresses the per-game summary. For the older raw `engine.log` dump, use
|
|
135
|
+
`--debug-log FILE` instead; by default it splits into `FILE_p0.log` /
|
|
136
|
+
`FILE_p1.log` (one file per seat), or pass `--collate` for a single
|
|
137
|
+
interleaved file. `--device` selects the torch device AI seats run
|
|
138
|
+
inference on (`cpu` by default). `--html FILE` additionally writes a
|
|
139
|
+
self-contained HTML viewer that replays the
|
|
140
|
+
game one phase/turn at a time — prev/next arrows, a per-seat view toggle
|
|
141
|
+
(`P0 / Both / P1` at 2 seats, `All / P0 / P1 / ...` at 3+ seats), 3x5 board
|
|
142
|
+
grids pinned at the top, and a collapsible decision log beneath (for a
|
|
143
|
+
`--games` series the game index is inserted before the extension, `game.html ->
|
|
144
|
+
game.0.html`). The **Timeline** modal (opened via the toolbar button) shows
|
|
145
|
+
per-seat score lines and per-seat critic/target return lines; it includes a
|
|
146
|
+
**⬇ CSV** download link that yields one row per in-game decision with columns
|
|
147
|
+
for timestamp, player, per-seat scores, and per-seat critic/target values
|
|
148
|
+
(each seat's own future-return margin vs its best other seat, in VP — not
|
|
149
|
+
projected onto any other seat's axis).
|
|
150
|
+
|
|
151
|
+
### The flat structured log
|
|
152
|
+
|
|
153
|
+
`--jsonl FILE` writes the same game as data: one JSON object per line — a header
|
|
154
|
+
row per match, then one row per event and sub-event. Every state change the
|
|
155
|
+
engine made is there with its own typed columns (`card`, `food`, `amount`,
|
|
156
|
+
`bird`, `habitat`), each event row carries the same at-a-glance header the HTML
|
|
157
|
+
viewer shows, and the tree's nesting survives as `event_id` / `parent_id` /
|
|
158
|
+
`depth` columns. Unlike `--log`, a `--games` series appends to the *one* file,
|
|
159
|
+
keyed by `game_id`.
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
import pandas
|
|
163
|
+
|
|
164
|
+
rows = pandas.read_json("game.jsonl", lines=True)
|
|
165
|
+
rows[rows.kind == "lay_egg"].groupby("player_id")["count"].sum()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`wingspan tournament --jsonl games.jsonl` does the same for every game of a
|
|
169
|
+
round-robin. See [`docs/GAMELOG.md`](docs/GAMELOG.md) for the full row schema.
|
|
170
|
+
|
|
171
|
+
## Train an agent
|
|
172
|
+
|
|
173
|
+
The training app is **FLIGHT PLAN** — a full-screen TUI that opens on a
|
|
174
|
+
configuration screen first, then transitions to a live `top`-style dashboard
|
|
175
|
+
once a run is started or resumed:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
wingspan dashboard # open FLIGHT PLAN (always starts in config)
|
|
179
|
+
wingspan dashboard --collect-device cpu --train-device cuda # CPU pool feeding a GPU learner
|
|
180
|
+
wingspan dashboard --train-device cpu # CPU-only
|
|
181
|
+
wingspan dashboard --games-per-iter 256 --eval-every 5 --eval-games 128
|
|
182
|
+
wingspan dashboard --config runs/my_run.json # open the config screen seeded from FILE
|
|
183
|
+
wingspan dashboard --config runs/my_run.json --start # skip the screen and launch immediately
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`--config FILE` supplies the whole run config from a file instead of building
|
|
187
|
+
it from flags — a dated `run_config_<stamp>.json` artifact, a
|
|
188
|
+
`configurator_defaults.json`-style envelope, a cloud run-file's `train:`
|
|
189
|
+
block, or a bare `RunConfig` JSON/YAML dump (see
|
|
190
|
+
`wingspan.training.config_file`). Only the five run-identity flags
|
|
191
|
+
(`--checkpoint-dir`, `--run-name`, `--collect-device`, `--train-device`,
|
|
192
|
+
`--resume`/`--no-resume`) may be combined with `--config` to override the
|
|
193
|
+
file; any other flag is a usage error, since the file already speaks for
|
|
194
|
+
every other field. Without `--start` the config screen still opens, seeded
|
|
195
|
+
from the file, so you can review or tweak it before pressing Start; with
|
|
196
|
+
`--start` the run launches immediately and headlessly — it never archives or
|
|
197
|
+
overwrites an existing run on its own, so an incompatible or resume-disabled
|
|
198
|
+
checkpoint directory is refused with a message pointing you at the config
|
|
199
|
+
screen's archive action instead.
|
|
200
|
+
|
|
201
|
+
The config screen lets you tune every hyperparameter (learning rate,
|
|
202
|
+
games/iteration, evaluation cadence, target-iteration milestone, network
|
|
203
|
+
width, …) and manage the runs already in the checkpoint directory. Arrow keys
|
|
204
|
+
move between fields, ←/→ nudge a value (or cycle a choice), and Enter edits
|
|
205
|
+
one directly; every value is validated as you type. The screen shows whether
|
|
206
|
+
the directory holds a resumable run and flags which edits would force a fresh
|
|
207
|
+
start (changing the network width can't reuse old weights). From there:
|
|
208
|
+
|
|
209
|
+
- **Start** resumes a compatible run, or starts a fresh one in an empty
|
|
210
|
+
directory.
|
|
211
|
+
- **New run** (or starting after an incompatible edit) prompts you to
|
|
212
|
+
**archive** the existing run to `checkpoints/archive/<label>/` — preserving
|
|
213
|
+
its checkpoints, metrics, and log — before the new run begins, so a long
|
|
214
|
+
training run is never silently overwritten.
|
|
215
|
+
|
|
216
|
+
Once started, the dashboard runs until you press **Ctrl+C**, which asks it to
|
|
217
|
+
finish the current game, save a final checkpoint, and print a summary. As
|
|
218
|
+
strength improves the evaluation opponent advances from the random agent to
|
|
219
|
+
frozen past selves (a self-play ladder). Checkpoints (`last.pt`, `best.pt`, the
|
|
220
|
+
frozen `opponent.pt`), a per-iteration `metrics.jsonl`, and a per-game
|
|
221
|
+
`games.jsonl` are written to the checkpoint directory (`checkpoints/` by
|
|
222
|
+
default; change with `--checkpoint-dir`), and runs are resumable. Pass
|
|
223
|
+
`--iterations N` to stop automatically after N rounds instead.
|
|
224
|
+
|
|
225
|
+
You can also set a **target-iteration** milestone (in the config screen):
|
|
226
|
+
the run pauses there, runs a large fixed-model self-play evaluation, and waits
|
|
227
|
+
for you to **[C]ontinue** — optionally entering a new target — or **[E]nd** the
|
|
228
|
+
run and return to the config screen.
|
|
229
|
+
|
|
230
|
+
See [docs/TRAINING.md](docs/TRAINING.md) for the training program and
|
|
231
|
+
[docs/DECISIONS.md](docs/DECISIONS.md) for the per-decision modelling direction.
|
|
232
|
+
|
|
233
|
+
## Run a tournament
|
|
234
|
+
|
|
235
|
+
`wingspan tournament` runs a round-robin between any mix of trained AIs and the
|
|
236
|
+
random agent, tracks Elo ratings, and writes a JSON report.
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
wingspan tournament # interactive picker (default)
|
|
240
|
+
wingspan tournament --base-dir checkpoints # picker scans a different dir
|
|
241
|
+
wingspan tournament --no-picker --ai runs/exp1 --ai runs/exp2 # skip picker; explicit dirs
|
|
242
|
+
wingspan tournament --no-picker --ai runs/exp1 --include-random # add the random agent
|
|
243
|
+
wingspan tournament --no-picker --ai runs/exp1 --ai runs/exp2 \
|
|
244
|
+
--games-per-pair 64 --out results.json # 64 mirrored games per pair
|
|
245
|
+
wingspan tournament --quiet # no live UI; periodic progress only
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
By default an interactive picker scans `checkpoints/` and lets you choose
|
|
249
|
+
competitors with arrow keys. Pass `--no-picker` to specify them via `--ai
|
|
250
|
+
<checkpoint-dir>` flags (repeatable) and optionally `--include-random`. Each
|
|
251
|
+
pair plays `--games-per-pair` games (default 32) as mirrored deals. The live
|
|
252
|
+
dashboard (skipped with `--quiet`) shows Elo ratings and W-L-T updating as
|
|
253
|
+
games finish; **q** / Ctrl+C stops after the current games complete. The final
|
|
254
|
+
standings and the full JSON report are written to `--out`
|
|
255
|
+
(`tournament_report.json` by default).
|
|
256
|
+
|
|
257
|
+
The tournament is **2-seat only for now**: N-seat scheduling and Elo are
|
|
258
|
+
deferred scope, so a checkpoint trained at `num_players != 2` is refused with
|
|
259
|
+
a clear error rather than being silently seated. 3-4 player checkpoints still
|
|
260
|
+
play fine through `wingspan play`; only the round-robin tournament format is
|
|
261
|
+
restricted.
|
|
262
|
+
|
|
263
|
+
## Get live advice for a physical game
|
|
264
|
+
|
|
265
|
+
`wingspan aid` is a live assistant for a 2-player game played at a physical
|
|
266
|
+
table, not on the computer. It runs a terminal session that starts at game
|
|
267
|
+
setup — you enter your dealt hand, bonus cards, round goals, the initial
|
|
268
|
+
tray, and the feeder roll — and a trained model then ranks your options for
|
|
269
|
+
every decision you make for the rest of the game, showing its top picks and
|
|
270
|
+
expected VP margin before you confirm what you actually played:
|
|
271
|
+
|
|
272
|
+
```
|
|
273
|
+
wingspan aid # advise with the latest trained model
|
|
274
|
+
wingspan aid best --seed 42 # advise with the strongest checkpoint
|
|
275
|
+
wingspan aid --log session.log --jsonl session.jsonl # write session logs
|
|
276
|
+
wingspan aid --trust-me # auto-play the model's picks for your seat
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
In a real terminal, card prompts are type-to-filter pickers (type a few
|
|
280
|
+
letters to narrow the list, arrows + Enter to select; Enter on an empty
|
|
281
|
+
query marks a revealed card as face-down where that's allowed) and dice are
|
|
282
|
+
entered as per-face counts (arrows to move between faces and adjust, Enter
|
|
283
|
+
to accept once the total matches). When stdio is scripted or redirected the
|
|
284
|
+
same prompts fall back to plain text: comma-separated card names and
|
|
285
|
+
space-separated die faces.
|
|
286
|
+
|
|
287
|
+
The opponent's moves are relayed by you as they happen — the assistant asks
|
|
288
|
+
"what did they do?" for each of their decisions and tracks their hand and
|
|
289
|
+
bonus cards as hidden counts (never guessing their identities), matching
|
|
290
|
+
what the encoder itself is allowed to see. At the end of the final round it
|
|
291
|
+
offers to enter the opponent's bonus card(s) for exact scoring; skipping
|
|
292
|
+
that leaves their bonus VP as a placeholder to count manually. Only
|
|
293
|
+
checkpoints trained at `num_players=2` can drive the advisor seat, and a
|
|
294
|
+
session runs setup-to-end with no mid-game entry or undo.
|
|
295
|
+
|
|
296
|
+
Pass `--trust-me` to skip confirming your own moves: the model's top pick is
|
|
297
|
+
committed automatically for your seat, so you only sit through setup entry,
|
|
298
|
+
oracle reveals/dice, and relaying the opponent's moves — the recommendation
|
|
299
|
+
display still prints first, since under `--trust-me` it's what tells you
|
|
300
|
+
which move to actually execute at the table.
|
|
301
|
+
|
|
302
|
+
## Run a research study
|
|
303
|
+
|
|
304
|
+
`wingspan research` hosts the offline, fixed-model studies from
|
|
305
|
+
[docs/RESEARCH.md](docs/RESEARCH.md). The first is the setup keep-rate
|
|
306
|
+
**experience study**: it deals random setups, asks the run's setup model which
|
|
307
|
+
birds it keeps, and writes one CSV row per dealt bird (an *exposure*) with a
|
|
308
|
+
0/1 `kept` flag (the *observation*), so a card's keep rate is
|
|
309
|
+
`sum(kept) / count(rows)` and pivots by any other column.
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
wingspan research setup-keep # 1000 setups from checkpoints/ -> setup_keep.csv
|
|
313
|
+
wingspan research setup-keep --setups 20000 --workers 8 # fan the deals across 8 processes
|
|
314
|
+
wingspan research setup-keep --checkpoint-dir runs/exp1 --out exp1_keep.csv
|
|
315
|
+
wingspan research setup-keep --temperature 1.0 # sample the keep instead of taking the argmax
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Each setup is one seat of a fresh seeded game dealt exactly as the engine deals
|
|
319
|
+
it (tray, feeder roll, round goals, five birds, two bonus cards); games use
|
|
320
|
+
consecutive seeds from `--seed`, so a study can be extended by continuing the
|
|
321
|
+
range, and the CSV is identical whether it ran in-process or under `--workers`.
|
|
322
|
+
Every row carries the exposure key (`setup_id`, `game_seed`, `seat`,
|
|
323
|
+
`card_slot`), the observation (`kept`, the policy's marginal `keep_prob`,
|
|
324
|
+
`n_kept`, the critic's `deal_value`, `bonus_kept`), the card's printed
|
|
325
|
+
attributes (points, egg limit, wingspan, nest, power color, habitats, per-food
|
|
326
|
+
cost, flocking/predator, effect kinds), and the rest of the setup (`hand`,
|
|
327
|
+
`tray_1..3`, the six `feeder_*` die counts, `goal_1..4` with categories,
|
|
328
|
+
`bonus_1`/`bonus_2`). The seat count defaults to the run's trained
|
|
329
|
+
`num_players`; the run must have trained a setup model (`setup.pt`).
|
|
330
|
+
|
|
331
|
+
The second is the **game-stats study**: greedy self-play of one run's model
|
|
332
|
+
against itself (its setup net resolves the opening keep), capturing one CSV row
|
|
333
|
+
per seat per game — the score after every turn (0–26, in both a projected and a
|
|
334
|
+
locked-in round-goal convention), the main action chosen on every turn, the
|
|
335
|
+
winner/tie, and the six-way final score breakdown. Alongside the raw table it
|
|
336
|
+
writes chart-ready aggregates (per-turn mean/CI/percentile score curves and
|
|
337
|
+
action frequencies for all vs. won games, the category breakdown as CSV and
|
|
338
|
+
markdown, paired final scores per game) plus a self-contained `preview.html`.
|
|
339
|
+
With `--blog-snippets` it also writes `blog_snippets/` — one ready-to-paste
|
|
340
|
+
Plotly embed block per figure for a markdown blog post (the scattergram
|
|
341
|
+
subsampled to keep the page light), plus the pinned CDN `<script>` tag.
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
wingspan research game-stats --out stats/ # 10k games from checkpoints/last.pt
|
|
345
|
+
wingspan research game-stats --games 100000 --workers 10 --out stats/
|
|
346
|
+
wingspan research game-stats --aggregate-only stats/games_raw.csv --out stats/ --blog-snippets
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Probe a model's architecture
|
|
350
|
+
|
|
351
|
+
`wingspan analysis probe` measures how much each part of a trained network's
|
|
352
|
+
architecture actually matters: it self-plays a sample of on-distribution
|
|
353
|
+
decisions, then reports board-attention behavior and ablation sensitivity
|
|
354
|
+
(zero / uniform / per-head knockout, scored by policy KL and value shift),
|
|
355
|
+
trunk and choice-encoder layer capacity (effective rank, linear
|
|
356
|
+
predictability, dead units), and which trunk input groups the network reads
|
|
357
|
+
from.
|
|
358
|
+
|
|
359
|
+
```
|
|
360
|
+
wingspan analysis probe last --games 50 --reference best # probe the latest checkpoint, compare against best.pt
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
See `docs/TRAINING.md` "Representation diagnostics" for how to read the
|
|
364
|
+
numbers and `src/wingspan/analysis/INDEX.md` for the package's caveats.
|
|
365
|
+
|
|
366
|
+
## Review a finished run
|
|
367
|
+
|
|
368
|
+
`training_summary.html` is a standalone, interactive HTML page charting a
|
|
369
|
+
run's `metrics.jsonl` progression end to end: strength vs. the reference
|
|
370
|
+
opponent, score composition, loss curves, throughput, and — when the run used
|
|
371
|
+
them — the setup-model and architecture-probe readouts. Every chart is a
|
|
372
|
+
`Plotly.js` chart (pan/zoom/hover), unlike the live dashboard's fixed-size
|
|
373
|
+
terminal charts.
|
|
374
|
+
|
|
375
|
+
The page is written automatically at the target milestone, alongside
|
|
376
|
+
`final_eval_<n>.json`, and can be regenerated on demand for any run directory
|
|
377
|
+
with `wingspan summary [RUN_DIR] [--out FILE]` (`RUN_DIR` defaults to
|
|
378
|
+
`checkpoints`). Because the charts load Plotly from its CDN
|
|
379
|
+
(`cdn.plot.ly`), viewing the page needs internet access.
|
|
380
|
+
|
|
381
|
+
## Installed commands
|
|
382
|
+
|
|
383
|
+
After `pip install -e .` all tools are available through a single `wingspan`
|
|
384
|
+
command with subcommands:
|
|
385
|
+
|
|
386
|
+
| Command | What it does |
|
|
387
|
+
| ----------------------- | ------------------------------------------------------- |
|
|
388
|
+
| `wingspan play` | Games between any mix of human, random, and AI seats |
|
|
389
|
+
| `wingspan aid` | Live assistant for a physical 2-player game |
|
|
390
|
+
| `wingspan dashboard` | FLIGHT PLAN: config screen → live training dashboard |
|
|
391
|
+
| `wingspan tournament` | Round-robin tournament between trained AIs |
|
|
392
|
+
| `wingspan inspect` | Model introspection report (vectors, architecture, params) |
|
|
393
|
+
| `wingspan summary` | Training-progression HTML report for a run directory |
|
|
394
|
+
| `wingspan cloud` | Headless S3-persisted training (container use) |
|
|
395
|
+
| `wingspan monitor` | FLOCK WATCH: live roster of cloud runs |
|
|
396
|
+
| `wingspan research` | Offline research studies (setup keep-rate, game-stats) |
|
|
397
|
+
| `wingspan analysis` | Architecture-importance probe over a trained checkpoint |
|
|
398
|
+
|
|
399
|
+
Run `wingspan --help` for the full list, or `wingspan <command> --help` for
|
|
400
|
+
per-command usage.
|
|
401
|
+
|
|
402
|
+
## Tests
|
|
403
|
+
|
|
404
|
+
Run the full quality gate (pyright + isort + black + pytest):
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
bash scripts/quality_gate.sh
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
See `CLAUDE.md` for the gate's section flags and pass-through argument reference.
|
|
411
|
+
|
|
412
|
+
## Further reading
|
|
413
|
+
|
|
414
|
+
| File | What it covers |
|
|
415
|
+
| ---- | -------------- |
|
|
416
|
+
| [docs/PROJECT.md](docs/PROJECT.md) | Full package layout and what's modelled |
|
|
417
|
+
| [docs/DECISIONS.md](docs/DECISIONS.md) | Decision/choice taxonomy, `ALL_DECISION_CLASSES` ordering, featurization |
|
|
418
|
+
| [docs/BIRDS.md](docs/BIRDS.md) | Every bird power: `EffectKind` patterns, handler mappings, implementation gaps |
|
|
419
|
+
| [docs/TRAINING.md](docs/TRAINING.md) | Training program, hyperparameter guidance, eval ladder |
|
|
420
|
+
| [docs/RESEARCH.md](docs/RESEARCH.md) | Research agenda, per-project feasibility analysis |
|