main
Elijah C. Voigt 1 year ago
parent fcf89e91fc
commit d045800ae3

@ -270,3 +270,11 @@ fast_movement_speed = 1.0
fast_text_speed = 999.0 fast_text_speed = 999.0
fast_dissolve_speed = 1.0 fast_dissolve_speed = 1.0
fast_light_speed = 1.0 fast_light_speed = 1.0
##############
### Game rules
##############
# 0: Disabled
# -1: No limit
# N: Some value in-between
undo_limit = -1

@ -1117,7 +1117,7 @@ fn capture_piece_end(
mut events: RemovedComponents<Dissolving>, mut events: RemovedComponents<Dissolving>,
mut query: Query<(Entity, &Dissolvable, &Side, &mut Transform), With<BeingCaptured>>, mut query: Query<(Entity, &Dissolvable, &Side, &mut Transform), With<BeingCaptured>>,
mut commands: Commands, mut commands: Commands,
board: Res<game::Board>,
score: Res<game::Score>, score: Res<game::Score>,
) { ) {
events.read().for_each(|e| { events.read().for_each(|e| {
@ -1128,7 +1128,7 @@ fn capture_piece_end(
.entity(entity) .entity(entity)
.insert(Dissolving::In(dissolvable.duration)) .insert(Dissolving::In(dissolvable.duration))
.remove::<BeingCaptured>() .remove::<BeingCaptured>()
.insert(Captured); .insert(Captured { epoch: board.current_epoch() - 1 });
} }
}); });
} }

@ -12,7 +12,10 @@ impl Plugin for GamePlugin {
.add_systems(OnEnter(GameState::Play), hide_valid_moves) .add_systems(OnEnter(GameState::Play), hide_valid_moves)
.add_systems( .add_systems(
Update, 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( .add_systems(
Update, Update,
@ -183,7 +186,9 @@ pub(crate) struct BeingCaptured;
/// Marker for component which is captured /// Marker for component which is captured
#[derive(Debug, Component)] #[derive(Debug, Component)]
pub(crate) struct Captured; pub(crate) struct Captured {
pub epoch: usize,
}
#[derive(Debug, Component)] #[derive(Debug, Component)]
pub(crate) struct Promoted; pub(crate) struct Promoted;
@ -253,6 +258,7 @@ pub(crate) struct Board {
#[derive(Debug, Default, Event, Clone)] #[derive(Debug, Default, Event, Clone)]
pub(crate) struct Move { pub(crate) struct Move {
pub epoch: usize, pub epoch: usize,
pub piece: Option<Piece>,
pub from: BoardIndex, pub from: BoardIndex,
pub to: Option<BoardIndex>, pub to: Option<BoardIndex>,
pub move_type: MoveType, pub move_type: MoveType,
@ -437,6 +443,7 @@ impl Board {
if self.inner[to.y][to.x].is_some() { if self.inner[to.y][to.x].is_some() {
moves.push(Move { moves.push(Move {
epoch, epoch,
piece: self.at(to).copied(),
from: to, from: to,
to: None, to: None,
move_type: move_type.clone(), move_type: move_type.clone(),
@ -446,6 +453,7 @@ impl Board {
// Capture the intended move in the moves ledger // Capture the intended move in the moves ledger
moves.push(Move { moves.push(Move {
epoch, epoch,
piece: self.at(from).copied(),
from, from,
to: Some(to), to: Some(to),
move_type: move_type.clone(), 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 /// Returns the Side of a piece
pub(crate) fn side(BoardIndex { x, .. }: BoardIndex) -> Result<Side, GameError> { pub(crate) fn side(BoardIndex { x, .. }: BoardIndex) -> Result<Side, GameError> {
match x { match x {
@ -576,6 +607,7 @@ impl Board {
Some(MoveType::Capture) Some(MoveType::Capture)
} }
None => { None => {
info!("Last move: {:?}", self.moves.last());
// move is valid if it does not un-do the previous move for this piece // move is valid if it does not un-do the previous move for this piece
match self.moves.last() { match self.moves.last() {
Some(previous) => { Some(previous) => {
@ -1506,3 +1538,57 @@ fn assert_piece_consistency(
let total_count = 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!"); 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));
}
Loading…
Cancel
Save