1use std::collections::HashSet;
3use std::clone::Clone;
4
5use shogi::*;
6use Validate;
7#[derive(Debug,Eq,PartialEq)]
9pub enum UsiCommand {
10 UsiOk,
12 UsiId(String, String),
14 UsiReadyOk,
16 UsiBestMove(BestMove),
18 UsiInfo(Vec<UsiInfoSubCommand>),
20 UsiOption(String,UsiOptType),
22 UsiCheckMate(CheckMate),
24}
25#[derive(Clone, Copy, Eq, PartialOrd, PartialEq, Debug)]
27pub enum BestMove {
28 Move(Move,Option<Move>),
30 Resign,
32 Win,
34 Abort,
36}
37#[derive(Clone, Debug,Eq,PartialEq)]
39pub enum UsiInfoSubCommand {
40 Depth(u32),
42 SelDepth(u32),
44 Time(u64),
46 Nodes(u64),
48 Pv(Vec<Move>),
50 MultiPv(u32),
52 Score(UsiScore),
54 CurrMove(Move),
56 Hashfull(u64),
58 Nps(u64),
60 Str(String),
62}
63#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
65pub enum UsiInfoSubCommandKind {
66 Depth,
68 SelDepth,
70 Time,
72 Nodes,
74 Pv,
76 MultiPv,
78 Score,
80 CurMove,
82 Hashfull,
84 Nps,
86 Str,
88}
89#[derive(Clone,Debug,Eq,PartialEq)]
91pub enum UsiScore {
92 Cp(i64),
94 CpUpper(i64),
96 CpLower(i64),
98 Mate(UsiScoreMate),
100 MateUpper(i64),
102 MateLower(i64),
104}
105#[derive(Clone,Debug,Eq,PartialEq)]
107pub enum UsiScoreMate {
108 Num(i64),
110 Plus,
112 Minus,
114}
115#[derive(Clone, Debug, Eq, PartialEq)]
117pub struct UsiInfoCommand(pub Vec<UsiInfoSubCommand>);
118#[derive(Debug,Eq,PartialEq)]
120pub enum CheckMate {
121 Moves(Vec<Move>),
123 NotiImplemented,
125 Timeout,
127 Nomate,
129 Abort,
131}
132#[derive(Debug,Eq,PartialEq)]
134pub enum UsiOptType {
135 Check(Option<bool>),
139 Spin(i64, i64,Option<i64>),
143 Combo(Option<String>, Vec<String>),
147 Button,
149 String(Option<String>),
153 FileName(Option<String>),
157}
158impl Clone for UsiOptType {
159 fn clone(&self) -> UsiOptType {
160 match *self {
161 UsiOptType::Check(None) => UsiOptType::Check(None),
162 UsiOptType::Check(Some(b)) => UsiOptType::Check(Some(b)),
163 UsiOptType::Spin(l,u,None) => UsiOptType::Spin(l,u,None),
164 UsiOptType::Spin(l,u,Some(d)) => UsiOptType::Spin(l,u,Some(d)),
165 UsiOptType::Combo(None, ref i) => UsiOptType::Combo(None, i.iter().map(|s| s.clone())
166 .collect::<Vec<String>>()),
167 UsiOptType::Combo(Some(ref d), ref i) => UsiOptType::Combo(Some(d.clone()), i.iter().map(|s| s.clone())
168 .collect::<Vec<String>>()),
169 UsiOptType::Button => UsiOptType::Button,
170 UsiOptType::String(None) => UsiOptType::String(None),
171 UsiOptType::String(Some(ref s)) => UsiOptType::String(Some(s.clone())),
172 UsiOptType::FileName(None) => UsiOptType::FileName(None),
173 UsiOptType::FileName(Some(ref s)) => UsiOptType::FileName(Some(s.clone())),
174 }
175 }
176}
177impl Validate for UsiCommand {
178 fn validate(&self) -> bool {
179 match *self {
180 UsiCommand::UsiBestMove(BestMove::Move(ref m,_)) if !m.validate() => false,
181 UsiCommand::UsiBestMove(BestMove::Move(_,Some(ref m))) if !m.validate() => false,
182 UsiCommand::UsiInfo(ref commands) => {
183 let mut hs = HashSet::new();
184 let mut prev_kind = None;
185
186 for cmd in commands {
187 match *cmd {
188 UsiInfoSubCommand::Pv(_) if hs.contains(&UsiInfoSubCommandKind::Str) => {
189 return false;
190 },
191 UsiInfoSubCommand::Str(_) if hs.contains(&UsiInfoSubCommandKind::Pv) => {
192 return false;
193 },
194 UsiInfoSubCommand::SelDepth(_) if !prev_kind.map(|k| k == UsiInfoSubCommandKind::Depth).unwrap_or(false) => {
195 return false;
196 },
197 ref c @ UsiInfoSubCommand::Pv(_) => {
198 return c.validate();
199 },
200 ref c @ UsiInfoSubCommand::CurrMove(_) => {
201 c.validate();
202 }
203 _ => (),
204 }
205 if hs.contains(&cmd.get_kind()) {
206 return false;
207 }
208 else {
209 let kind = cmd.get_kind();
210 hs.insert(kind);
211 prev_kind = Some(kind);
212 }
213 }
214
215 if hs.contains(&UsiInfoSubCommandKind::MultiPv) && !hs.contains(&UsiInfoSubCommandKind::Pv) {
216 false
217 } else {
218 true
219 }
220 },
221 UsiCommand::UsiOption(_,ref opt) => opt.validate(),
222 UsiCommand::UsiCheckMate(ref c) => c.validate(),
223 _ => true
224 }
225 }
226}
227impl UsiInfoSubCommand {
228 pub fn get_kind(&self) -> UsiInfoSubCommandKind {
230 match *self {
231 UsiInfoSubCommand::Depth(_) => UsiInfoSubCommandKind::Depth,
232 UsiInfoSubCommand::SelDepth(_) => UsiInfoSubCommandKind::SelDepth,
233 UsiInfoSubCommand::Time(_) => UsiInfoSubCommandKind::Time,
234 UsiInfoSubCommand::Nodes(_) => UsiInfoSubCommandKind::Nodes,
235 UsiInfoSubCommand::Pv(_) => UsiInfoSubCommandKind::Pv,
236 UsiInfoSubCommand::MultiPv(_) => UsiInfoSubCommandKind::MultiPv,
237 UsiInfoSubCommand::Score(_) => UsiInfoSubCommandKind::Score,
238 UsiInfoSubCommand::CurrMove(_) => UsiInfoSubCommandKind::CurMove,
239 UsiInfoSubCommand::Hashfull(_) => UsiInfoSubCommandKind::Hashfull,
240 UsiInfoSubCommand::Nps(_) => UsiInfoSubCommandKind::Nps,
241 UsiInfoSubCommand::Str(_) => UsiInfoSubCommandKind::Str,
242 }
243 }
244}
245impl Validate for UsiInfoSubCommand {
246 fn validate(&self) -> bool {
247 match *self {
248 UsiInfoSubCommand::Pv(ref v) if v.len() < 1 => false,
249 UsiInfoSubCommand::Pv(ref v) => {
250 for m in v {
251 match *m {
252 ref mv if !mv.validate() => {
253 return false;
254 },
255 _ => (),
256 }
257 }
258 true
259 },
260 UsiInfoSubCommand::CurrMove(ref m) if !m.validate() => false,
261 _ => true,
262 }
263 }
264}
265impl Validate for CheckMate {
266 fn validate(&self) -> bool {
267 match *self {
268 CheckMate::Moves(ref v) if v.len() < 1 => false,
269 CheckMate::Moves(ref v) => {
270 for m in v {
271 match m.validate() {
272 false => {
273 return false;
274 },
275 _ => (),
276 }
277 }
278 true
279 },
280 _ => true,
281 }
282 }
283}
284impl Validate for UsiOptType {
285 fn validate(&self) -> bool {
286 match *self {
287 UsiOptType::Combo(_,ref l) if l.len() < 1 => false,
288 _ => true,
289 }
290 }
291}