diff --git a/src/board.rs b/src/board.rs index 4a0706c..5c8e1d1 100644 --- a/src/board.rs +++ b/src/board.rs @@ -21,6 +21,32 @@ impl Board { } } + pub fn moveable(&self, direction: Direction) -> bool { + let player_next_position = self.level.player_position + direction.to_vector(); + if self + .level + .get_unchecked(&player_next_position) + .intersects(Tile::Wall) + { + return false; + } + if self + .level + .get_unchecked(&player_next_position) + .intersects(Tile::Crate) + { + let crate_next_position = player_next_position + direction.to_vector(); + if self + .level + .get_unchecked(&crate_next_position) + .intersects(Tile::Crate | Tile::Wall) + { + return false; + } + } + return true; + } + pub fn move_or_push(&mut self, direction: Direction) { let direction_vector = direction.to_vector(); let player_next_position = self.level.player_position + direction_vector; diff --git a/src/solver/solver.rs b/src/solver/solver.rs index 2cb5994..adb57e7 100644 --- a/src/solver/solver.rs +++ b/src/solver/solver.rs @@ -120,6 +120,10 @@ impl Solver { } fn minimum_push_count_to_nearest_target(&self, position: &Vector2) -> Option { + // TODO: 优化求解器最小推动数计算方法 + // 从目标开始逆推, 得到全部可达位置的下界. + // 若以存在下界, 取最小值. 若已经为更小的值, 停止搜索. + if self.level.target_positions.contains(position) { return Some(0); } @@ -207,17 +211,17 @@ impl Solver { ] .chunks(2) { - let neighbor = [ + let neighbors = [ position + directions[0].to_vector(), position + directions[1].to_vector(), ]; if !(self .level - .get_unchecked(&neighbor[0]) + .get_unchecked(&neighbors[0]) .intersects(Tile::Wall) && self .level - .get_unchecked(&neighbor[1]) + .get_unchecked(&neighbors[1]) .intersects(Tile::Wall)) { continue; diff --git a/src/solver/state.rs b/src/solver/state.rs index 985addc..4672424 100644 --- a/src/solver/state.rs +++ b/src/solver/state.rs @@ -101,6 +101,7 @@ impl State { continue; } + // TODO: 检测是否会产生新的死锁 if self.can_block_crate(&new_crate_position, solver) { continue; } diff --git a/src/systems/auto_solve.rs b/src/systems/auto_solve.rs index f0e8103..eb3c300 100644 --- a/src/systems/auto_solve.rs +++ b/src/systems/auto_solve.rs @@ -120,7 +120,7 @@ pub fn update_solver( info!(" Solution: {}", solution.lurd()); for movement in &*solution { - player_move_or_push(movement.direction, &mut player_movement); + player_move(movement.direction, &mut player_movement); } next_state.set(AppState::Main); return; diff --git a/src/systems/input.rs b/src/systems/input.rs index 67316e3..a3f17bf 100644 --- a/src/systems/input.rs +++ b/src/systems/input.rs @@ -222,8 +222,8 @@ impl Action { pub fn player_move_to( target: &Vector2, - board: &mut crate::board::Board, player_movement: &mut PlayerMovement, + board: &crate::board::Board, ) { if let Some(path) = find_path(&board.level.player_position, target, |position| { board @@ -235,12 +235,23 @@ pub fn player_move_to( .windows(2) .map(|pos| Direction::from_vector(pos[1] - pos[0]).unwrap()); for direction in directions { - player_move_or_push(direction, player_movement); + player_move(direction, player_movement); } } } -pub fn player_move_or_push(direction: Direction, player_movement: &mut PlayerMovement) { +pub fn player_move(direction: Direction, player_movement: &mut PlayerMovement) { + player_movement.directions.push_front(direction); +} + +pub fn player_move_with_check( + direction: Direction, + player_movement: &mut PlayerMovement, + board: &crate::board::Board, +) { + if !board.moveable(direction) { + return; + } player_movement.directions.push_front(direction); } @@ -291,16 +302,16 @@ pub fn handle_other_action( let board = &mut board.single_mut().board; if action_state.just_pressed(Action::MoveUp) { - player_move_or_push(Direction::Up, &mut player_movement); + player_move_with_check(Direction::Up, &mut player_movement, board); } if action_state.just_pressed(Action::MoveDown) { - player_move_or_push(Direction::Down, &mut player_movement); + player_move_with_check(Direction::Down, &mut player_movement, board); } if action_state.just_pressed(Action::MoveLeft) { - player_move_or_push(Direction::Left, &mut player_movement); + player_move_with_check(Direction::Left, &mut player_movement, board); } if action_state.just_pressed(Action::MoveRight) { - player_move_or_push(Direction::Right, &mut player_movement); + player_move_with_check(Direction::Right, &mut player_movement, board); } if action_state.just_pressed(Action::Undo) { @@ -485,7 +496,7 @@ pub fn mouse_input( _ => unreachable!(), } - player_move_to(&grid_position, board, &mut player_movement); + player_move_to(&grid_position, &mut player_movement, board); } }