use sashite_epin::sashite_pin::Identifier as Pin;
use sashite_epin::{Identifier as Epin, Letter, Side as PieceSide, State};
use crate::domain::side::Side;
use crate::domain::variant::{Variant, VariantAssignment};
#[must_use]
pub fn capture_transform(captured: Epin, variants: VariantAssignment) -> Epin {
let captured_side: Side = captured.side().into();
let capturer_side = captured_side.flip();
let captured_variant = variants.variant_of(captured_side);
let capturer_variant = variants.variant_of(capturer_side);
let base = to_base(captured);
match capturer_variant {
Variant::Chess | Variant::Xiongqi => base,
Variant::Ogi => match captured_variant {
Variant::Ogi => flip_side(base),
Variant::Chess | Variant::Xiongqi => ogi_fu(capturer_side).unwrap_or(base),
},
}
}
#[inline]
fn to_base(captured: Epin) -> Epin {
let core = captured.pin().normalized(); let core = match core.letter().as_char() {
'T' | 't' => demote_tokin(core).unwrap_or(core), _ => core,
};
captured.with_pin(core)
}
#[inline]
fn demote_tokin(core: Pin) -> Option<Pin> {
let ch = match core.side() {
PieceSide::First => 'F',
PieceSide::Second => 'f',
};
let letter = Letter::try_from_char(ch).ok()?;
Some(Pin::new(letter, core.side(), State::Normal, false))
}
#[inline]
fn flip_side(piece: Epin) -> Epin {
piece.with_pin(piece.pin().flipped())
}
#[inline]
fn ogi_fu(side: Side) -> Option<Epin> {
let piece_side: PieceSide = side.into();
let ch = match side {
Side::First => 'F',
Side::Second => 'f',
};
let letter = Letter::try_from_char(ch).ok()?;
Some(Epin::new(
Pin::new(letter, piece_side, State::Normal, false),
false,
))
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use super::capture_transform;
use crate::domain::variant::Variant::{Chess, Ogi, Xiongqi};
use crate::domain::variant::VariantAssignment;
use sashite_epin::Identifier as Epin;
fn check(captured: &str, va: VariantAssignment, expected: &str) {
let piece = Epin::parse(captured).expect("valid captured EPIN token");
let got = capture_transform(piece, va);
assert_eq!(
got.encode().as_str(),
expected,
"capture of `{captured}` under {va:?} expected `{expected}`",
);
}
#[test]
fn chess_ogi_jw() {
let va = VariantAssignment::new(Ogi, Chess);
check("T", va, "F");
check("+F", va, "F");
check("I", va, "I");
check("R", va, "R");
check("B", va, "B");
check("N", va, "N");
check("q", va, "F");
check("+p", va, "F");
check("-p", va, "F");
check("+r", va, "F");
check("-r", va, "F");
check("n", va, "F");
check("b", va, "F");
}
#[test]
fn chess_ogi_wj() {
let va = VariantAssignment::new(Chess, Ogi);
check("t", va, "f"); check("+f", va, "f");
check("i", va, "i");
check("Q", va, "f"); check("+P", va, "f");
check("-R", va, "f");
}
#[test]
fn ogi_xiongqi_jc() {
let va = VariantAssignment::new(Ogi, Xiongqi);
check("T", va, "F");
check("+F", va, "F");
check("-F", va, "F");
check("I", va, "I");
check("R", va, "R");
check("B", va, "B");
check("N", va, "N");
check("s", va, "F");
check("+s", va, "F");
check("-s", va, "F");
check("r", va, "F");
check("n", va, "F");
check("b", va, "F");
check("e", va, "F");
}
#[test]
fn ogi_xiongqi_cj() {
let va = VariantAssignment::new(Xiongqi, Ogi);
check("t", va, "f"); check("+f", va, "f");
check("i", va, "i");
check("E", va, "f"); check("+S", va, "f");
check("-R", va, "f");
}
#[test]
fn chess_xiongqi() {
let va = VariantAssignment::new(Chess, Xiongqi);
check("+s", va, "s");
check("-s", va, "s");
check("e", va, "e");
check("r", va, "r");
check("n", va, "n");
check("b", va, "b");
check("+P", va, "P");
check("-P", va, "P");
check("Q", va, "Q");
check("+R", va, "R");
check("N", va, "N");
}
#[test]
fn chess_xiongqi_reversed() {
let va = VariantAssignment::new(Xiongqi, Chess);
check("+S", va, "S"); check("-S", va, "S");
check("E", va, "E");
check("+p", va, "p"); check("q", va, "q");
check("-r", va, "r");
}
#[test]
fn pure_ogi() {
let va = VariantAssignment::new(Ogi, Ogi);
check("f", va, "F");
check("+f", va, "F");
check("-f", va, "F");
check("t", va, "F");
check("n", va, "N");
check("r", va, "R");
check("b", va, "B");
check("i", va, "I");
check("T", va, "f");
check("N", va, "n");
}
#[test]
fn pure_chess() {
let va = VariantAssignment::new(Chess, Chess);
check("+p", va, "p");
check("-p", va, "p");
check("+r", va, "r");
check("q", va, "q");
check("n", va, "n");
check("+P", va, "P");
}
#[test]
fn pure_xiongqi() {
let va = VariantAssignment::new(Xiongqi, Xiongqi);
check("+s", va, "s");
check("-s", va, "s");
check("e", va, "e");
check("r", va, "r");
check("n", va, "n");
check("b", va, "b");
check("+E", va, "E"); }
}