1use std::{
2 collections::HashMap,
3 fs::File,
4 io::{self, BufRead, BufReader, Write},
5 process::ExitCode,
6 str::FromStr,
7};
8
9use pns::{Net, State, Tid};
10
11fn main() -> ExitCode {
12 let mut save = false;
13 let mut load = false;
14
15 let mut args = std::env::args();
16 args.next();
17 for arg in args {
18 match arg.as_ref() {
19 "save" => save = true,
20 "load" => load = true,
21 _ => eprintln!("Ignore invalid argument '{arg}'"),
22 }
23 }
24
25 let Ok(net) = Net::load("pns/examples/example.pn".as_ref()) else {
26 eprintln!("Failed to load example net");
27 return ExitCode::FAILURE;
28 };
29
30 let mut names = HashMap::new();
31 let Ok(file) = File::open("pns/examples/example.pnk") else {
32 eprintln!("Failed to load example keys");
33 return ExitCode::FAILURE;
34 };
35 for (tid, line) in net.transition_ids().zip(BufReader::new(file).lines()) {
36 let Ok(line) = line else {
37 eprintln!("Failed to read key");
38 return ExitCode::FAILURE;
39 };
40 names.insert(tid, line);
41 }
42
43 if save && net.save("examples/example_copy.pns".as_ref()).is_err() {
44 eprintln!("Failed to save example net");
45 }
46
47 let mut state = if load {
48 let Ok(state) = State::load(&net, "examples/example.pns".as_ref()) else {
49 eprintln!("Loading state failed");
50 return ExitCode::FAILURE;
51 };
52 state
53 } else {
54 State::new(&net)
55 };
56
57 let mut forward = true;
58
59 loop {
60 let fireable = if forward {
61 state.fireable()
62 } else {
63 state.unfireable()
64 };
65
66 if fireable.is_empty() {
67 println!("Reverse play direction!");
68 println!();
69 forward = !forward;
70 continue;
71 }
72
73 println!("Choose a transition:");
74 let fireable: Vec<Tid> = fireable.collect();
75 for (i, tid) in fireable.iter().enumerate() {
76 println!("{}: {}", i + 1, names[tid]);
77 }
78 print!("> ");
79 let _ = io::stdout().flush();
80 let stdin = io::stdin();
81 let mut string = String::new();
82 let Ok(size) = stdin.read_line(&mut string) else {
83 eprintln!("Input error");
84 continue;
85 };
86 println!();
87 if size <= 1 {
88 continue;
89 }
90 match unsafe { string.chars().next().unwrap_unchecked() } {
91 'r' => {
92 println!("Reverse play direction!");
93 println!();
94 forward = !forward;
95 continue;
96 }
97 'q' => break,
98 's' => {
99 let result = if unsafe { state.save(&net, "examples/example.pns".as_ref()).is_ok() }
100 {
101 "successful"
102 } else {
103 "failed"
104 };
105
106 println!("Saving state {result}",);
107 println!();
108
109 continue;
110 }
111 _ => (),
112 }
113 match usize::from_str(&string[..(string.len() - 1)]) {
114 Ok(num) if num != 0 && num <= fireable.len() => {
115 let tid = fireable[num - 1];
116 if forward {
117 unsafe { state.fire_unchecked(&net, tid) }
118 } else {
119 unsafe { state.unfire_unchecked(&net, tid) }
120 }
121 }
122 _ => {
123 println!(
124 "You have to input a valid number from 1 to {}",
125 fireable.len()
126 );
127 println!();
128 println!("Other options:");
129 println!("q: Quit");
130 println!("r: Reverse play direction");
131 println!("s: Save");
132 println!();
133 }
134 }
135 }
136
137 ExitCode::SUCCESS
138}