|
|
|
|
@ -12,7 +12,10 @@ impl Plugin for GamePlugin {
|
|
|
|
|
.add_systems(OnEnter(GameState::Play), hide_valid_moves)
|
|
|
|
|
.add_systems(
|
|
|
|
|
Update,
|
|
|
|
|
manage_state_entities::<GameState>().run_if(state_changed::<GameState>),
|
|
|
|
|
(
|
|
|
|
|
manage_state_entities::<GameState>().run_if(state_changed::<GameState>),
|
|
|
|
|
undo_move.run_if(just_pressed(KeyCode::KeyU)),
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
.add_systems(
|
|
|
|
|
Update,
|
|
|
|
|
@ -183,7 +186,9 @@ pub(crate) struct BeingCaptured;
|
|
|
|
|
|
|
|
|
|
/// Marker for component which is captured
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub(crate) struct Captured;
|
|
|
|
|
pub(crate) struct Captured {
|
|
|
|
|
pub epoch: usize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Component)]
|
|
|
|
|
pub(crate) struct Promoted;
|
|
|
|
|
@ -253,6 +258,7 @@ pub(crate) struct Board {
|
|
|
|
|
#[derive(Debug, Default, Event, Clone)]
|
|
|
|
|
pub(crate) struct Move {
|
|
|
|
|
pub epoch: usize,
|
|
|
|
|
pub piece: Option<Piece>,
|
|
|
|
|
pub from: BoardIndex,
|
|
|
|
|
pub to: Option<BoardIndex>,
|
|
|
|
|
pub move_type: MoveType,
|
|
|
|
|
@ -437,6 +443,7 @@ impl Board {
|
|
|
|
|
if self.inner[to.y][to.x].is_some() {
|
|
|
|
|
moves.push(Move {
|
|
|
|
|
epoch,
|
|
|
|
|
piece: self.at(to).copied(),
|
|
|
|
|
from: to,
|
|
|
|
|
to: None,
|
|
|
|
|
move_type: move_type.clone(),
|
|
|
|
|
@ -446,6 +453,7 @@ impl Board {
|
|
|
|
|
// Capture the intended move in the moves ledger
|
|
|
|
|
moves.push(Move {
|
|
|
|
|
epoch,
|
|
|
|
|
piece: self.at(from).copied(),
|
|
|
|
|
from,
|
|
|
|
|
to: Some(to),
|
|
|
|
|
move_type: move_type.clone(),
|
|
|
|
|
@ -478,6 +486,29 @@ impl Board {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Undo the last move
|
|
|
|
|
fn undo_move(&mut self) -> Vec<Move> {
|
|
|
|
|
let latest_epoch = self.current_epoch() - 1;
|
|
|
|
|
|
|
|
|
|
let mut moves = vec![];
|
|
|
|
|
|
|
|
|
|
while let Some(last) = self.moves.last() {
|
|
|
|
|
if last.epoch == latest_epoch {
|
|
|
|
|
let last = self.moves.pop().unwrap();
|
|
|
|
|
self.inner[last.from.y][last.from.x] = last.piece;
|
|
|
|
|
if let Some(to) = last.to {
|
|
|
|
|
self.inner[to.y][to.x] = None;
|
|
|
|
|
}
|
|
|
|
|
moves.push(last);
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Remaining moves: {:?}", self.moves);
|
|
|
|
|
return moves;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the Side of a piece
|
|
|
|
|
pub(crate) fn side(BoardIndex { x, .. }: BoardIndex) -> Result<Side, GameError> {
|
|
|
|
|
match x {
|
|
|
|
|
@ -576,6 +607,7 @@ impl Board {
|
|
|
|
|
Some(MoveType::Capture)
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
info!("Last move: {:?}", self.moves.last());
|
|
|
|
|
// move is valid if it does not un-do the previous move for this piece
|
|
|
|
|
match self.moves.last() {
|
|
|
|
|
Some(previous) => {
|
|
|
|
|
@ -1505,4 +1537,58 @@ fn assert_piece_consistency(
|
|
|
|
|
info!("Active: {} | being captured: {} | captured: {}", active_count, being_captured_count, captured_count);
|
|
|
|
|
let total_count = active_count + being_captured_count + captured_count;
|
|
|
|
|
assert_eq!(total_count, 18, "Pieces does does not add up!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// When user presses 'u' last move is undone
|
|
|
|
|
fn undo_move(
|
|
|
|
|
mut board: ResMut<Board>,
|
|
|
|
|
mut active_pieces: Query<&mut BoardIndex, With<Piece>>,
|
|
|
|
|
captured_pieces: Query<(Entity, &Captured), With<Piece>>,
|
|
|
|
|
turn: Res<State<TurnState>>,
|
|
|
|
|
mut next_turn: ResMut<NextState<TurnState>>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
) {
|
|
|
|
|
// Keep track of the current side in case we need to go back
|
|
|
|
|
let mut side = turn.get().0;
|
|
|
|
|
|
|
|
|
|
board
|
|
|
|
|
.undo_move()
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|Move { epoch, from, to, .. }| {
|
|
|
|
|
// If we have any moves to do, go back to the opposite side
|
|
|
|
|
if side == turn.get().0 {
|
|
|
|
|
side = !turn.get().0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info!("Reverting move {:?} {:?} -> {:?}", epoch, from, to);
|
|
|
|
|
match to { Some(to_idx) => { info!("Moving piece back from {:?}", to_idx);
|
|
|
|
|
// Find piece currently at "to_idx" and update it's position to "from"
|
|
|
|
|
active_pieces
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.filter(|idx| {
|
|
|
|
|
(idx.x, idx.y) == (to_idx.x, to_idx.y)
|
|
|
|
|
})
|
|
|
|
|
.for_each(|mut idx| {
|
|
|
|
|
*idx = *from
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
None => {
|
|
|
|
|
captured_pieces
|
|
|
|
|
.iter()
|
|
|
|
|
.find_map(|(entity, captured)| {
|
|
|
|
|
(captured.epoch == *epoch).then_some(entity)
|
|
|
|
|
})
|
|
|
|
|
.iter()
|
|
|
|
|
.for_each(|entity| {
|
|
|
|
|
commands
|
|
|
|
|
.entity(*entity)
|
|
|
|
|
.remove::<Captured>()
|
|
|
|
|
.insert(*from);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Set the turn state (may be a no-op)
|
|
|
|
|
next_turn.set(TurnState(side));
|
|
|
|
|
}
|