use std::str::FromStr;
use soukoban::{prelude::*, solver::*};
mod utils;
use utils::*;
#[test]
fn a_star_search() {
fn search(mut level: Level, strategy: Strategy) -> Actions {
let solver = Solver::new(level.map().clone(), strategy);
let solution = solver.search(Algorithm::AStar).unwrap();
let directions = solution.iter().map(|action| action.direction());
level.execute_batch(directions).unwrap();
assert!(level.is_solved());
solution
}
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 3),
Strategy::Quick,
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::PushOptimal,
)
.shifts(),
Actions::from_str("DuLLrUUdrR").unwrap().shifts()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::MoveOptimal,
)
.moves(),
Actions::from_str("DuLLrUUdrR").unwrap().moves()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::PushOptimal,
)
.shifts(),
Actions::from_str(
"rr4DrddlluRdrUl5ulldRur4D3RdrUUd3lddlluRdrUl4ulldRur3D3RdrU3lddlluRdrUlu3R"
)
.unwrap()
.shifts()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::MoveOptimal,
)
.moves(),
Actions::from_str(
"rr4DrddlluRdrUl5ulldRur4D3RdrUUd3lddlluRdrUl4ulldRur3D3RdrU3lddlluRdrUlu3R"
)
.unwrap()
.moves()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 3),
Strategy::PushOptimal,
)
.shifts(),
Actions::from_str(
"rRRddrruULuu4l3D3u4rdd3L3ruu4ldDldRu6ruLd5luu4rDrd4LDu3ruu4ldDldRu3rddrUru4L3ruu4ldD"
)
.unwrap()
.shifts()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 3),
Strategy::MoveOptimal,
)
.shifts(),
Actions::from_str(
"rRRddrruULuu4l3D3u4rdd3L3ruu4ldDldRu6ruLd5luu4rDrd4LDu3ruu4ldDldRu3rddrUru4L3ruu4ldD"
)
.unwrap()
.shifts()
);
search(
load_level_from_file("assets/Aymeric_Du_Peloux_282.xsb", 67),
Strategy::Quick,
);
search(
load_level_from_file("assets/Aymeric_Du_Peloux_282.xsb", 78),
Strategy::Quick,
);
}
#[test]
fn ida_star_search() {
fn search(mut level: Level, strategy: Strategy) -> Actions {
let solver = Solver::new(level.map().clone(), strategy);
let solution = solver.search(Algorithm::IDAStar).unwrap();
let directions = solution.iter().map(|action| action.direction());
level.execute_batch(directions).unwrap();
assert!(level.is_solved());
solution
}
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 3),
Strategy::Quick,
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::PushOptimal,
)
.shifts(),
Actions::from_str("DuLLrUUdrR").unwrap().shifts()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::MoveOptimal,
)
.moves(),
Actions::from_str("DuLLrUUdrR").unwrap().moves()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::PushOptimal,
)
.shifts(),
Actions::from_str(
"rr4DrddlluRdrUl5ulldRur4D3RdrUUd3lddlluRdrUl4ulldRur3D3RdrU3lddlluRdrUlu3R"
)
.unwrap()
.shifts()
);
assert_eq!(
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::MoveOptimal,
)
.moves(),
Actions::from_str(
"rr4DrddlluRdrUl5ulldRur4D3RdrUUd3lddlluRdrUl4ulldRur3D3RdrU3lddlluRdrUlu3R"
)
.unwrap()
.moves()
);
}
#[test]
fn bfs_search() {
fn search(mut level: Level, strategy: Strategy) -> Actions {
let solver = Solver::new(level.map().clone(), strategy);
let solution = solver.search(Algorithm::Bfs).unwrap();
let directions = solution.iter().map(|action| action.direction());
level.execute_batch(directions).unwrap();
assert!(level.is_solved());
solution
}
search(
load_level_from_file("assets/BoxWorld_100.xsb", 1),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 2),
Strategy::Quick,
);
search(
load_level_from_file("assets/BoxWorld_100.xsb", 3),
Strategy::Quick,
);
}
#[test]
fn request_stop() {
let level = load_level_from_file("assets/Grigr2001_100.xsb", 1);
let solver = Solver::new(level.into(), Strategy::Quick);
let handler = std::thread::spawn({
let solver = solver.clone();
move || solver.search(Algorithm::AStar)
});
std::thread::sleep(std::time::Duration::from_secs(1));
solver.request_stop();
let result = handler.join().unwrap();
assert_eq!(result, Err(SearchError::Interrupted));
}
#[test]
fn min_costs() {
let level = load_level_from_file("assets/Aymeric_Du_Peloux_282.xsb", 67);
let solver = Solver::new(level.into(), Strategy::Quick);
assert_eq!(solver.context().min_costs().len(), 8);
let level = load_level_from_file("assets/Aymeric_Du_Peloux_282.xsb", 78);
let solver = Solver::new(level.into(), Strategy::Quick);
assert_eq!(solver.context().min_costs().len(), 8);
}
#[test]
fn tunnels() {
let level = load_level_from_file("assets/BoxWorld_100.xsb", 2);
let solver = Solver::new(level.into(), Strategy::Quick);
assert_eq!(solver.context().tunnels().len(), 4);
}