ruci/messages/engine/
best_move.rs1use std::fmt::{Display, Formatter, Write};
2use shakmaty::uci::UciMove;
3use crate::messages::RawEngineMessage;
4use crate::auxiliary::MessageTryFromRawMessageError;
5use crate::messages::pointers::engine::{EngineMessageBestMoveParameterPointer, EngineMessageParameterPointer, EngineMessagePointer};
6
7#[allow(clippy::module_name_repetitions)]
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct BestMove {
11 pub r#move: UciMove,
12 pub ponder: Option<UciMove>,
13}
14
15impl TryFrom<RawEngineMessage> for BestMove {
16 type Error = MessageTryFromRawMessageError<EngineMessageParameterPointer>;
17
18 fn try_from(raw_message: RawEngineMessage) -> Result<Self, Self::Error> {
19 if raw_message.message_pointer != EngineMessagePointer::BestMove {
20 return Err(Self::Error::InvalidMessage);
21 };
22
23 let Ok(r#move) = raw_message
26 .value
27 .ok_or(Self::Error::MissingValue)?
28 .parse()
29 else {
30 return Err(Self::Error::ValueParseError);
31 };
32
33 let ponder = raw_message
34 .parameters
35 .get(&EngineMessageParameterPointer::BestMove(
36 EngineMessageBestMoveParameterPointer::Ponder,
37 ))
38 .and_then(|s| s.parse().ok());
39
40 Ok(Self { r#move, ponder })
41 }
42}
43
44impl Display for BestMove {
45 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46 write!(f, "bestmove {}", self.r#move)?;
47
48 if let Some(ponder) = &self.ponder {
49 write!(f, " ponder {ponder}")?;
50 }
51
52 f.write_char('\n')
53 }
54}
55
56#[cfg(test)]
57#[allow(clippy::unwrap_used)]
58mod tests {
59 use std::str::FromStr;
60 use crate::messages::{EngineMessage, BestMove};
61
62 use shakmaty::uci::UciMove;
63 use pretty_assertions::assert_eq;
64
65 #[test]
66 fn to_from_str() {
67 let repr = EngineMessage::BestMove(BestMove {
68 r#move: UciMove::from_ascii(b"e2e4").unwrap(),
69 ponder: Some(UciMove::from_ascii(b"c7c5").unwrap()),
70 });
71 let str_repr = "bestmove e2e4 ponder c7c5\n";
72
73 assert_eq!(repr.to_string(), str_repr);
74 assert_eq!(EngineMessage::from_str(str_repr), Ok(repr));
75 }
76}