rbp_server/analysis/
cli.rs1use super::*;
5use clap::Parser;
6use rbp_cards::*;
7use rbp_gameplay::*;
8use std::io::Write;
9
10pub struct CLI(API);
11
12impl From<API> for CLI {
13 fn from(api: API) -> Self {
14 Self(api)
15 }
16}
17
18impl CLI {
19 pub async fn run() -> () {
20 log::info!("entering analysis");
21 let cli = Self(API::from(rbp_database::db().await));
22 loop {
23 print!("> ");
24 let ref mut input = String::new();
25 std::io::stdout().flush().unwrap();
26 std::io::stdin().read_line(input).unwrap();
27 match input.trim() {
28 "quit" => break,
29 "exit" => break,
30 _ => match cli.handle(input).await {
31 Err(e) => eprintln!("{}", e),
32 Ok(_) => continue,
33 },
34 }
35 }
36 }
37 async fn handle(&self, input: &str) -> Result<(), Box<dyn std::error::Error>> {
38 match Query::try_parse_from(std::iter::once("> ").chain(input.split_whitespace()))? {
39 Query::Abstraction { target } => {
40 if let Ok(obs) = Observation::try_from(target.as_str()) {
41 return Ok(println!("{}", self.0.obs_to_abs(obs).await?));
42 }
43 Err("invalid abstraction target".into())
44 }
45 Query::Distance { target1, target2 } => {
46 if let (Ok(o1), Ok(o2)) = (
47 Observation::try_from(target1.as_str()),
48 Observation::try_from(target2.as_str()),
49 ) {
50 return Ok(println!("{:.4}", self.0.obs_distance(o1, o2).await?));
51 }
52 if let (Ok(a1), Ok(a2)) = (
53 Abstraction::try_from(target1.as_str()),
54 Abstraction::try_from(target2.as_str()),
55 ) {
56 return Ok(println!("{:.4}", self.0.abs_distance(a1, a2).await?));
57 }
58 Err("invalid distance targets".into())
59 }
60 Query::Equity { target } => {
61 if let Ok(obs) = Observation::try_from(target.as_str()) {
62 return Ok(println!("{:.4}", self.0.obs_equity(obs).await?));
63 }
64 if let Ok(abs) = Abstraction::try_from(target.as_str()) {
65 return Ok(println!("{:.4}", self.0.abs_equity(abs).await?));
66 }
67 Err("invalid equity target".into())
68 }
69 Query::Population { target } => {
70 if let Ok(obs) = Observation::try_from(target.as_str()) {
71 return Ok(println!("{}", self.0.obs_population(obs).await?));
72 }
73 if let Ok(abs) = Abstraction::try_from(target.as_str()) {
74 return Ok(println!("{}", self.0.abs_population(abs).await?));
75 }
76 Err("invalid population target".into())
77 }
78 Query::Similar { target } => {
79 if let Ok(obs) = Observation::try_from(target.as_str()) {
80 let members = self
81 .0
82 .obs_similar(obs)
83 .await?
84 .iter()
85 .map(|obs| (obs, Strength::from(Hand::from(*obs))))
86 .map(|(o, s)| format!(" - {:<18} {}", o, s))
87 .collect::<Vec<String>>()
88 .join("\n");
89 return Ok(println!("{}", members));
90 }
91 if let Ok(abs) = Abstraction::try_from(target.as_str()) {
92 let members = self
93 .0
94 .abs_similar(abs)
95 .await?
96 .iter()
97 .map(|obs| (obs, Strength::from(Hand::from(*obs))))
98 .map(|(o, s)| format!(" - {:<18} {}", o, s))
99 .collect::<Vec<String>>()
100 .join("\n");
101 return Ok(println!("{}", members));
102 }
103 Err("invalid similarity target".into())
104 }
105 Query::Nearby { target } => {
106 if let Ok(obs) = Observation::try_from(target.as_str()) {
107 let neighborhood = self
108 .0
109 .obs_nearby(obs)
110 .await?
111 .iter()
112 .enumerate()
113 .map(|(i, (abs, dist))| format!("{:>2}. {} ({:.4})", i + 1, abs, dist))
114 .collect::<Vec<String>>()
115 .join("\n");
116 return Ok(println!("{}", neighborhood));
117 }
118 if let Ok(abs) = Abstraction::try_from(target.as_str()) {
119 let neighborhood = self
120 .0
121 .abs_nearby(abs)
122 .await?
123 .iter()
124 .enumerate()
125 .map(|(i, (abs, dist))| format!("{:>2}. {} ({:.4})", i + 1, abs, dist))
126 .collect::<Vec<String>>()
127 .join("\n");
128 return Ok(println!("{}", neighborhood));
129 }
130 Err("invalid neighborhood target".into())
131 }
132 Query::Composition { target } => {
133 if let Ok(obs) = Observation::try_from(target.as_str()) {
134 let distribution = self
135 .0
136 .obs_histogram(obs)
137 .await?
138 .distribution()
139 .iter()
140 .enumerate()
141 .map(|(i, (abs, dist))| format!("{:>2}. {} ({:.4})", i + 1, abs, dist))
142 .collect::<Vec<String>>()
143 .join("\n");
144 return Ok(println!("{}", distribution));
145 }
146 if let Ok(abs) = Abstraction::try_from(target.as_str()) {
147 let distribution = self
148 .0
149 .abs_histogram(abs)
150 .await?
151 .distribution()
152 .iter()
153 .enumerate()
154 .map(|(i, (abs, dist))| format!("{:>2}. {} ({:.4})", i + 1, abs, dist))
155 .collect::<Vec<String>>()
156 .join("\n");
157 return Ok(println!("{}", distribution));
158 }
159 Err("invalid histogram target".into())
160 }
161 Query::Path { value } => {
162 let path = Path::from(value);
163 println!("Path({})", value);
164 println!(" Display: {}", path);
165 println!(" Length: {}", path.length());
166 println!(" Aggro: {}", path.aggression());
167 println!(" Edges: {:?}", Vec::<Edge>::from(path));
168 Ok(())
169 }
170 Query::Edge { value } => {
171 let edge = Edge::from(value);
172 println!("Edge({})", value);
173 println!(" Display: {}", edge);
174 println!(" Is choice: {}", edge.is_choice());
175 println!(" Is aggro: {}", edge.is_aggro());
176 Ok(())
177 }
178 Query::AbsFromInt { value } => {
179 let abs = Abstraction::from(value);
180 println!("Abstraction({})", value);
181 println!(" Display: {}", abs);
182 println!(" Street: {}", abs.street());
183 println!(" Index: {}", abs.index());
184 Ok(())
185 }
186 Query::ObsFromInt { value } => {
187 println!("Observation({})", value);
188 match std::panic::catch_unwind(|| Observation::from(value)) {
189 Ok(obs) => {
190 println!(" Display: {}", obs);
191 println!(" Street: {}", obs.street());
192 println!(" i64: {}", i64::from(obs));
193 Ok(())
194 }
195 Err(_) => {
196 println!(" Error: Invalid observation encoding (assertions failed)");
197 println!(" Note: Observations require valid poker hand representations");
198 Ok(())
199 }
200 }
201 }
202 Query::Isomorphism { value } => {
203 println!("Isomorphism({})", value);
204 match std::panic::catch_unwind(|| {
205 let iso = Isomorphism::from(value);
206 let obs = Observation::from(iso);
207 (iso, obs)
208 }) {
209 Ok((iso, obs)) => {
210 println!(" Observation: {}", obs);
211 println!(" Street: {}", obs.street());
212 println!(" i64: {}", i64::from(iso));
213 Ok(())
214 }
215 Err(_) => {
216 println!(" Error: Invalid isomorphism encoding (assertions failed)");
217 println!(" Note: Isomorphisms require valid poker hand representations");
218 Ok(())
219 }
220 }
221 }
222 }
223 }
224}