Add candidate selection.

This commit is contained in:
hal8174 2024-01-21 15:29:20 +01:00
parent 207a0436d8
commit 8f6809c17f
3 changed files with 148 additions and 50 deletions

View file

@ -14,6 +14,7 @@ enum Mode {
enum ProblemCase { enum ProblemCase {
Level1, Level1,
Level2, Level2,
Level3,
} }
impl ProblemCase { impl ProblemCase {
@ -21,6 +22,7 @@ impl ProblemCase {
match self { match self {
ProblemCase::Level1 => problems::belt_madness_level_1(), ProblemCase::Level1 => problems::belt_madness_level_1(),
ProblemCase::Level2 => problems::belt_madness_level_2(), ProblemCase::Level2 => problems::belt_madness_level_2(),
ProblemCase::Level3 => problems::belt_madness_level_3(),
} }
} }
} }

View file

@ -20,6 +20,48 @@ pub struct ConflictAvoidance {
belts: Vec<Vec<PathField>>, belts: Vec<Vec<PathField>>,
} }
#[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<usize>) {
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 { impl ConflictAvoidance {
pub fn new(problem: Problem) -> Self { pub fn new(problem: Problem) -> Self {
let mut map: Map<Field> = Map::new(problem.map.width, problem.map.height); let mut map: Map<Field> = Map::new(problem.map.width, problem.map.height);
@ -50,33 +92,6 @@ impl ConflictAvoidance {
Self { map, belts } Self { map, belts }
} }
fn extend_range(
conflict_map: &Map<usize>,
xrange: &mut RangeInclusive<usize>,
yrange: &mut RangeInclusive<usize>,
) {
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 { pub fn remove_conflict(&mut self) -> bool {
let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height); let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height);
@ -114,37 +129,32 @@ impl ConflictAvoidance {
println!(); println!();
} }
let mut c = None; let mut candidates = Vec::new();
for y in 0..self.map.height { for y in 0..self.map.height {
for x in 0..self.map.width { for x in 0..self.map.width {
if *conflicts.get(x, y) > 1 { if *conflicts.get(x, y) > 1 {
c = Some((x, y)); let mut candidate = Candidate::new(
break; 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 { if candidates.is_empty() {
Some(c) => c, return false;
None => { }
return false;
}
};
let xoffset = 1;
let yoffset = 1;
let mut xrange = cx..=cx;
let mut yrange = cy..=cy;
loop { loop {
xrange = xrange.start().saturating_sub(xoffset) candidates.sort_by_key(|c| -c.area());
..=usize::min(xrange.end() + xoffset, self.map.width - 1); let c = candidates.pop().unwrap();
yrange = yrange.start().saturating_sub(yoffset) let mut xrange = c.min.x as usize..=c.max.x as usize;
..=usize::min(yrange.end() + yoffset, self.map.height - 1); let mut yrange = c.min.y as usize..=c.max.y as usize;
println!("x: {:?}, y: {:?}", xrange, yrange);
Self::extend_range(&conflicts, &mut xrange, &mut yrange);
println!("x: {:?}, y: {:?}", xrange, yrange); println!("x: {:?}, y: {:?}", xrange, yrange);
@ -261,6 +271,57 @@ impl ConflictAvoidance {
} }
return true; 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);
}
} }
} }
} }

View file

@ -84,13 +84,19 @@ impl Problem {
} }
} }
static COLORS: [Color; 6] = [ static COLORS: [Color; 12] = [
Color::Red, Color::Red,
Color::Green, Color::Green,
Color::Yellow, Color::Yellow,
Color::Blue, Color::Blue,
Color::Magenta, Color::Magenta,
Color::Cyan, Color::Cyan,
Color::BrightRed,
Color::BrightGreen,
Color::BrightYellow,
Color::BrightBlue,
Color::BrightMagenta,
Color::Cyan,
]; ];
impl Display for Problem { impl Display for Problem {
@ -277,6 +283,35 @@ pub mod problems {
} }
pub fn belt_madness_level_2() -> Problem { 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); let mut p = Problem::new(33, 13);
p.set_blocked_range(1, 3, 2, 5, true); p.set_blocked_range(1, 3, 2, 5, true);