use shogi_core::{Color, Move, Piece, Square};
use crate::{Error, FromUsi, Result};
impl FromUsi for Move {
fn parse_usi_slice(s: &[u8]) -> Result<(&[u8], Self)> {
if s.len() < 4 {
return Err(Error::InvalidInput {
from: 0,
to: s.len(),
description: "A `Move` expected, but less than 4 bytes found",
});
}
if s.get(1).copied() == Some(b'*') {
let (remaining, piece) = bind!(Piece::parse_usi_slice(&s[..1]));
debug_assert!(remaining.is_empty());
if piece.color() == Color::White {
return Err(Error::InvalidInput {
from: 0,
to: 1,
description: "piece must be an uppercase letter",
});
}
let (s, square) = try_with_progress!(Square::parse_usi_slice(&s[2..]), 2);
return Ok((s, Move::Drop { piece, to: square }));
}
let (s, from) = bind!(Square::parse_usi_slice(s));
let (mut s, to) = try_with_progress!(Square::parse_usi_slice(s), 2);
let mut promote = false;
if let Some((&b'+', rest)) = s.split_first() {
promote = true;
s = rest;
}
Ok((s, Move::Normal { from, to, promote }))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn negative() {
let result = Move::from_usi("P*9j"); assert!(matches!(
result,
Err(Error::InvalidInput { from: 2, to: 4, .. }),
));
let result = Move::from_usi("P+3d"); assert!(matches!(
result,
Err(Error::InvalidInput { from: 0, to: 2, .. }),
));
}
}