ruci/messages/engine/
best_move.rs

1use 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)]
9/// <https://backscattering.de/chess/uci/#engine-bestmove>
10pub 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        //println!("value: {:?}", raw_message.value);
24
25        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}