robot_master/config.rs
1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand};
4use robot_master_arena::{BoardSize, config::ArenaConfig};
5use v_utils::macros as v_macros;
6
7#[derive(Parser)]
8#[command(author, version = concat!(env!("CARGO_PKG_VERSION"), " (", env!("GIT_HASH"), ")"), about, long_about = None)]
9pub struct Cli {
10 #[clap(flatten)]
11 pub settings_flags: SettingsFlags,
12 #[clap(flatten)]
13 pub players: PlayerArgs,
14 #[command(subcommand)]
15 pub command: Commands,
16}
17#[derive(Clone, Debug, Parser)]
18pub struct PlayerArgs {
19 /// Player 1 (Cols) algorithm: manual/m, random/r, greedy/g, sadist/s
20 #[arg(short = 'a', long, default_value = "manual")]
21 pub player1: String,
22 /// Player 2 (Rows) algorithm: manual/m, random/r, greedy/g, sadist/s
23 #[arg(short = 'b', long, default_value = "random")]
24 pub player2: String,
25 /// Board size (5, 7, 9, or 11)
26 #[arg(short = 's', long, default_value = "5")]
27 pub size: BoardSize,
28 /// Hide opponent's hand (information-hidden mode)
29 #[arg(long, default_value = "false")]
30 pub hide: bool,
31 /// Directory containing .onnx model files
32 #[arg(long, default_value = "./models")]
33 pub models_dir: PathBuf,
34}
35#[derive(Clone, Debug, Parser)]
36pub struct TrainArgs {
37 /// Include the git hash in the run ID (fully pins to exact build; fragments cache across commits)
38 #[arg(long)]
39 pub exact_generation: bool,
40 /// Number of selfplay → train → export iterations
41 #[arg(long, default_value = "20")]
42 pub iterations: u32,
43 /// Self-play games per iteration
44 #[arg(long, default_value = "200")]
45 pub games: u32,
46 /// Gumbel simulations per move during self-play
47 #[arg(long, default_value = "64")]
48 pub sims: u32,
49 /// Board size (must match the selfplay binary and model architecture)
50 #[arg(long, default_value = "5")]
51 pub size: u32,
52 /// Pass --force-cpu to selfplay (sequential rayon, faster at 5×5/7×7).
53 #[arg(long)]
54 pub force_cpu: bool,
55 /// Hide opponent's hand (information-hidden mode).
56 #[arg(long)]
57 pub hide: bool,
58}
59#[derive(Subcommand)]
60pub enum Commands {
61 /// Play the game in the terminal
62 Tui,
63 /// Play the game with a graphical interface
64 Gui {
65 /// Enable music and sound effects
66 #[arg(long, default_value = "false")]
67 sound: bool,
68 },
69 /// Arena: tournaments and data management
70 Arena {
71 /// Filter players by grepping these patterns against known IDs. If empty, all players.
72 #[arg(short, long, value_delimiter = ',')]
73 select: Vec<String>,
74 /// Run an ephemeral tournament with these player specs (e.g. `rollout|v50 rollout|g200`).
75 /// Bypasses the ratings database entirely - no prior ratings loaded, nothing saved.
76 /// Mutually exclusive with --select.
77 #[arg(long, value_delimiter = ',')]
78 no_priors: Vec<String>,
79 #[command(subcommand)]
80 command: ArenaCommands,
81 },
82 /// Train a neural network model (AlphaZero selfplay → train → export loop)
83 Train {
84 #[command(subcommand)]
85 arch: TrainArch,
86 },
87 //DO: `site` command that starts the leptos server
88}
89
90#[derive(Subcommand)]
91pub enum TrainArch {
92 /// ResNet CNN architecture
93 Cnn {
94 #[clap(flatten)]
95 args: TrainArgs,
96 /// Supervised pre-training spec (e.g. `rollout|v50`). Controls both:
97 /// selfplay data generation (uses this bot until NN beats it >68% over 32 games),
98 /// and eval matches run every 10 versions to detect the threshold.
99 /// If omitted, starts NN selfplay immediately with no eval.
100 #[arg(long)]
101 supervise: Option<String>,
102 },
103 /// Transformer architecture
104 Transformer {
105 #[clap(flatten)]
106 args: TrainArgs,
107 },
108}
109
110#[derive(Subcommand)]
111pub enum ArenaCommands {
112 /// Run a tournament
113 Tourney {
114 #[command(subcommand)]
115 mode: TourneyMode,
116 /// Output results as JSON to stdout (progress and status remain on stderr).
117 #[arg(long)]
118 json: bool,
119 },
120 /// Player data management
121 Players {
122 #[command(subcommand)]
123 command: PlayersCommands,
124 },
125}
126
127#[derive(Subcommand)]
128pub enum TourneyMode {
129 /// True FIDE Swiss: 1 game/pairing, pair within score groups, runs N full brackets
130 Swiss {
131 /// Number of full Swiss brackets to run
132 #[arg(default_value = "10")]
133 cycles: usize,
134 /// Number of threads (0 = all cores)
135 #[arg(short, long, default_value = "0")]
136 threads: usize,
137 },
138 /// Rating-based: weighted-random pairing by ELO proximity, ceil(target_rounds / threads) cycles
139 Rating {
140 /// Total games to play (split across cycles of `threads` games each)
141 #[arg(default_value = "100")]
142 target_rounds: usize,
143 /// Number of threads (0 = all cores)
144 #[arg(short, long, default_value = "0")]
145 threads: usize,
146 },
147 /// Single-elimination: pair by ELO proximity, winners advance, repeat for N cycles
148 Elimination {
149 /// Number of full elimination brackets to run
150 #[arg(default_value = "10")]
151 cycles: usize,
152 /// Number of threads (0 = all cores)
153 #[arg(short, long, default_value = "0")]
154 threads: usize,
155 },
156 /// Round-robin: every player plays every other exactly once per sweep, repeat for N sweeps
157 RoundRobin {
158 /// Number of full round-robin sweeps to run
159 #[arg(default_value = "3")]
160 cycles: usize,
161 /// Number of threads (0 = all cores)
162 #[arg(short, long, default_value = "0")]
163 threads: usize,
164 },
165}
166
167#[derive(Subcommand)]
168pub enum PlayersCommands {
169 /// Register player algorithms (e.g. `rollout|800`, `random`, `onnx:model_v5|g200|s5|hh`). Also auto-registers any missing default variants.
170 New {
171 /// Player specs: algo names with optional sim counts (e.g. `rollout|800`, `greedy`, `onnx:model_v5|g400`)
172 players: Vec<String>,
173 /// Constrain to specific board sizes, e.g. `5,7`. Required for onnx bots; ignored for rule-based bots.
174 #[arg(long, value_delimiter = ',')]
175 sizes: Vec<u8>,
176 /// Constrain to a specific hide mode. Optional; omit to support both modes.
177 #[arg(long)]
178 hide: Option<bool>,
179 },
180 /// List all players and their ratings
181 List,
182 /// Reset ratings to default (all if no players filter, otherwise only matched)
183 ResetRatings,
184 /// Remove players from the database entirely
185 Nuke,
186}
187
188#[derive(Clone, Debug, Default, v_macros::LiveSettings, v_macros::MyConfigPrimitives, v_macros::Settings)]
189pub struct Config {
190 #[serde(default)]
191 pub arena: ArenaConfig,
192}