Initial Rust CLI/TUI Rebuild (Seeded Sim + CSV Export)
This commit is contained in:
parent
faf0929bb6
commit
dae34cce41
16 changed files with 2739 additions and 0 deletions
135
src/main.rs
Normal file
135
src/main.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
mod app;
|
||||
mod data;
|
||||
mod export;
|
||||
mod instance;
|
||||
mod sim;
|
||||
mod ui;
|
||||
mod utils;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
|
||||
use app::{run_tui, App, Speed};
|
||||
use data::{display_name, TEAMS};
|
||||
use export::simulation_to_csv_bytes;
|
||||
use sim::{run_simulation, SimulationType};
|
||||
use utils::{derive_seed, Rng};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "soccercloud")]
|
||||
#[command(about = "MentalNet SoccerCloud - Rust CLI/TUI simulator")]
|
||||
struct Cli {
|
||||
#[arg(long, global = true)]
|
||||
seed: Option<u64>,
|
||||
|
||||
#[arg(long, global = true, value_enum, default_value_t = Speed::X1)]
|
||||
speed: Speed,
|
||||
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
Quick {
|
||||
#[arg(long)]
|
||||
home: String,
|
||||
#[arg(long)]
|
||||
away: String,
|
||||
},
|
||||
List,
|
||||
Export {
|
||||
#[arg(long, value_enum)]
|
||||
mode: ModeArg,
|
||||
#[arg(long)]
|
||||
out: String,
|
||||
#[arg(long = "team", required = true)]
|
||||
teams: Vec<String>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
enum ModeArg {
|
||||
Single,
|
||||
League4,
|
||||
Knockout4,
|
||||
}
|
||||
|
||||
impl From<ModeArg> for SimulationType {
|
||||
fn from(value: ModeArg) -> Self {
|
||||
match value {
|
||||
ModeArg::Single => SimulationType::Single,
|
||||
ModeArg::League4 => SimulationType::League4,
|
||||
ModeArg::Knockout4 => SimulationType::Knockout4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let cli = Cli::parse();
|
||||
let base_seed = cli.seed.unwrap_or_else(|| Rng::from_time().next_u64());
|
||||
|
||||
match cli.command {
|
||||
None => {
|
||||
let app = App::new(base_seed, cli.speed);
|
||||
run_tui(app)
|
||||
}
|
||||
Some(Commands::Quick { home, away }) => {
|
||||
quick_mode(&home, &away, base_seed);
|
||||
Ok(())
|
||||
}
|
||||
Some(Commands::List) => {
|
||||
for team in TEAMS {
|
||||
println!("{}", display_name(team));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Some(Commands::Export { mode, out, teams }) => export_mode(mode, out, teams, base_seed),
|
||||
}
|
||||
}
|
||||
|
||||
fn quick_mode(home: &str, away: &str, base_seed: u64) {
|
||||
let teams = vec![home.to_string(), away.to_string()];
|
||||
let seed = derive_seed(base_seed, 1);
|
||||
let mut rng = Rng::new(seed);
|
||||
let prepared = run_simulation(SimulationType::Single, &teams, &mut rng);
|
||||
|
||||
println!("seed={seed}");
|
||||
if let sim::SimOutcome::Single(m) = prepared.outcome {
|
||||
println!("{} {}-{} {}", m.home, m.home_goals, m.away_goals, m.away);
|
||||
println!("xG {:.2} - {:.2}", m.stats.home.xg, m.stats.away.xg);
|
||||
}
|
||||
|
||||
println!("-- log --");
|
||||
for frame in prepared.frames {
|
||||
for line in frame.logs {
|
||||
println!("{}", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn export_mode(mode: ModeArg, out: String, teams: Vec<String>, base_seed: u64) -> io::Result<()> {
|
||||
let required = match mode {
|
||||
ModeArg::Single => 2,
|
||||
ModeArg::League4 | ModeArg::Knockout4 => 4,
|
||||
};
|
||||
if teams.len() != required {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!(
|
||||
"mode {:?} requires exactly {} --team values",
|
||||
mode, required
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let mut rng = Rng::new(derive_seed(base_seed, 1));
|
||||
let prepared = run_simulation(mode.into(), &teams, &mut rng);
|
||||
let bytes = simulation_to_csv_bytes(&prepared)?;
|
||||
let mut f = File::create(&out)?;
|
||||
f.write_all(&bytes)?;
|
||||
println!("Wrote {}", out);
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue