Skip to content

Commit

Permalink
chore(deps): update dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ShenMian committed Aug 2, 2024
1 parent 6ec4a94 commit e59ca9f
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 326 deletions.
420 changes: 226 additions & 194 deletions Cargo.lock

Large diffs are not rendered by default.

48 changes: 19 additions & 29 deletions src/board.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use nalgebra::Vector2;
use soukoban::{direction::Direction, Action, Actions, Level, Tiles};

#[derive(Clone)]
Expand All @@ -20,13 +19,14 @@ impl Board {

/// Checks if the player can move or push in the specified direction.
pub fn moveable(&self, direction: Direction) -> bool {
let player_next_position = self.level.player_position() + &direction.into();
if self.level[player_next_position].intersects(Tiles::Wall) {
let map = self.level.map();
let player_next_position = map.player_position() + &direction.into();
if map[player_next_position].intersects(Tiles::Wall) {
return false;
}
if self.level[player_next_position].intersects(Tiles::Box) {
if map[player_next_position].intersects(Tiles::Box) {
let box_next_position = player_next_position + &direction.into();
if self.level[box_next_position].intersects(Tiles::Box | Tiles::Wall) {
if map[box_next_position].intersects(Tiles::Box | Tiles::Wall) {
return false;
}
}
Expand All @@ -35,23 +35,24 @@ impl Board {

/// Moves the player or pushes a box in the specified direction.
pub fn move_or_push(&mut self, direction: Direction) {
let map = self.level.map_mut();
let direction_vector = &direction.into();
let player_next_position = self.level.player_position() + direction_vector;
if self.level[player_next_position].intersects(Tiles::Wall) {
let player_next_position = map.player_position() + direction_vector;
if map[player_next_position].intersects(Tiles::Wall) {
return;
}
if self.level[player_next_position].intersects(Tiles::Box) {
if map[player_next_position].intersects(Tiles::Box) {
let box_next_position = player_next_position + direction_vector;
if self.level[box_next_position].intersects(Tiles::Wall | Tiles::Box) {
if map[box_next_position].intersects(Tiles::Wall | Tiles::Box) {
return;
}
self.move_box(player_next_position, box_next_position);
map.set_box_position(player_next_position, box_next_position);

self.actions.push(Action::Push(direction));
} else {
self.actions.push(Action::Move(direction));
}
self.move_player(player_next_position);
map.set_player_position(player_next_position);
self.undone_actions.clear();
}

Expand All @@ -69,14 +70,16 @@ impl Board {
/// Undoes the last move.
pub fn undo_move(&mut self) {
debug_assert!(!self.actions.is_empty());
let map = self.level.map_mut();
let history = self.actions.pop().unwrap();
let direction = history.direction();
if history.is_push() {
let box_position = self.level.player_position() + &direction.into();
self.move_box(box_position, self.level.player_position());
let box_position = map.player_position() + &direction.into();
let player_position = map.player_position();
map.set_box_position(box_position, player_position);
}
let player_prev_position = self.level.player_position() - &direction.into();
self.move_player(player_prev_position);
let player_prev_position = map.player_position() - &direction.into();
map.set_player_position(player_prev_position);
self.undone_actions.push(history);
}

Expand All @@ -102,7 +105,7 @@ impl Board {

/// Checks if the level is solved.
pub fn is_solved(&self) -> bool {
self.level.box_positions() == self.level.goal_positions()
self.level.map().box_positions() == self.level.map().goal_positions()
}

pub fn actions(&self) -> &Actions {
Expand All @@ -116,17 +119,4 @@ impl Board {
.map(|action| action.direction())
.unwrap_or(Direction::Down)
}

fn move_player(&mut self, to: Vector2<i32>) {
let player_position = self.level.player_position();
self.level[player_position].remove(Tiles::Player);
self.level[to].insert(Tiles::Player);
self.level.set_player_position(to);
}

fn move_box(&mut self, from: Vector2<i32>, to: Vector2<i32>) {
self.level[from].remove(Tiles::Box);
self.level[to].insert(Tiles::Box);
self.level.set_box_position(from, to);
}
}
6 changes: 3 additions & 3 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl Database {

let _ = self.connection.execute(
"INSERT INTO tb_level(title, author, comments, map, width, height, hash, date) VALUES (?, ?, ?, ?, ?, ?, ?, DATE('now'))",
(title, author, comments, level.map().to_string(), level.dimensions().x, level.dimensions().y, hash),
(title, author, comments, level.map().to_string(), level.map().dimensions().x, level.map().dimensions().y, hash),
);
}

Expand Down Expand Up @@ -223,8 +223,8 @@ impl Database {
fn normalized_hash(level: &Level) -> String {
let mut hasher = DefaultHasher::new();
let mut normalized_level = level.clone();
normalized_level.normalize();
normalized_level.hash(&mut hasher);
normalized_level.map_mut().normalize();
normalized_level.map_mut().hash(&mut hasher);
let hash = hasher.finish();
// Must convert the hash to a string first, otherwise rusqlite may throw an error.
hash.to_string()
Expand Down
89 changes: 47 additions & 42 deletions src/solve/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ impl Solver {
heap: BinaryHeap::new(),
};
instance.heap.push(State::new(
instance.level.player_position(),
instance.level.box_positions().clone(),
instance.level.map().player_position(),
instance.level.map().box_positions().clone(),
Actions::new(),
&instance,
));
Expand Down Expand Up @@ -123,11 +123,12 @@ impl Solver {

/// Calculates and returns the set of tunnels in the level.
fn calculate_tunnels(&self) -> HashSet<(Vector2<i32>, Direction)> {
let map = self.level.map();
let mut tunnels = HashSet::new();
for x in 1..self.level.dimensions().x - 1 {
for y in 1..self.level.dimensions().y - 1 {
for x in 1..map.dimensions().x - 1 {
for y in 1..map.dimensions().y - 1 {
let box_position = Vector2::new(x, y);
if !self.level[box_position].intersects(Tiles::Floor) {
if !map[box_position].intersects(Tiles::Floor) {
continue;
}

Expand All @@ -148,33 +149,33 @@ impl Solver {
// .
// #$#
// #@#
if self.level[player_position + &left.into()].intersects(Tiles::Wall)
&& self.level[player_position + &right.into()].intersects(Tiles::Wall)
&& self.level[box_position + &left.into()].intersects(Tiles::Wall)
&& self.level[box_position + &right.into()].intersects(Tiles::Wall)
&& self.level[box_position].intersects(Tiles::Floor)
if map[player_position + &left.into()].intersects(Tiles::Wall)
&& map[player_position + &right.into()].intersects(Tiles::Wall)
&& map[box_position + &left.into()].intersects(Tiles::Wall)
&& map[box_position + &right.into()].intersects(Tiles::Wall)
&& map[box_position].intersects(Tiles::Floor)
&& self
.lower_bounds()
.contains_key(&(box_position + &up.into()))
&& !self.level[box_position].intersects(Tiles::Goal)
&& !map[box_position].intersects(Tiles::Goal)
{
tunnels.insert((player_position, up));
}

// . .
// #$_ or _$#
// #@# #@#
if self.level[player_position + &left.into()].intersects(Tiles::Wall)
&& self.level[player_position + &right.into()].intersects(Tiles::Wall)
&& (self.level[box_position + &right.into()].intersects(Tiles::Wall)
&& self.level[box_position + &left.into()].intersects(Tiles::Floor)
|| self.level[box_position + &right.into()].intersects(Tiles::Floor)
&& self.level[box_position + &left.into()].intersects(Tiles::Wall))
&& self.level[box_position].intersects(Tiles::Floor)
if map[player_position + &left.into()].intersects(Tiles::Wall)
&& map[player_position + &right.into()].intersects(Tiles::Wall)
&& (map[box_position + &right.into()].intersects(Tiles::Wall)
&& map[box_position + &left.into()].intersects(Tiles::Floor)
|| map[box_position + &right.into()].intersects(Tiles::Floor)
&& map[box_position + &left.into()].intersects(Tiles::Wall))
&& map[box_position].intersects(Tiles::Floor)
&& self
.lower_bounds()
.contains_key(&(box_position + &up.into()))
&& !self.level[box_position].intersects(Tiles::Goal)
&& !map[box_position].intersects(Tiles::Goal)
{
tunnels.insert((player_position, up));
}
Expand Down Expand Up @@ -202,7 +203,8 @@ impl Solver {
/// Calculates and returns the lower bounds using the minimum push method.
fn minimum_push_lower_bounds(&self) -> HashMap<Vector2<i32>, usize> {
let mut lower_bounds = HashMap::new();
for target_position in self.level.goal_positions() {
let map = self.level.map();
for target_position in map.goal_positions() {
lower_bounds.insert(*target_position, 0);
let mut player_position = None;
for pull_direction in [
Expand All @@ -213,9 +215,9 @@ impl Solver {
] {
let next_box_position = target_position + &pull_direction.into();
let next_player_position = next_box_position + &pull_direction.into();
if self.level.in_bounds(next_player_position)
&& !self.level[next_player_position].intersects(Tiles::Wall)
&& !self.level[next_box_position].intersects(Tiles::Wall)
if map.in_bounds(next_player_position)
&& !map[next_player_position].intersects(Tiles::Wall)
&& !map[next_box_position].intersects(Tiles::Wall)
{
player_position = Some(next_player_position);
break;
Expand All @@ -242,8 +244,9 @@ impl Solver {
lower_bounds: &mut HashMap<Vector2<i32>, usize>,
visited: &mut HashSet<(Vector2<i32>, Direction)>,
) {
let map = self.level.map();
let player_reachable_area = reachable_area(player_position, |position| {
!self.level[position].intersects(Tiles::Wall) && position != box_position
!map[position].intersects(Tiles::Wall) && position != box_position
});
for pull_direction in [
Direction::Up,
Expand All @@ -252,13 +255,13 @@ impl Solver {
Direction::Left,
] {
let next_box_position = box_position + &pull_direction.into();
if self.level[next_box_position].intersects(Tiles::Wall) {
if map[next_box_position].intersects(Tiles::Wall) {
continue;
}

let next_player_position = next_box_position + &pull_direction.into();
if !self.level.in_bounds(next_player_position)
|| self.level[next_player_position].intersects(Tiles::Wall)
if !map.in_bounds(next_player_position)
|| map[next_player_position].intersects(Tiles::Wall)
{
continue;
}
Expand Down Expand Up @@ -286,17 +289,18 @@ impl Solver {
/// Calculates and returns the lower bounds using the minimum move method.
fn minimum_move_lower_bounds(&self) -> HashMap<Vector2<i32>, usize> {
let mut lower_bounds = HashMap::new();
for x in 1..self.level.dimensions().x - 1 {
for y in 1..self.level.dimensions().y - 1 {
let map = self.level.map();
for x in 1..map.dimensions().x - 1 {
for y in 1..map.dimensions().y - 1 {
let position = Vector2::new(x, y);
// There may be situations in the level where the box is
// already on the target and cannot be reached by the player.
if self.level[position].intersects(Tiles::Goal) {
if map[position].intersects(Tiles::Goal) {
lower_bounds.insert(position, 0);
continue;
}
if !self.level[position].intersects(Tiles::Floor)
// || self.level[position].intersects(Tiles::Deadlock)
if !map[position].intersects(Tiles::Floor)
// || map[position].intersects(Tiles::Deadlock)
{
continue;
}
Expand All @@ -305,7 +309,7 @@ impl Solver {
box_pushable_paths_with_positions(&self.level, &position, &HashSet::new());
if let Some(lower_bound) = paths
.iter()
.filter(|path| self.level[path.0.box_position].intersects(Tiles::Goal))
.filter(|path| map[path.0.box_position].intersects(Tiles::Goal))
.map(|path| path.1.len() - 1)
.min()
{
Expand All @@ -319,22 +323,22 @@ impl Solver {
/// Calculates and returns the lower bounds using the Manhattan distance method.
fn manhattan_distance_lower_bounds(&self) -> HashMap<Vector2<i32>, usize> {
let mut lower_bounds = HashMap::new();
for x in 1..self.level.dimensions().x - 1 {
for y in 1..self.level.dimensions().y - 1 {
let map = self.level.map();
for x in 1..map.dimensions().x - 1 {
for y in 1..map.dimensions().y - 1 {
let position = Vector2::new(x, y);
// There may be situations in the level where the box is
// already on the target and cannot be reached by the player.
if self.level[position].intersects(Tiles::Goal) {
if map[position].intersects(Tiles::Goal) {
lower_bounds.insert(position, 0);
continue;
}
if !self.level[position].intersects(Tiles::Floor)
// || self.level.get(&position).intersects(Tiles::Deadlock)
if !map[position].intersects(Tiles::Floor)
// || map.get(&position).intersects(Tiles::Deadlock)
{
continue;
}
let lower_bound = self
.level
let lower_bound = map
.goal_positions()
.iter()
.map(|box_pos| manhattan_distance(box_pos, &position))
Expand Down Expand Up @@ -363,8 +367,9 @@ impl Solver {
/// Prints the lower bounds for each position in the level.
#[allow(dead_code)]
pub fn print_lower_bounds(&self) {
for y in 0..self.level.dimensions().y {
for x in 0..self.level.dimensions().x {
let map = self.level.map();
for y in 0..map.dimensions().y {
for x in 0..map.dimensions().x {
let position = Vector2::new(x, y);
if let Some(lower_bound) = self.lower_bounds().get(&position) {
print!("{:3} ", lower_bound);
Expand Down
9 changes: 5 additions & 4 deletions src/solve/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ impl State {
new_box_positions.insert(new_box_position);

// skip deadlocks
if !solver.level[new_box_position].intersects(Tiles::Goal)
if !solver.level.map()[new_box_position].intersects(Tiles::Goal)
&& deadlock::is_freeze_deadlock(
&solver.level,
solver.level.map(),
new_box_position,
&new_box_positions,
&mut HashSet::new(),
Expand Down Expand Up @@ -209,12 +209,13 @@ impl State {

/// Checks if a position can block the player's movement.
fn can_block_player(&self, position: Vector2<i32>, solver: &Solver) -> bool {
solver.level[position].intersects(Tiles::Wall) || self.box_positions.contains(&position)
solver.level.map()[position].intersects(Tiles::Wall)
|| self.box_positions.contains(&position)
}

/// Checks if a position can block a box's movement.
fn can_block_box(&self, position: Vector2<i32>, solver: &Solver) -> bool {
solver.level[position].intersects(Tiles::Wall /* | Tiles::Deadlock */)
solver.level.map()[position].intersects(Tiles::Wall /* | Tiles::Deadlock */)
|| !solver.lower_bounds().contains_key(&position)
|| self.box_positions.contains(&position)
}
Expand Down
Loading

0 comments on commit e59ca9f

Please sign in to comment.