Initial conflict avoidance.
This commit is contained in:
parent
9751764611
commit
993fb0730c
4 changed files with 480 additions and 185 deletions
|
|
@ -1,57 +1,55 @@
|
||||||
use factorio_blueprint::belt_finding::{common::Position, Problem};
|
use clap::{Parser, ValueEnum};
|
||||||
|
use factorio_blueprint::belt_finding::{conflict_avoidance::ConflictAvoidance, problems, Problem};
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Clone)]
|
||||||
|
enum Mode {
|
||||||
|
Solve,
|
||||||
|
ConflictAvoidance,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(ValueEnum, Clone)]
|
||||||
|
enum ProblemCase {
|
||||||
|
Level1,
|
||||||
|
Level2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProblemCase {
|
||||||
|
fn get_problem(&self) -> Problem {
|
||||||
|
match self {
|
||||||
|
ProblemCase::Level1 => problems::belt_madness_level_1(),
|
||||||
|
ProblemCase::Level2 => problems::belt_madness_level_2(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
#[arg(value_enum, default_value = "level1")]
|
||||||
|
problem: ProblemCase,
|
||||||
|
#[arg(value_enum, default_value = "solve")]
|
||||||
|
mode: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut p = Problem::new(17, 13);
|
let args = Args::parse();
|
||||||
|
|
||||||
p.set_blocked(0, 3, true);
|
let mut p = args.problem.get_problem();
|
||||||
|
|
||||||
p.set_blocked(1, 4, true);
|
|
||||||
p.set_blocked(2, 4, true);
|
|
||||||
p.set_blocked(1, 5, true);
|
|
||||||
p.set_blocked(2, 5, true);
|
|
||||||
|
|
||||||
p.set_blocked(1, 7, true);
|
|
||||||
p.set_blocked(2, 7, true);
|
|
||||||
p.set_blocked(1, 8, true);
|
|
||||||
p.set_blocked(2, 8, true);
|
|
||||||
|
|
||||||
p.set_blocked(0, 9, true);
|
|
||||||
|
|
||||||
p.set_blocked(16, 3, true);
|
|
||||||
|
|
||||||
p.set_blocked(14, 4, true);
|
|
||||||
p.set_blocked(15, 4, true);
|
|
||||||
p.set_blocked(14, 5, true);
|
|
||||||
p.set_blocked(15, 5, true);
|
|
||||||
|
|
||||||
p.set_blocked(14, 7, true);
|
|
||||||
p.set_blocked(15, 7, true);
|
|
||||||
p.set_blocked(14, 8, true);
|
|
||||||
p.set_blocked(15, 8, true);
|
|
||||||
|
|
||||||
p.set_blocked(16, 9, true);
|
|
||||||
|
|
||||||
p.add_connection(Position::new(3, 7), Position::new(13, 4));
|
|
||||||
p.add_connection(Position::new(3, 8), Position::new(13, 5));
|
|
||||||
|
|
||||||
p.add_connection(Position::new(3, 4), Position::new(13, 8));
|
|
||||||
p.add_connection(Position::new(3, 5), Position::new(13, 7));
|
|
||||||
|
|
||||||
// p.set_blocked(8, 12, true);
|
|
||||||
// p.set_blocked(8, 11, true);
|
|
||||||
// p.set_blocked(8, 10, true);
|
|
||||||
// p.set_blocked(8, 9, true);
|
|
||||||
// p.set_blocked(8, 8, true);
|
|
||||||
// p.set_blocked(8, 7, true);
|
|
||||||
// p.set_blocked(8, 6, true);
|
|
||||||
// p.set_blocked(8, 5, true);
|
|
||||||
// p.set_blocked(8, 4, true);
|
|
||||||
// p.set_blocked(8, 3, true);
|
|
||||||
// p.set_blocked(8, 2, true);
|
|
||||||
// p.set_blocked(8, 1, true);
|
|
||||||
// p.set_blocked(8, 0, true);
|
|
||||||
|
|
||||||
|
match args.mode {
|
||||||
|
Mode::Solve => {
|
||||||
println!("{}", p);
|
println!("{}", p);
|
||||||
p.find_path();
|
p.find_path();
|
||||||
println!("{}", p);
|
println!("{}", p);
|
||||||
}
|
}
|
||||||
|
Mode::ConflictAvoidance => {
|
||||||
|
println!("{}", p);
|
||||||
|
p.find_path();
|
||||||
|
println!("{}", p);
|
||||||
|
let mut c = ConflictAvoidance::new(p);
|
||||||
|
println!("{}", c);
|
||||||
|
while c.remove_conflict() {
|
||||||
|
println!("{}", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub enum Direction {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Direction {
|
impl Direction {
|
||||||
pub fn from_neghbors(pos: &Position, neighbor: &Position) -> Self {
|
pub fn from_neighbors(pos: &Position, neighbor: &Position) -> Self {
|
||||||
let x_diff = pos.x as i64 - neighbor.x as i64;
|
let x_diff = pos.x as i64 - neighbor.x as i64;
|
||||||
let y_diff = pos.y as i64 - neighbor.y as i64;
|
let y_diff = pos.y as i64 - neighbor.y as i64;
|
||||||
|
|
||||||
|
|
@ -143,4 +143,24 @@ impl PathField {
|
||||||
.map(|p| (p, *dir)),
|
.map(|p| (p, *dir)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self, offset: (i32, i32)) -> Self {
|
||||||
|
match self {
|
||||||
|
PathField::Belt { pos, dir } => PathField::Belt {
|
||||||
|
pos: Position::new(
|
||||||
|
(pos.x as i32 + offset.0) as usize,
|
||||||
|
(pos.y as i32 + offset.1) as usize,
|
||||||
|
),
|
||||||
|
dir: *dir,
|
||||||
|
},
|
||||||
|
PathField::Underground { pos, dir, len } => PathField::Underground {
|
||||||
|
pos: Position::new(
|
||||||
|
(pos.x as i32 + offset.0) as usize,
|
||||||
|
(pos.y as i32 + offset.1) as usize,
|
||||||
|
),
|
||||||
|
dir: *dir,
|
||||||
|
len: *len,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
335
src/belt_finding/conflict_avoidance.rs
Normal file
335
src/belt_finding/conflict_avoidance.rs
Normal file
|
|
@ -0,0 +1,335 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use colored::Colorize;
|
||||||
|
|
||||||
|
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
common::{Dimension, Direction, PathField, Position},
|
||||||
|
Problem, COLORS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Field {
|
||||||
|
blocked: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ConflictAvoidance {
|
||||||
|
map: Map<Field>,
|
||||||
|
belts: Vec<Vec<PathField>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConflictAvoidance {
|
||||||
|
pub fn new(problem: Problem) -> Self {
|
||||||
|
let mut map: Map<Field> = Map::new(problem.map.width, problem.map.height);
|
||||||
|
for x in 0..problem.map.width {
|
||||||
|
for y in 0..problem.map.height {
|
||||||
|
map.get_mut(x, y).blocked = problem.map.get(x, y).blocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut belts = Vec::new();
|
||||||
|
for i in 0..problem.path.len() {
|
||||||
|
let mut p = Vec::new();
|
||||||
|
|
||||||
|
for j in 0..problem.path[i].len() - 1 {
|
||||||
|
p.push(PathField::Belt {
|
||||||
|
pos: problem.path[i][j],
|
||||||
|
dir: Direction::from_neighbors(&problem.path[i][j], &problem.path[i][j + 1]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
p.push(PathField::Belt {
|
||||||
|
pos: *problem.path[i].last().unwrap(),
|
||||||
|
dir: *p.last().unwrap().dir(),
|
||||||
|
});
|
||||||
|
|
||||||
|
belts.push(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { map, belts }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_conflict(&mut self) -> bool {
|
||||||
|
let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height);
|
||||||
|
|
||||||
|
for x in 0..self.map.width {
|
||||||
|
for y in 0..self.map.height {
|
||||||
|
if self.map.get(x, y).blocked {
|
||||||
|
*conflicts.get_mut(x, y) += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for path in &self.belts {
|
||||||
|
for p in path {
|
||||||
|
match p {
|
||||||
|
PathField::Belt { pos, dir: _ } => *conflicts.get_mut(pos.x, pos.y) += 1,
|
||||||
|
PathField::Underground { pos, dir, len } => {
|
||||||
|
*conflicts.get_mut(pos.x, pos.y) += 1;
|
||||||
|
let end = pos
|
||||||
|
.in_direction(
|
||||||
|
dir,
|
||||||
|
*len as usize,
|
||||||
|
&Dimension {
|
||||||
|
width: self.map.width,
|
||||||
|
height: self.map.height,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
*conflicts.get_mut(end.x, end.y) += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in 0..self.map.height {
|
||||||
|
for x in 0..self.map.width {
|
||||||
|
if *conflicts.get(x, y) > 1 {
|
||||||
|
print!("#");
|
||||||
|
} else {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut c = None;
|
||||||
|
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 (cx, cy) = match c {
|
||||||
|
Some(c) => c,
|
||||||
|
None => {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut xoffset = 0;
|
||||||
|
let mut yoffset = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
xoffset += 1;
|
||||||
|
yoffset += 1;
|
||||||
|
|
||||||
|
let xrange = cx..=cx;
|
||||||
|
let yrange = cy..=cy;
|
||||||
|
|
||||||
|
let xrange = xrange.start().saturating_sub(xoffset)
|
||||||
|
..=usize::min(xrange.end() + xoffset, self.map.width - 1);
|
||||||
|
let yrange = yrange.start().saturating_sub(yoffset)
|
||||||
|
..=usize::min(yrange.end() + yoffset, self.map.height - 1);
|
||||||
|
|
||||||
|
println!("x: {:?}, y: {:?}", xrange, yrange);
|
||||||
|
|
||||||
|
let xsize = xrange.end() - xrange.start() + 1;
|
||||||
|
let ysize = yrange.end() - yrange.start() + 1;
|
||||||
|
|
||||||
|
// dbg!(xsize, ysize);
|
||||||
|
|
||||||
|
let mut b = BruteforceBuilder::new(xsize + 2, ysize + 2);
|
||||||
|
b.set_blocked_range(0, 0, xsize + 1, 0, true);
|
||||||
|
b.set_blocked_range(0, ysize + 1, xsize + 1, ysize + 1, true);
|
||||||
|
b.set_blocked_range(0, 0, 0, ysize + 1, true);
|
||||||
|
b.set_blocked_range(xsize + 1, 0, xsize + 1, ysize + 1, true);
|
||||||
|
|
||||||
|
for x in 0..xsize {
|
||||||
|
for y in 0..ysize {
|
||||||
|
b.set_blocked(
|
||||||
|
x + 1,
|
||||||
|
y + 1,
|
||||||
|
self.map.get(xrange.start() + x, yrange.start() + y).blocked,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut mapping = Vec::new();
|
||||||
|
|
||||||
|
for (i, path) in self.belts.iter().enumerate() {
|
||||||
|
let s = path
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.pos())
|
||||||
|
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
||||||
|
.map(|i| i.saturating_sub(1));
|
||||||
|
let e = path
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.pos())
|
||||||
|
.rev()
|
||||||
|
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
||||||
|
.map(|i| usize::min(path.len() - 1, path.len() - i));
|
||||||
|
|
||||||
|
if let Some((start, end)) = s.zip(e) {
|
||||||
|
// dbg!(start, end);
|
||||||
|
mapping.push((i, start, end));
|
||||||
|
|
||||||
|
// dbg!(path[start], path[end]);
|
||||||
|
|
||||||
|
let (start_pos, start_dir) = path[start]
|
||||||
|
.end_pos(&Dimension {
|
||||||
|
width: self.map.width,
|
||||||
|
height: self.map.height,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
let end_pos = path[end].pos();
|
||||||
|
let end_dir = path[end].dir();
|
||||||
|
|
||||||
|
// dbg!(start_pos, end_pos);
|
||||||
|
|
||||||
|
b.add_path(
|
||||||
|
(
|
||||||
|
Position::new(
|
||||||
|
start_pos.x - (xrange.start() - 1),
|
||||||
|
start_pos.y - (yrange.start() - 1),
|
||||||
|
),
|
||||||
|
start_dir,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Position::new(
|
||||||
|
end_pos.x - (xrange.start() - 1),
|
||||||
|
end_pos.y - (yrange.start() - 1),
|
||||||
|
),
|
||||||
|
*end_dir,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{:?}", mapping);
|
||||||
|
|
||||||
|
let mut b = b.build();
|
||||||
|
|
||||||
|
println!("{}", b);
|
||||||
|
|
||||||
|
let mut min_cost = f64::INFINITY;
|
||||||
|
let mut solutions = Vec::new();
|
||||||
|
|
||||||
|
while b.next_finish_state() {
|
||||||
|
// println!("{}", b);
|
||||||
|
let c = b.cost();
|
||||||
|
if c < min_cost {
|
||||||
|
min_cost = c;
|
||||||
|
solutions = b.get_paths();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", b.solution_count());
|
||||||
|
|
||||||
|
if b.solution_count() > 0 {
|
||||||
|
for (p, (index, start, end)) in solutions.iter().zip(mapping) {
|
||||||
|
let mut t = Vec::new();
|
||||||
|
|
||||||
|
t.extend_from_slice(&self.belts[index][0..=start]);
|
||||||
|
t.extend(p[1..].iter().map(|p| {
|
||||||
|
p.offset(((*xrange.start() as i32) - 1, (*yrange.start() as i32) - 1))
|
||||||
|
}));
|
||||||
|
t.extend_from_slice(&self.belts[index][end..]);
|
||||||
|
// println!("{:?}", &t);
|
||||||
|
// println!("{:?}", &self.belts[index]);
|
||||||
|
|
||||||
|
self.belts[index] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_all_conflicts(&mut self) {
|
||||||
|
while self.remove_conflict() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ConflictAvoidance {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let width_digits = self.map.width.ilog10() + 1;
|
||||||
|
let height_digits = self.map.height.ilog10() + 1;
|
||||||
|
|
||||||
|
// print header
|
||||||
|
for i in 0..width_digits {
|
||||||
|
let d = width_digits - i - 1;
|
||||||
|
// padding
|
||||||
|
for _ in 0..height_digits {
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for x in 0..self.map.width {
|
||||||
|
let digits = x / (usize::pow(10, d));
|
||||||
|
if digits == 0 && d > 0 {
|
||||||
|
write!(f, " ")?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", char::from_u32((digits % 10) as u32 + 48).unwrap())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
|
||||||
|
|
||||||
|
for (i, problem) in self.belts.iter().enumerate() {
|
||||||
|
for p in problem {
|
||||||
|
match p {
|
||||||
|
PathField::Belt { pos, dir } => match dir {
|
||||||
|
Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))),
|
||||||
|
Direction::Right => m.set(pos.x, pos.y, Some((i, "→"))),
|
||||||
|
Direction::Down => m.set(pos.x, pos.y, Some((i, "↓"))),
|
||||||
|
Direction::Left => m.set(pos.x, pos.y, Some((i, "←"))),
|
||||||
|
},
|
||||||
|
PathField::Underground { pos, dir, len } => {
|
||||||
|
match dir {
|
||||||
|
Direction::Up => m.set(pos.x, pos.y, Some((i, "↟"))),
|
||||||
|
Direction::Right => m.set(pos.x, pos.y, Some((i, "↠"))),
|
||||||
|
Direction::Down => m.set(pos.x, pos.y, Some((i, "↡"))),
|
||||||
|
Direction::Left => m.set(pos.x, pos.y, Some((i, "↞"))),
|
||||||
|
};
|
||||||
|
let end_pos = pos
|
||||||
|
.in_direction(
|
||||||
|
dir,
|
||||||
|
*len as usize,
|
||||||
|
&Dimension {
|
||||||
|
width: self.map.width,
|
||||||
|
height: self.map.height,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
match dir {
|
||||||
|
Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, "↥"))),
|
||||||
|
Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, "↦"))),
|
||||||
|
Direction::Down => m.set(end_pos.x, end_pos.y, Some((i, "↧"))),
|
||||||
|
Direction::Left => m.set(end_pos.x, end_pos.y, Some((i, "↤"))),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let last_pos = problem.last().unwrap().pos();
|
||||||
|
m.set(last_pos.x, last_pos.y, Some((i, "T")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print body
|
||||||
|
|
||||||
|
for y in 0..self.map.height {
|
||||||
|
write!(f, "{:1$}", y, height_digits as usize)?;
|
||||||
|
|
||||||
|
for x in 0..self.map.width {
|
||||||
|
if let Some((i, c)) = m.get(x, y) {
|
||||||
|
write!(f, "{}", c.color(COLORS[*i]))?;
|
||||||
|
} else if self.map.get(x, y).blocked {
|
||||||
|
write!(f, "#")?;
|
||||||
|
} else if x % 8 == 0 || y % 8 == 0 {
|
||||||
|
write!(f, "∙")?;
|
||||||
|
} else {
|
||||||
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ use self::common::Position;
|
||||||
|
|
||||||
pub mod brute_force;
|
pub mod brute_force;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
pub mod conflict_avoidance;
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy)]
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
|
|
@ -216,137 +217,78 @@ impl Problem {
|
||||||
self.path[i] = p;
|
self.path[i] = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height);
|
|
||||||
|
|
||||||
for x in 0..self.map.width {
|
|
||||||
for y in 0..self.map.height {
|
|
||||||
if self.map.get(x, y).blocked {
|
|
||||||
*conflicts.get_mut(x, y) += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for path in &self.path {
|
|
||||||
for pos in path {
|
|
||||||
*conflicts.get_mut(pos.x, pos.y) += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for y in 0..self.map.height {
|
pub mod problems {
|
||||||
for x in 0..self.map.width {
|
use super::{common::Position, Problem};
|
||||||
if *conflicts.get(x, y) > 1 {
|
|
||||||
print!("#");
|
pub fn belt_madness_level_1() -> Problem {
|
||||||
} else {
|
let mut p = Problem::new(17, 13);
|
||||||
print!(" ");
|
|
||||||
}
|
p.set_blocked(0, 3, true);
|
||||||
}
|
|
||||||
println!();
|
p.set_blocked(1, 4, true);
|
||||||
|
p.set_blocked(2, 4, true);
|
||||||
|
p.set_blocked(1, 5, true);
|
||||||
|
p.set_blocked(2, 5, true);
|
||||||
|
|
||||||
|
p.set_blocked(1, 7, true);
|
||||||
|
p.set_blocked(2, 7, true);
|
||||||
|
p.set_blocked(1, 8, true);
|
||||||
|
p.set_blocked(2, 8, true);
|
||||||
|
|
||||||
|
p.set_blocked(0, 9, true);
|
||||||
|
|
||||||
|
p.set_blocked(16, 3, true);
|
||||||
|
|
||||||
|
p.set_blocked(14, 4, true);
|
||||||
|
p.set_blocked(15, 4, true);
|
||||||
|
p.set_blocked(14, 5, true);
|
||||||
|
p.set_blocked(15, 5, true);
|
||||||
|
|
||||||
|
p.set_blocked(14, 7, true);
|
||||||
|
p.set_blocked(15, 7, true);
|
||||||
|
p.set_blocked(14, 8, true);
|
||||||
|
p.set_blocked(15, 8, true);
|
||||||
|
|
||||||
|
p.set_blocked(16, 9, true);
|
||||||
|
|
||||||
|
p.add_connection(Position::new(3, 7), Position::new(13, 4));
|
||||||
|
p.add_connection(Position::new(3, 8), Position::new(13, 5));
|
||||||
|
|
||||||
|
p.add_connection(Position::new(3, 4), Position::new(13, 8));
|
||||||
|
p.add_connection(Position::new(3, 5), Position::new(13, 7));
|
||||||
|
|
||||||
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{self}");
|
pub fn belt_madness_level_2() -> Problem {
|
||||||
|
let mut p = Problem::new(33, 13);
|
||||||
|
|
||||||
loop {
|
p.set_blocked_range(1, 3, 2, 5, true);
|
||||||
let mut c = None;
|
p.set_blocked_range(1, 7, 2, 9, true);
|
||||||
for y in 0..self.map.height {
|
|
||||||
for x in 0..self.map.width {
|
p.set_blocked(0, 3, true);
|
||||||
if *conflicts.get(x, y) > 1 {
|
p.set_blocked(0, 8, true);
|
||||||
c = Some((x, y));
|
|
||||||
break;
|
p.set_blocked_range(10, 0, 21, 2, true);
|
||||||
}
|
p.set_blocked_range(10, 5, 21, 7, true);
|
||||||
}
|
p.set_blocked_range(10, 10, 21, 12, true);
|
||||||
}
|
|
||||||
|
p.set_blocked_range(30, 3, 31, 5, true);
|
||||||
dbg!(c);
|
p.set_blocked_range(30, 7, 31, 9, true);
|
||||||
|
p.set_blocked(32, 3, true);
|
||||||
let xoffset = 2;
|
p.set_blocked(32, 9, true);
|
||||||
let yoffset = 2;
|
|
||||||
|
p.add_connection(Position::new(3, 3), Position::new(29, 7));
|
||||||
if let Some((cx, cy)) = c {
|
p.add_connection(Position::new(3, 4), Position::new(29, 9));
|
||||||
*conflicts.get_mut(cx, cy) = 1;
|
p.add_connection(Position::new(3, 5), Position::new(29, 8));
|
||||||
|
|
||||||
let xrange = cx..=cx;
|
p.add_connection(Position::new(3, 7), Position::new(29, 3));
|
||||||
let yrange = cy..=cy;
|
p.add_connection(Position::new(3, 8), Position::new(29, 5));
|
||||||
|
p.add_connection(Position::new(3, 9), Position::new(29, 4));
|
||||||
let xrange = xrange.start().saturating_sub(xoffset)
|
|
||||||
..=usize::min(xrange.end() + xoffset, self.map.width - 1);
|
p
|
||||||
let yrange = yrange.start().saturating_sub(yoffset)
|
|
||||||
..=usize::min(yrange.end() + yoffset, self.map.height - 1);
|
|
||||||
// dbg!(&xrange, &yrange);
|
|
||||||
|
|
||||||
let xsize = xrange.end() - xrange.start() + 1;
|
|
||||||
let ysize = yrange.end() - yrange.start() + 1;
|
|
||||||
|
|
||||||
// dbg!(xsize, ysize);
|
|
||||||
|
|
||||||
let mut b = BruteforceBuilder::new(xsize + 2, ysize + 2);
|
|
||||||
b.set_blocked_range(0, 0, xsize + 1, 0, true);
|
|
||||||
b.set_blocked_range(0, ysize + 1, xsize + 1, ysize + 1, true);
|
|
||||||
b.set_blocked_range(0, 0, 0, ysize + 1, true);
|
|
||||||
b.set_blocked_range(xsize + 1, 0, xsize + 1, ysize + 1, true);
|
|
||||||
|
|
||||||
for x in 0..xsize {
|
|
||||||
for y in 0..ysize {
|
|
||||||
b.set_blocked(
|
|
||||||
x + 1,
|
|
||||||
y + 1,
|
|
||||||
self.map.get(xrange.start() + x, yrange.start() + y).blocked,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for path in &self.path {
|
|
||||||
let s = path
|
|
||||||
.iter()
|
|
||||||
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
|
||||||
.map(|i| i.saturating_sub(1));
|
|
||||||
let e = path
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
|
||||||
.map(|i| usize::min(path.len() - 1, path.len() - i));
|
|
||||||
|
|
||||||
if let Some((start, end)) = s.zip(e) {
|
|
||||||
// dbg!(start, end);
|
|
||||||
|
|
||||||
let start_pos = path[start];
|
|
||||||
let start_dir = Direction::from_neghbors(&path[start], &path[start + 1]);
|
|
||||||
let end_pos = path[end];
|
|
||||||
let end_dir = Direction::from_neghbors(&path[end - 1], &path[end]);
|
|
||||||
|
|
||||||
// dbg!(start_pos, end_pos);
|
|
||||||
|
|
||||||
b.add_path(
|
|
||||||
(
|
|
||||||
Position::new(
|
|
||||||
start_pos.x - (xrange.start() - 1),
|
|
||||||
start_pos.y - (yrange.start() - 1),
|
|
||||||
),
|
|
||||||
start_dir,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Position::new(
|
|
||||||
end_pos.x - (xrange.start() - 1),
|
|
||||||
end_pos.y - (yrange.start() - 1),
|
|
||||||
),
|
|
||||||
end_dir,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut b = b.build();
|
|
||||||
|
|
||||||
println!("{}", b);
|
|
||||||
|
|
||||||
while b.next_finish_state() {
|
|
||||||
println!("{}", b);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{}", b.solution_count());
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue