use std::{
collections::HashMap,
fs::File,
io::{self, BufRead, BufReader, Write},
process::ExitCode,
str::FromStr,
};
use pns::{Net, State, Tid};
fn main() -> ExitCode {
let mut save = false;
let mut load = false;
let mut args = std::env::args();
args.next();
for arg in args {
match arg.as_ref() {
"save" => save = true,
"load" => load = true,
_ => eprintln!("Ignore invalid argument '{arg}'"),
}
}
let Ok(net) = Net::load("pns/examples/example.pn".as_ref()) else {
eprintln!("Failed to load example net");
return ExitCode::FAILURE;
};
let mut names = HashMap::new();
let Ok(file) = File::open("pns/examples/example.pnk") else {
eprintln!("Failed to load example keys");
return ExitCode::FAILURE;
};
for (tid, line) in net.transition_ids().zip(BufReader::new(file).lines()) {
let Ok(line) = line else {
eprintln!("Failed to read key");
return ExitCode::FAILURE;
};
names.insert(tid, line);
}
if save && net.save("examples/example_copy.pns".as_ref()).is_err() {
eprintln!("Failed to save example net");
}
let mut state = if load {
let Ok(state) = State::load(&net, "examples/example.pns".as_ref()) else {
eprintln!("Loading state failed");
return ExitCode::FAILURE;
};
state
} else {
State::new(&net)
};
let mut forward = true;
loop {
let fireable = if forward {
state.fireable()
} else {
state.unfireable()
};
if fireable.is_empty() {
println!("Reverse play direction!");
println!();
forward = !forward;
continue;
}
println!("Choose a transition:");
let fireable: Vec<Tid> = fireable.collect();
for (i, tid) in fireable.iter().enumerate() {
println!("{}: {}", i + 1, names[tid]);
}
print!("> ");
let _ = io::stdout().flush();
let stdin = io::stdin();
let mut string = String::new();
let Ok(size) = stdin.read_line(&mut string) else {
eprintln!("Input error");
continue;
};
println!();
if size <= 1 {
continue;
}
match unsafe { string.chars().next().unwrap_unchecked() } {
'r' => {
println!("Reverse play direction!");
println!();
forward = !forward;
continue;
}
'q' => break,
's' => {
let result = if unsafe { state.save(&net, "examples/example.pns".as_ref()).is_ok() }
{
"successful"
} else {
"failed"
};
println!("Saving state {result}",);
println!();
continue;
}
_ => (),
}
match usize::from_str(&string[..(string.len() - 1)]) {
Ok(num) if num != 0 && num <= fireable.len() => {
let tid = fireable[num - 1];
if forward {
unsafe { state.fire_unchecked(&net, tid) }
} else {
unsafe { state.unfire_unchecked(&net, tid) }
}
}
_ => {
println!(
"You have to input a valid number from 1 to {}",
fireable.len()
);
println!();
println!("Other options:");
println!("q: Quit");
println!("r: Reverse play direction");
println!("s: Save");
println!();
}
}
}
ExitCode::SUCCESS
}