basic autosolving

This commit is contained in:
mehbark 2025-07-07 12:14:26 -04:00
parent 767f3bc3b6
commit b0418f3bcd

View file

@ -2,9 +2,11 @@ use std::{
error::Error,
fmt::{self, Display},
io::{self, prelude::*},
process,
};
use bitvec::vec::BitVec;
use pathfinding::prelude::dijkstra;
type Pos = (i16, i16);
@ -50,7 +52,7 @@ impl BoardConsts {
}
}
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
struct Board {
pub player: Pos,
boxes: BitVec,
@ -89,6 +91,41 @@ impl Board {
*self.boxes.get(consts.index_of(pos)).unwrap()
}
pub fn is_won(&self, consts: &BoardConsts) -> bool {
consts.goals.iter_ones().eq(self.boxes.iter_ones())
}
pub fn solid_at(&self, consts: &BoardConsts, pos: Pos) -> bool {
self.box_at(consts, pos) || consts.wall_at(pos)
}
pub fn do_move(&self, consts: &BoardConsts, (dx, dy): Pos) -> Option<Self> {
let p0 = self.player;
let p1 = (p0.0 + dx, p0.1 + dy);
let p2 = (p1.0 + dx, p1.1 + dy);
if !self.solid_at(consts, p1) {
let mut new = self.clone();
new.player = p1;
Some(new)
} else if self.box_at(consts, p1) && !self.solid_at(consts, p2) {
let mut new = self.clone();
new.player = p1;
new.boxes.set(consts.index_of(p1), false);
new.boxes.set(consts.index_of(p2), true);
Some(new)
} else {
None
}
}
pub fn successors(&self, consts: &BoardConsts) -> Vec<Self> {
[(-1, 0), (1, 0), (0, -1), (0, 1)]
.into_iter()
.filter_map(|delta| self.do_move(consts, delta))
.collect()
}
pub fn parse(src: &str) -> Result<(BoardConsts, Board), BoardParseError> {
let width = src.lines().map(str::len).max().unwrap_or(0) as i16;
let mut player = Err(BoardParseError::NoPlayer);
@ -174,5 +211,17 @@ fn main() -> Result<(), Box<dyn Error>> {
let src = io::read_to_string(io::stdin())?;
let (consts, board) = Board::parse(&src)?;
board.write(&consts, &mut io::stdout())?;
let Some((steps, _step_count)) = dijkstra(
&board,
|b| b.successors(&consts).into_iter().map(move |b| (b, 1)),
|b| b.is_won(&consts),
) else {
eprintln!("no solution found :(");
process::exit(1);
};
for (i, step) in steps.into_iter().enumerate() {
eprintln!("step #{i}");
step.write(&consts, &mut io::stdout())?;
}
Ok(())
}