Adapt methods from dual maze to original maze.

This commit is contained in:
Juergen Stuber 2018-12-02 14:39:59 +01:00
parent 045f03374d
commit 85ff8c6c62

View File

@ -15,20 +15,31 @@ use pixelfoo::vec2d::Vec2d;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Square { enum Square {
Unknown, Unused,
Unknown { prio: i32 },
Corridor, Corridor,
Wall, Wall,
Start, Start,
Finish, Finish,
} }
impl Square {
pub fn is_unknown(&self) -> bool {
match self {
Square::Unknown { .. } => true,
_ => false,
}
}
}
struct Board(Vec<Vec<Square>>); struct Board(Vec<Vec<Square>>);
fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> { fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> {
for line in &board.0 { for line in &board.0 {
for square in line { for square in line {
let c = match square { let c = match square {
Square::Unknown => Color::black(), Square::Unused => Color::black(),
Square::Unknown { .. } => Color::black(),
Square::Corridor => Color::yellow(), Square::Corridor => Color::yellow(),
Square::Wall => Color::darkblue(), Square::Wall => Color::darkblue(),
Square::Start => Color::red(), Square::Start => Color::red(),
@ -40,6 +51,12 @@ fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> {
w.flush() w.flush()
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Orientation {
Horizontal,
Vertical,
}
impl Board { impl Board {
fn new(board_size: Vec2d, maze_size: Vec2d) -> Board { fn new(board_size: Vec2d, maze_size: Vec2d) -> Board {
Board( Board(
@ -56,10 +73,10 @@ impl Board {
{ {
Square::Wall Square::Wall
} else { } else {
Square::Unknown Square::Unknown { prio: 0 }
} }
} else { } else {
Square::Unknown Square::Unused
} }
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
@ -73,6 +90,81 @@ impl Board {
fn set(&mut self, pos: Point2d, sq: Square) { fn set(&mut self, pos: Point2d, sq: Square) {
self.0[pos.y as usize][pos.x as usize] = sq; 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 { struct Move {
@ -81,9 +173,17 @@ struct Move {
prio: i32, prio: i32,
} }
fn add_move(open: &mut Vec<Move>, arg: isize, from: Point2d, dir: Vec2d) { fn add_move<R>(board: &Board, open: &mut Vec<Move>, rng: &mut R, from: Point2d, dir: Vec2d)
open.push(Move { from, dir, prio: 0 }); where
open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb)); 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; const DEFAULT_ARG: isize = 16;
@ -122,12 +222,19 @@ fn main() -> std::io::Result<()> {
t_wait = 60.0; // s t_wait = 60.0; // s
board = Board::new(board_size, maze_size); 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 // start in the middle
board.set(maze_mid, Square::Corridor); board.set(maze_mid, Square::Corridor);
add_move(&mut open, arg, maze_mid, v2d(1, 0)); add_move(&board, &mut open, &mut rng, 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(0, 1));
add_move(&mut open, arg, maze_mid, v2d(-1, 0)); add_move(&board, &mut open, &mut rng, 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(0, -1));
} }
} }
@ -135,41 +242,25 @@ fn main() -> std::io::Result<()> {
let work = arg.max(1); let work = arg.max(1);
let mut count = 0; let mut count = 0;
while !open.is_empty() && count < work { while !open.is_empty() && count < work {
let mut start = 0; open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb));
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::<f64>() >= 0.4 {
break;
}
start = limit;
prio = open[limit].prio;
}
}
let r = rng.gen_range(start, limit);
let Move { let Move {
from: p0, from: p0,
dir: dir0, dir: dir0,
.. ..
} = open.remove(r); } = open.pop().unwrap();
let p1 = p0 + dir0; let p1 = p0 + dir0;
let p2 = p1 + dir0; let p2 = p1 + dir0;
if board.get(p1) == Square::Unknown { if board.get(p1).is_unknown() {
board.set(p1, Square::Corridor); board.set(p1, Square::Corridor);
board.set(p2, Square::Corridor); board.set(p2, Square::Corridor);
for dir1 in Vec2d::directions() { for dir1 in Vec2d::directions() {
let p3 = p2 + dir1; let p3 = p2 + dir1;
let p4 = p3 + dir1; let p4 = p3 + dir1;
if board.get(p3) == Square::Unknown { if board.get(p3).is_unknown() {
if board.get(p4) == Square::Unknown { if board.get(p4).is_unknown() {
add_move(&mut open, arg, p2, dir1); add_move(&board, &mut open, &mut rng, p2, dir1);
} else { } else {
board.set(p3, Square::Wall); board.set(p3, Square::Wall);
} }