From 8f6809c17f1292b2e1963ab9052efcc6bfdf2796 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 21 Jan 2024 15:29:20 +0100 Subject: [PATCH] Add candidate selection. --- examples/solve_belt.rs | 2 + src/belt_finding/conflict_avoidance.rs | 159 +++++++++++++++++-------- src/belt_finding/mod.rs | 37 +++++- 3 files changed, 148 insertions(+), 50 deletions(-) diff --git a/examples/solve_belt.rs b/examples/solve_belt.rs index 2bf49a3..26a53ce 100644 --- a/examples/solve_belt.rs +++ b/examples/solve_belt.rs @@ -14,6 +14,7 @@ enum Mode { enum ProblemCase { Level1, Level2, + Level3, } impl ProblemCase { @@ -21,6 +22,7 @@ impl ProblemCase { match self { ProblemCase::Level1 => problems::belt_madness_level_1(), ProblemCase::Level2 => problems::belt_madness_level_2(), + ProblemCase::Level3 => problems::belt_madness_level_3(), } } } diff --git a/src/belt_finding/conflict_avoidance.rs b/src/belt_finding/conflict_avoidance.rs index ee6599f..7318195 100644 --- a/src/belt_finding/conflict_avoidance.rs +++ b/src/belt_finding/conflict_avoidance.rs @@ -20,6 +20,48 @@ pub struct ConflictAvoidance { belts: Vec>, } +#[derive(Debug, PartialEq, Eq)] +struct Candidate { + min: Position, + max: Position, +} + +impl Candidate { + fn new(min: Position, max: Position) -> Self { + Self { min, max } + } + + fn area(&self) -> PositionType { + (self.max.x - self.min.x) * (self.max.y - self.min.y) + } + fn extend_range(&mut self, conflict_map: &Map) { + for x in self.min.x..=self.max.x { + if self.min.y > 0 && *conflict_map.get(x as usize, self.min.y as usize) > 1 { + self.min.y -= 1; + return self.extend_range(conflict_map); + } + if (self.max.y as usize) < conflict_map.height - 1 + && *conflict_map.get(x as usize, self.max.y as usize) > 1 + { + self.max.y += 1; + return self.extend_range(conflict_map); + } + } + for y in self.min.y..=self.max.y { + if self.min.x > 0 && *conflict_map.get(self.min.x as usize, y as usize) > 1 { + self.min.x -= 1; + return self.extend_range(conflict_map); + } + if (self.max.x as usize) < conflict_map.width - 1 + && *conflict_map.get(self.max.x as usize, y as usize) > 1 + { + self.max.x += 1; + return self.extend_range(conflict_map); + } + } + } +} + impl ConflictAvoidance { pub fn new(problem: Problem) -> Self { let mut map: Map = Map::new(problem.map.width, problem.map.height); @@ -50,33 +92,6 @@ impl ConflictAvoidance { Self { map, belts } } - fn extend_range( - conflict_map: &Map, - xrange: &mut RangeInclusive, - yrange: &mut RangeInclusive, - ) { - for x in xrange.clone() { - if *yrange.start() > 0 && *conflict_map.get(x, *yrange.start()) > 1 { - *yrange = *yrange.start() - 1..=*yrange.end(); - return Self::extend_range(conflict_map, xrange, yrange); - } - if *yrange.end() < conflict_map.height - 1 && *conflict_map.get(x, *yrange.end()) > 1 { - *yrange = *yrange.start()..=*yrange.end() + 1; - return Self::extend_range(conflict_map, xrange, yrange); - } - } - for y in yrange.clone() { - if *xrange.start() > 0 && *conflict_map.get(*xrange.start(), y) > 1 { - *xrange = *xrange.start() - 1..=*xrange.end(); - return Self::extend_range(conflict_map, xrange, yrange); - } - if *xrange.end() < conflict_map.width - 1 && *conflict_map.get(*xrange.end(), y) > 1 { - *xrange = *xrange.start()..=*xrange.end() + 1; - return Self::extend_range(conflict_map, xrange, yrange); - } - } - } - pub fn remove_conflict(&mut self) -> bool { let mut conflicts: Map = Map::new(self.map.width, self.map.height); @@ -114,37 +129,32 @@ impl ConflictAvoidance { println!(); } - let mut c = None; + let mut candidates = Vec::new(); + for y in 0..self.map.height { for x in 0..self.map.width { if *conflicts.get(x, y) > 1 { - c = Some((x, y)); - break; + let mut candidate = Candidate::new( + Position::new(x as PositionType, y as PositionType), + Position::new(x as PositionType, y as PositionType), + ); + candidate.extend_range(&conflicts); + if !candidates.iter().any(|c| c == &candidate) { + candidates.push(candidate); + } } } } - let (cx, cy) = match c { - Some(c) => c, - None => { - return false; - } - }; - - let xoffset = 1; - let yoffset = 1; - - let mut xrange = cx..=cx; - let mut yrange = cy..=cy; + if candidates.is_empty() { + return false; + } loop { - xrange = xrange.start().saturating_sub(xoffset) - ..=usize::min(xrange.end() + xoffset, self.map.width - 1); - yrange = yrange.start().saturating_sub(yoffset) - ..=usize::min(yrange.end() + yoffset, self.map.height - 1); - - println!("x: {:?}, y: {:?}", xrange, yrange); - Self::extend_range(&conflicts, &mut xrange, &mut yrange); + candidates.sort_by_key(|c| -c.area()); + let c = candidates.pop().unwrap(); + let mut xrange = c.min.x as usize..=c.max.x as usize; + let mut yrange = c.min.y as usize..=c.max.y as usize; println!("x: {:?}, y: {:?}", xrange, yrange); @@ -261,6 +271,57 @@ impl ConflictAvoidance { } return true; + } else { + let mut candidate = Candidate::new( + Position::new( + xrange.start().saturating_sub(1) as PositionType, + *yrange.start() as PositionType, + ), + Position::new(*xrange.end() as PositionType, *yrange.end() as PositionType), + ); + candidate.extend_range(&conflicts); + if candidate != c && !candidates.iter().any(|c| c == &candidate) { + candidates.push(candidate); + } + let mut candidate = Candidate::new( + Position::new( + *xrange.start() as PositionType, + yrange.start().saturating_sub(1) as PositionType, + ), + Position::new(*xrange.end() as PositionType, *yrange.end() as PositionType), + ); + candidate.extend_range(&conflicts); + if candidate != c && !candidates.iter().any(|c| c == &candidate) { + candidates.push(candidate); + } + let mut candidate = Candidate::new( + Position::new( + *xrange.start() as PositionType, + *yrange.start() as PositionType, + ), + Position::new( + usize::min(xrange.end() + 1, self.map.width - 1) as PositionType, + *yrange.end() as PositionType, + ), + ); + candidate.extend_range(&conflicts); + if candidate != c && !candidates.iter().any(|c| c == &candidate) { + candidates.push(candidate); + } + let mut candidate = Candidate::new( + Position::new( + *xrange.start() as PositionType, + *yrange.start() as PositionType, + ), + Position::new( + *xrange.end() as PositionType, + usize::min(yrange.end() + 1, self.map.height - 1) as PositionType, + ), + ); + candidate.extend_range(&conflicts); + if candidate != c && !candidates.iter().any(|c| c == &candidate) { + candidates.push(candidate); + } } } } diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index d0f0708..d9210b0 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -84,13 +84,19 @@ impl Problem { } } -static COLORS: [Color; 6] = [ +static COLORS: [Color; 12] = [ Color::Red, Color::Green, Color::Yellow, Color::Blue, Color::Magenta, Color::Cyan, + Color::BrightRed, + Color::BrightGreen, + Color::BrightYellow, + Color::BrightBlue, + Color::BrightMagenta, + Color::Cyan, ]; impl Display for Problem { @@ -277,6 +283,35 @@ pub mod problems { } pub fn belt_madness_level_2() -> Problem { + let mut p = Problem::new(17, 13); + p.set_blocked(0, 3, true); + + p.set_blocked_range(1, 2, 2, 5, true); + p.set_blocked_range(1, 7, 2, 10, true); + + p.set_blocked(0, 9, true); + + p.set_blocked(16, 3, true); + + p.set_blocked_range(14, 2, 15, 5, true); + p.set_blocked_range(14, 7, 15, 10, true); + + p.set_blocked(16, 9, true); + + p.add_connection(Position::new(3, 4), Position::new(13, 2)); + p.add_connection(Position::new(3, 7), Position::new(13, 3)); + p.add_connection(Position::new(3, 10), Position::new(13, 4)); + p.add_connection(Position::new(3, 9), Position::new(13, 5)); + + p.add_connection(Position::new(3, 2), Position::new(13, 7)); + p.add_connection(Position::new(3, 3), Position::new(13, 8)); + p.add_connection(Position::new(3, 5), Position::new(13, 9)); + p.add_connection(Position::new(3, 8), Position::new(13, 10)); + + p + } + + pub fn belt_madness_level_3() -> Problem { let mut p = Problem::new(33, 13); p.set_blocked_range(1, 3, 2, 5, true);