|
|
|
|
@ -513,6 +513,7 @@ impl Board {
|
|
|
|
|
from: BoardIndex,
|
|
|
|
|
to: BoardIndex,
|
|
|
|
|
) -> Option<MoveType> {
|
|
|
|
|
self.line(from, to).all(|board_index| self.at(board_index).is_none()).then(|| {
|
|
|
|
|
self.at(from).map(|piece| {
|
|
|
|
|
// Given that the side does not have a queen||drone
|
|
|
|
|
// And the piece is a drone||pawn
|
|
|
|
|
@ -538,10 +539,6 @@ impl Board {
|
|
|
|
|
match dest_at {
|
|
|
|
|
// Cannot move on top of a friendly
|
|
|
|
|
Some(to_piece) => {
|
|
|
|
|
(!self.line(from, to)
|
|
|
|
|
.any(|board_index| self.at(board_index)
|
|
|
|
|
.is_some())
|
|
|
|
|
).then(|| {
|
|
|
|
|
match (piece, to_piece) {
|
|
|
|
|
(Piece::Pawn, Piece::Pawn) => {
|
|
|
|
|
(!side_has_drone).then_some(MoveType::Merge)
|
|
|
|
|
@ -553,15 +550,10 @@ impl Board {
|
|
|
|
|
Some(MoveType::Invalid)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}).flatten()
|
|
|
|
|
},
|
|
|
|
|
// Any other spot is valid
|
|
|
|
|
None => {
|
|
|
|
|
// If there is another piece between A and B
|
|
|
|
|
(!self
|
|
|
|
|
.line(from, to)
|
|
|
|
|
.any(|board_index| self.at(board_index).is_some()))
|
|
|
|
|
.then_some(MoveType::Valid)
|
|
|
|
|
Some(MoveType::Valid)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -569,11 +561,7 @@ impl Board {
|
|
|
|
|
(Side::A, Side::B) | (Side::B, Side::A) => {
|
|
|
|
|
match dest_at {
|
|
|
|
|
Some(_) => {
|
|
|
|
|
// If there is no other piece between A and B
|
|
|
|
|
(!self
|
|
|
|
|
.line(from, to)
|
|
|
|
|
.any(|board_index| self.at(board_index).is_some()))
|
|
|
|
|
.then_some(MoveType::Capture)
|
|
|
|
|
Some(MoveType::Capture)
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
// move is valid if it does not un-do the previous move
|
|
|
|
|
@ -583,12 +571,8 @@ impl Board {
|
|
|
|
|
}
|
|
|
|
|
// First move in the game, this is valid (and impossible)
|
|
|
|
|
None => {
|
|
|
|
|
// If there is no other pieces between A and B
|
|
|
|
|
// the move is valid
|
|
|
|
|
(!self
|
|
|
|
|
.line(from, to)
|
|
|
|
|
.any(|board_index| self.at(board_index).is_some()))
|
|
|
|
|
.then_some(MoveType::Valid)
|
|
|
|
|
Some(MoveType::Valid)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -596,7 +580,8 @@ impl Board {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}).flatten().or(Some(MoveType::Invalid))
|
|
|
|
|
})
|
|
|
|
|
}).flatten().flatten().or(Some(MoveType::Invalid))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the possible moves the piece at this tile can make.
|
|
|
|
|
@ -604,9 +589,12 @@ impl Board {
|
|
|
|
|
if let Some(piece) = self.at(current_board_index) {
|
|
|
|
|
piece.moves_at(¤t_board_index).iter().filter_map(|move_index| {
|
|
|
|
|
// Get the move type (or none if totally invalid)
|
|
|
|
|
match self.move_type(current_board_index, *move_index) {
|
|
|
|
|
let result = self.move_type(current_board_index, *move_index);
|
|
|
|
|
match result {
|
|
|
|
|
None | Some(MoveType::Invalid) => None,
|
|
|
|
|
_ => Some(*move_index),
|
|
|
|
|
Some(MoveType::Capture) | Some(MoveType::Merge) | Some(MoveType::Valid) => {
|
|
|
|
|
Some(*move_index)
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.collect()
|
|
|
|
|
@ -738,7 +726,7 @@ mod test {
|
|
|
|
|
|
|
|
|
|
/// When an enemy is on one side, can move to capture just that piece
|
|
|
|
|
#[test]
|
|
|
|
|
fn case_03() {
|
|
|
|
|
fn case_01() {
|
|
|
|
|
let board = Board::from_ascii(
|
|
|
|
|
r#"........
|
|
|
|
|
........
|
|
|
|
|
@ -798,7 +786,6 @@ mod test {
|
|
|
|
|
(5, 0).into(),
|
|
|
|
|
(5, 2).into(),
|
|
|
|
|
]);
|
|
|
|
|
println!("Moves: {:?}", Piece::Queen.moves_at(&(4, 1).into()));
|
|
|
|
|
assert_eq!(
|
|
|
|
|
expected, given,
|
|
|
|
|
"Mostly blocked queen, moves include captures"
|
|
|
|
|
@ -807,7 +794,7 @@ mod test {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn case_01() {
|
|
|
|
|
fn case_03() {
|
|
|
|
|
let board = Board::from_ascii(
|
|
|
|
|
r#".p.....q
|
|
|
|
|
dp.p.pdq
|
|
|
|
|
@ -839,7 +826,38 @@ mod test {
|
|
|
|
|
]);
|
|
|
|
|
assert_eq!(expected, given);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A strange failure mode in game which I suspect comes from
|
|
|
|
|
// a disconnect between board logic and display plumbing
|
|
|
|
|
#[test]
|
|
|
|
|
fn case_04() {
|
|
|
|
|
let mut board = Board::from_ascii(
|
|
|
|
|
r#".....dqq
|
|
|
|
|
dpp..pdq
|
|
|
|
|
qdp....d
|
|
|
|
|
qqd....."#,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
board.move_piece((5, 3).into(), (4, 3).into()).unwrap();
|
|
|
|
|
board.move_piece((2, 2).into(), (1, 3).into()).unwrap();
|
|
|
|
|
|
|
|
|
|
let expected = Board::from_ascii(
|
|
|
|
|
r#".p..d#qq
|
|
|
|
|
dp...pdq
|
|
|
|
|
qdp....d
|
|
|
|
|
qqd....."#,
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(expected.inner, board.inner);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let given = board.valid_moves((6, 3).into());
|
|
|
|
|
let expected: HashSet<BoardIndex> = HashSet::from([(5, 3).into()]);
|
|
|
|
|
assert_eq!(expected, given);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
@ -1328,7 +1346,9 @@ fn show_valid_moves(
|
|
|
|
|
events.iter().for_each(|idx| {
|
|
|
|
|
// Iterate over all ValidMove entities
|
|
|
|
|
// For each one with a ValidMove index, make it visible
|
|
|
|
|
board.valid_moves(*idx).iter().for_each(|idx| {
|
|
|
|
|
let valid_moves = board.valid_moves(*idx);
|
|
|
|
|
info!("Showing valid moves for {:?}: {:?}", idx, valid_moves);
|
|
|
|
|
valid_moves.iter().for_each(|idx| {
|
|
|
|
|
indicators.iter_mut().for_each(|(i, mut vis)| {
|
|
|
|
|
if i == idx {
|
|
|
|
|
*vis = Visibility::Inherited;
|
|
|
|
|
|