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