diff --git a/src/bin/maze/main.rs b/src/bin/maze/main.rs index 5d183e0..53738f5 100644 --- a/src/bin/maze/main.rs +++ b/src/bin/maze/main.rs @@ -15,20 +15,31 @@ use pixelfoo::vec2d::Vec2d; #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Square { - Unknown, + Unused, + Unknown { prio: i32 }, Corridor, Wall, Start, Finish, } +impl Square { + pub fn is_unknown(&self) -> bool { + match self { + Square::Unknown { .. } => true, + _ => false, + } + } +} + struct Board(Vec>); fn send(w: &mut T, board: &Board) -> std::io::Result<()> { for line in &board.0 { for square in line { let c = match square { - Square::Unknown => Color::black(), + Square::Unused => Color::black(), + Square::Unknown { .. } => Color::black(), Square::Corridor => Color::yellow(), Square::Wall => Color::darkblue(), Square::Start => Color::red(), @@ -40,6 +51,12 @@ fn send(w: &mut T, board: &Board) -> std::io::Result<()> { w.flush() } +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum Orientation { + Horizontal, + Vertical, +} + impl Board { fn new(board_size: Vec2d, maze_size: Vec2d) -> Board { Board( @@ -56,10 +73,10 @@ impl Board { { Square::Wall } else { - Square::Unknown + Square::Unknown { prio: 0 } } } else { - Square::Unknown + Square::Unused } }) .collect::>() @@ -73,6 +90,81 @@ impl Board { fn set(&mut self, pos: Point2d, sq: Square) { self.0[pos.y as usize][pos.x as usize] = sq; } + + fn set_orientation(&mut self, desired: Orientation, pos: Point2d) { + let sq = self.get(pos); + let actual; + match sq { + Square::Unknown { .. } => { + // determine corridor orientation + if pos.x % 2 == 0 && pos.y % 2 != 0 { + actual = Orientation::Horizontal; + } else if pos.x % 2 != 0 && pos.y % 2 == 0 { + actual = Orientation::Vertical; + } else { + // not a potential wall, unused + actual = Orientation::Horizontal; + } + let prio = if actual == desired { 10 } else { -10 }; + self.set(pos, Square::Unknown { prio }); + } + _ => (), + } + } + fn set_horizontal(&mut self, pos: Point2d) { + self.set_orientation(Orientation::Horizontal, pos); + } + fn set_vertical(&mut self, pos: Point2d) { + self.set_orientation(Orientation::Vertical, pos); + } + fn draw_horizontal_segment(&mut self, pos: Point2d, size: Vec2d) { + for x in 0..size.x { + let xn = size.x - 1 - x; + self.set_horizontal(pos + v2d(x, 0)); + for y in 1..x.min(xn).min(size.y / 2) + 1 { + self.set_horizontal(pos + v2d(x, y)); + self.set_horizontal(pos + v2d(x, -y)); + } + } + } + fn draw_vertical_segment(&mut self, pos: Point2d, size: Vec2d) { + for y in 0..size.y { + let yn = size.y - 1 - y; + self.set_vertical(pos + v2d(0, y)); + for x in 1..y.min(yn).min(size.x / 2) + 1 { + self.set_vertical(pos + v2d(x, y)); + self.set_vertical(pos + v2d(-x, y)); + } + } + } + fn draw_7_segments(&mut self, pos: Point2d, size: Vec2d, segments: u8) { + let length = size.x; + let width = size.y; + let delta = length + 1; + let hsize = v2d(length, width); + let vsize = v2d(width, length); + if (segments & (1 << 0)) != 0 { + self.draw_horizontal_segment(pos + v2d(1, 0), hsize); + } + if (segments & (1 << 1)) != 0 { + self.draw_vertical_segment(pos + v2d(delta, 1), vsize); + } + if (segments & (1 << 2)) != 0 { + self.draw_vertical_segment(pos + v2d(delta, delta + 1), vsize); + } + if (segments & (1 << 3)) != 0 { + self.draw_horizontal_segment(pos + v2d(1, 2 * delta), hsize); + } + if (segments & (1 << 4)) != 0 { + self.draw_vertical_segment(pos + v2d(0, 1), vsize); + } + if (segments & (1 << 5)) != 0 { + self.draw_vertical_segment(pos + v2d(0, delta + 1), vsize); + } + if (segments & (1 << 6)) != 0 { + self.draw_horizontal_segment(pos + v2d(1, delta), hsize); + } + } } struct Move { @@ -81,9 +173,17 @@ struct Move { prio: i32, } -fn add_move(open: &mut Vec, arg: isize, from: Point2d, dir: Vec2d) { - open.push(Move { from, dir, prio: 0 }); - open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb)); +fn add_move(board: &Board, open: &mut Vec, rng: &mut R, from: Point2d, dir: Vec2d) +where + R: Rng, +{ + if let Square::Unknown { prio } = board.get(from + dir) { + open.push(Move { + from, + dir, + prio: prio * 100 + rng.gen_range(0, 1000), + }); + } } const DEFAULT_ARG: isize = 16; @@ -122,12 +222,19 @@ fn main() -> std::io::Result<()> { t_wait = 60.0; // s board = Board::new(board_size, maze_size); + // draw stuff in prios + let segment_size = v2d(11, 5); + board.draw_7_segments(p2d(6, 8), segment_size, 0x06); + board.draw_7_segments(p2d(24, 8), segment_size, 0x4f); + board.draw_7_segments(p2d(42, 8), segment_size, 0x4f); + board.draw_7_segments(p2d(60, 8), segment_size, 0x07); + // start in the middle board.set(maze_mid, Square::Corridor); - add_move(&mut open, arg, maze_mid, v2d(1, 0)); - add_move(&mut open, arg, maze_mid, v2d(0, 1)); - add_move(&mut open, arg, maze_mid, v2d(-1, 0)); - add_move(&mut open, arg, maze_mid, v2d(0, -1)); + add_move(&board, &mut open, &mut rng, maze_mid, v2d(1, 0)); + add_move(&board, &mut open, &mut rng, maze_mid, v2d(0, 1)); + add_move(&board, &mut open, &mut rng, maze_mid, v2d(-1, 0)); + add_move(&board, &mut open, &mut rng, maze_mid, v2d(0, -1)); } } @@ -135,41 +242,25 @@ fn main() -> std::io::Result<()> { let work = arg.max(1); let mut count = 0; while !open.is_empty() && count < work { - let mut start = 0; - let mut limit = 0; - let mut prio = open[limit].prio; - loop { - limit += 1; - if limit >= open.len() { - break; - } - if open[limit].prio > prio { - if rng.gen::() >= 0.4 { - break; - } - start = limit; - prio = open[limit].prio; - } - } - let r = rng.gen_range(start, limit); + open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb)); let Move { from: p0, dir: dir0, .. - } = open.remove(r); + } = open.pop().unwrap(); let p1 = p0 + dir0; let p2 = p1 + dir0; - if board.get(p1) == Square::Unknown { + if board.get(p1).is_unknown() { board.set(p1, Square::Corridor); board.set(p2, Square::Corridor); for dir1 in Vec2d::directions() { let p3 = p2 + dir1; let p4 = p3 + dir1; - if board.get(p3) == Square::Unknown { - if board.get(p4) == Square::Unknown { - add_move(&mut open, arg, p2, dir1); + if board.get(p3).is_unknown() { + if board.get(p4).is_unknown() { + add_move(&board, &mut open, &mut rng, p2, dir1); } else { board.set(p3, Square::Wall); }