Rewrote path selection for conflict avoidance.
This commit is contained in:
parent
8f6809c17f
commit
7fdf32342a
8 changed files with 514 additions and 439 deletions
|
|
@ -1,15 +1,15 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use colored::Colorize;
|
||||
use termcolor::ColorSpec;
|
||||
|
||||
use crate::misc::Map;
|
||||
|
||||
use super::{
|
||||
common::{Dimension, Direction, PathField, PositionType},
|
||||
common::{print_map, Dimension, Direction, PathField, PositionType},
|
||||
Position, COLORS,
|
||||
};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct BruteforceField {
|
||||
pub blocked: bool,
|
||||
underground_vertical: bool,
|
||||
|
|
@ -18,7 +18,7 @@ pub struct BruteforceField {
|
|||
|
||||
static MAX_UNDERGROUND_LENGTH: u8 = 6;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BruteforceBuilder {
|
||||
map: Map<BruteforceField>,
|
||||
path: Vec<[(Position, Direction); 2]>,
|
||||
|
|
@ -49,6 +49,7 @@ impl BruteforceBuilder {
|
|||
}
|
||||
|
||||
pub fn build(self) -> Bruteforce {
|
||||
// dbg!(&self);
|
||||
let dimension = Dimension {
|
||||
width: self.map.width,
|
||||
height: self.map.height,
|
||||
|
|
@ -583,26 +584,6 @@ impl Display for Bruteforce {
|
|||
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.problems.iter().enumerate() {
|
||||
|
|
@ -662,27 +643,23 @@ impl Display for Bruteforce {
|
|||
|
||||
// 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 self.map.get(x, y).underground_horizontal {
|
||||
write!(f, "_")?;
|
||||
} else if self.map.get(x, y).underground_vertical {
|
||||
write!(f, "|")?;
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
write!(f, "∙")?;
|
||||
} else {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
||||
if let Some((i, c)) = m.get(x as usize, y as usize) {
|
||||
let mut color = ColorSpec::new();
|
||||
color.set_fg(Some(COLORS[*i]));
|
||||
(color, *c)
|
||||
} else if self.map.get(x as usize, y as usize).blocked {
|
||||
(ColorSpec::new(), "#")
|
||||
} else if self.map.get(x as usize, y as usize).underground_horizontal {
|
||||
(ColorSpec::new(), "_")
|
||||
} else if self.map.get(x as usize, y as usize).underground_vertical {
|
||||
(ColorSpec::new(), "|")
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
(ColorSpec::new(), "∙")
|
||||
} else {
|
||||
(ColorSpec::new(), " ")
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
use std::io::Write;
|
||||
|
||||
use base64::write;
|
||||
use termcolor::{ColorSpec, StandardStream, WriteColor};
|
||||
|
||||
pub type PositionType = i32;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
|
|
@ -108,6 +113,16 @@ impl Position {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::Sub for Position {
|
||||
type Output = Position;
|
||||
|
||||
fn sub(mut self, rhs: Self) -> Self::Output {
|
||||
self.x -= rhs.x;
|
||||
self.y -= rhs.y;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub enum PathField {
|
||||
Belt {
|
||||
|
|
@ -167,3 +182,73 @@ impl PathField {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_map<F>(width: i32, height: i32, f: F)
|
||||
where
|
||||
F: Fn(i32, i32) -> (ColorSpec, &'static str),
|
||||
{
|
||||
let stdout = &mut StandardStream::stdout(termcolor::ColorChoice::Always);
|
||||
|
||||
let width_digits = width.ilog10() + 1;
|
||||
let height_digits = height.ilog10() + 1;
|
||||
|
||||
// print header
|
||||
for i in 0..width_digits {
|
||||
let d = width_digits - i - 1;
|
||||
|
||||
//padding
|
||||
for _ in 0..height_digits {
|
||||
write!(stdout, " ");
|
||||
}
|
||||
|
||||
for x in 0..width {
|
||||
let digits = x / (i32::pow(10, d));
|
||||
if digits == 0 && d > 0 {
|
||||
write!(stdout, " ");
|
||||
} else {
|
||||
write!(
|
||||
stdout,
|
||||
"{}",
|
||||
char::from_u32((digits % 10) as u32 + 48).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
writeln!(stdout);
|
||||
}
|
||||
|
||||
for y in 0..height {
|
||||
write!(stdout, "{:1$}", y, height_digits as usize);
|
||||
|
||||
for x in 0..width {
|
||||
let (c, s) = f(x, y);
|
||||
stdout.set_color(&c);
|
||||
write!(stdout, "{:1}", s);
|
||||
stdout.reset();
|
||||
}
|
||||
|
||||
writeln!(stdout, "{:1$}", y, height_digits as usize);
|
||||
}
|
||||
|
||||
for i in 0..width_digits {
|
||||
let d = width_digits - i - 1;
|
||||
|
||||
//padding
|
||||
for _ in 0..height_digits {
|
||||
write!(stdout, " ");
|
||||
}
|
||||
|
||||
for x in 0..width {
|
||||
let digits = x / (i32::pow(10, d));
|
||||
if digits == 0 && d > 0 {
|
||||
write!(stdout, " ");
|
||||
} else {
|
||||
write!(
|
||||
stdout,
|
||||
"{}",
|
||||
char::from_u32((digits % 10) as u32 + 48).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
writeln!(stdout);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
use std::{fmt::Display, ops::RangeInclusive};
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{RangeBounds, RangeInclusive},
|
||||
};
|
||||
|
||||
use clap::builder::PathBufValueParser;
|
||||
use colored::Colorize;
|
||||
use termcolor::ColorSpec;
|
||||
|
||||
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
||||
|
||||
use super::{
|
||||
common::{Dimension, Direction, PathField, Position, PositionType},
|
||||
common::{print_map, Dimension, Direction, PathField, Position, PositionType},
|
||||
Problem, COLORS,
|
||||
};
|
||||
|
||||
|
|
@ -18,6 +21,7 @@ struct Field {
|
|||
pub struct ConflictAvoidance {
|
||||
map: Map<Field>,
|
||||
belts: Vec<Vec<PathField>>,
|
||||
range: Option<(RangeInclusive<i32>, RangeInclusive<i32>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
|
|
@ -89,7 +93,11 @@ impl ConflictAvoidance {
|
|||
belts.push(p);
|
||||
}
|
||||
|
||||
Self { map, belts }
|
||||
Self {
|
||||
map,
|
||||
belts,
|
||||
range: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_conflict(&mut self) -> bool {
|
||||
|
|
@ -153,10 +161,12 @@ impl ConflictAvoidance {
|
|||
loop {
|
||||
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;
|
||||
let xrange = c.min.x as usize..=c.max.x as usize;
|
||||
let yrange = c.min.y as usize..=c.max.y as usize;
|
||||
|
||||
println!("x: {:?}, y: {:?}", xrange, yrange);
|
||||
self.range = Some((c.min.x..=c.max.x, c.min.y..=c.max.y));
|
||||
|
||||
// println!("x: {:?}, y: {:?}", xrange, yrange);
|
||||
|
||||
let xsize = xrange.end() - xrange.start() + 1;
|
||||
let ysize = yrange.end() - yrange.start() + 1;
|
||||
|
|
@ -180,63 +190,66 @@ impl ConflictAvoidance {
|
|||
}
|
||||
|
||||
let mut mapping = Vec::new();
|
||||
let offset = Position::new(*xrange.start() as i32 - 1, *yrange.start() as i32 - 1);
|
||||
|
||||
dbg!(&xrange, &yrange);
|
||||
|
||||
for (i, path) in self.belts.iter().enumerate() {
|
||||
let s = path
|
||||
// index of first PathField where the next position is in the area
|
||||
let start_index = path
|
||||
.iter()
|
||||
.map(|p| p.pos())
|
||||
.position(|p| {
|
||||
xrange.contains(&(p.x as usize)) && yrange.contains(&(p.y as usize))
|
||||
.map(|p| {
|
||||
let (pos, dir) = p.end_pos();
|
||||
pos.in_direction(&dir, 1)
|
||||
})
|
||||
.map(|i| i.saturating_sub(1));
|
||||
let e = path
|
||||
.iter()
|
||||
.map(|p| p.pos())
|
||||
.rev()
|
||||
.position(|p| {
|
||||
xrange.contains(&(p.x as usize)) && yrange.contains(&(p.y as usize))
|
||||
})
|
||||
.map(|i| usize::min(path.len() - 1, path.len() - i));
|
||||
.position(|pos| {
|
||||
xrange.contains(&(pos.x as usize)) && yrange.contains(&(pos.y as usize))
|
||||
});
|
||||
|
||||
if let Some((start, mut end)) = s.zip(e) {
|
||||
// dbg!(start, end);
|
||||
if matches!(path[end - 1], PathField::Underground { .. }) {
|
||||
end -= 1;
|
||||
// index of last PathField that ends inside the area
|
||||
let end_index = path
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|p| p.end_pos().0)
|
||||
.position(|pos| {
|
||||
xrange.contains(&(pos.x as usize)) && yrange.contains(&(pos.y as usize))
|
||||
})
|
||||
.map(|rev_i| path.len() - rev_i - 1);
|
||||
|
||||
if let Some((start_index, end_index)) = Option::zip(start_index, end_index) {
|
||||
// dbg!(start_index, end_index, path[start_index], path[end_index]);
|
||||
|
||||
let (start_pos, start_dir) = path[start_index].end_pos();
|
||||
|
||||
let (end_pos, end_dir) = path[end_index].end_pos();
|
||||
|
||||
// edge cases with underground into and end
|
||||
|
||||
if let Some(PathField::Underground {
|
||||
pos,
|
||||
dir: _,
|
||||
len: _,
|
||||
}) = path.get(end_index + 1)
|
||||
{
|
||||
if xrange.contains(&(pos.x as usize)) && yrange.contains(&(pos.y as usize))
|
||||
{
|
||||
let p = *pos - offset;
|
||||
println!("Blocked {:?}", p);
|
||||
b.set_blocked(p.x as usize, p.y as usize, true);
|
||||
}
|
||||
}
|
||||
|
||||
mapping.push((i, start, end));
|
||||
b.add_path((start_pos - offset, start_dir), (end_pos - offset, end_dir));
|
||||
|
||||
let (start_pos, start_dir) = path[start].end_pos();
|
||||
let end_pos = path[end].pos();
|
||||
let end_dir = path[end].dir();
|
||||
|
||||
// dbg!(start_pos, end_pos);
|
||||
// dbg!(i, path[start], path[end]);
|
||||
|
||||
b.add_path(
|
||||
(
|
||||
Position::new(
|
||||
start_pos.x - (*xrange.start() as i32 - 1),
|
||||
start_pos.y - (*yrange.start() as i32 - 1),
|
||||
),
|
||||
start_dir,
|
||||
),
|
||||
(
|
||||
Position::new(
|
||||
end_pos.x - (*xrange.start() as i32 - 1),
|
||||
end_pos.y - (*yrange.start() as i32 - 1),
|
||||
),
|
||||
*end_dir,
|
||||
),
|
||||
);
|
||||
mapping.push((i, start_index, end_index));
|
||||
}
|
||||
}
|
||||
|
||||
println!("{:?}", mapping);
|
||||
// println!("{:?}", mapping);
|
||||
|
||||
let mut b = b.build();
|
||||
|
||||
println!("{}", b);
|
||||
println!("{}", self);
|
||||
|
||||
let mut min_cost = f64::INFINITY;
|
||||
let mut solutions = Vec::new();
|
||||
|
|
@ -250,26 +263,38 @@ impl ConflictAvoidance {
|
|||
}
|
||||
}
|
||||
|
||||
println!("{}", b.solution_count());
|
||||
// dbg!(&solutions);
|
||||
|
||||
// println!("{}", b.solution_count());
|
||||
|
||||
if b.solution_count() > 0 {
|
||||
for (p, (index, start, end)) in solutions.iter().zip(mapping) {
|
||||
let mut t = Vec::new();
|
||||
// println!("{:?}", p);
|
||||
|
||||
t.extend_from_slice(&self.belts[index][0..=start]);
|
||||
t.extend(p[1..].iter().map(|p| {
|
||||
p.offset(&Position::new(
|
||||
(*xrange.start() as i32) - 1,
|
||||
(*yrange.start() as i32) - 1,
|
||||
))
|
||||
}));
|
||||
t.extend_from_slice(&self.belts[index][end..]);
|
||||
t.extend(p[1..].iter().map(|p| p.offset(&offset)));
|
||||
let (end_pos, end_dir) = self.belts[index][end].end_pos();
|
||||
t.push(PathField::Belt {
|
||||
pos: end_pos,
|
||||
dir: end_dir,
|
||||
});
|
||||
if end + 1 < self.belts[index].len() {
|
||||
t.extend_from_slice(&self.belts[index][end + 1..]);
|
||||
}
|
||||
// println!("{:?}", &t);
|
||||
// println!();
|
||||
// println!("{:?}", &self.belts[index]);
|
||||
|
||||
self.belts[index] = t;
|
||||
}
|
||||
|
||||
for (i, path) in self.belts.iter().enumerate() {
|
||||
if path.iter().any(|p| (p.pos().x == 18) && p.pos().y == 18) {
|
||||
dbg!(i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
let mut candidate = Candidate::new(
|
||||
|
|
@ -333,29 +358,6 @@ impl ConflictAvoidance {
|
|||
|
||||
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() {
|
||||
|
|
@ -402,25 +404,57 @@ impl Display for ConflictAvoidance {
|
|||
m.set(last_pos.x as usize, last_pos.y as usize, Some((i, "T")));
|
||||
}
|
||||
|
||||
// create conflict map
|
||||
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 as usize, pos.y as usize) += 1
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1;
|
||||
let end = pos.in_direction(dir, *len as PositionType);
|
||||
*conflicts.get_mut(end.x as usize, end.y as usize) += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Print body
|
||||
|
||||
for y in 0..self.map.height {
|
||||
write!(f, "{:1$}", y, height_digits as usize)?;
|
||||
print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
||||
let mut color = ColorSpec::new();
|
||||
|
||||
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, " ")?;
|
||||
if let Some((xrange, yrange)) = &self.range {
|
||||
if xrange.contains(&x) && yrange.contains(&y) {
|
||||
color.set_bg(Some(termcolor::Color::Rgb(96, 96, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
}
|
||||
if conflicts.get(x as usize, y as usize) > &1 {
|
||||
color.set_bg(Some(termcolor::Color::Black));
|
||||
}
|
||||
|
||||
if let Some((i, c)) = m.get(x as usize, y as usize) {
|
||||
color.set_fg(Some(COLORS[*i]));
|
||||
(color, c)
|
||||
} else if self.map.get(x as usize, y as usize).blocked {
|
||||
(color, "#")
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
(color, "∙")
|
||||
} else {
|
||||
(color, " ")
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
use termcolor::{Color, ColorSpec};
|
||||
|
||||
use crate::belt_finding::{brute_force::BruteforceBuilder, common::Direction};
|
||||
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
||||
use crate::graph::wheighted_graph::WheightedGraph;
|
||||
use crate::misc::Map;
|
||||
use crate::priority_queue::BinaryHeap;
|
||||
use colored::{Color, Colorize};
|
||||
use std::fmt::Display;
|
||||
use std::ops::{Deref, Index};
|
||||
|
||||
use self::common::{Position, PositionType};
|
||||
use self::common::{print_map, Position, PositionType};
|
||||
|
||||
pub mod brute_force;
|
||||
pub mod common;
|
||||
|
|
@ -69,7 +71,11 @@ impl Problem {
|
|||
for (i, path) in self.path.iter().enumerate() {
|
||||
if i != without {
|
||||
for p in path {
|
||||
self.map.get_mut(p.x as usize, p.y as usize).wheight += 50.0;
|
||||
let weight = 50.0;
|
||||
let x = p.x as usize;
|
||||
let y = p.y as usize;
|
||||
|
||||
self.map.get_mut(x, y).wheight += weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -84,89 +90,68 @@ impl Problem {
|
|||
}
|
||||
}
|
||||
|
||||
static COLORS: [Color; 12] = [
|
||||
static COLORS: Cyclic<Color, 6> = Cyclic([
|
||||
Color::Red,
|
||||
Color::Green,
|
||||
Color::Yellow,
|
||||
Color::Blue,
|
||||
Color::Magenta,
|
||||
Color::Cyan,
|
||||
Color::BrightRed,
|
||||
Color::BrightGreen,
|
||||
Color::BrightYellow,
|
||||
Color::BrightBlue,
|
||||
Color::BrightMagenta,
|
||||
Color::Cyan,
|
||||
];
|
||||
]);
|
||||
|
||||
struct Cyclic<T, const N: usize>([T; N]);
|
||||
|
||||
impl<T, const N: usize> Index<usize> for Cyclic<T, N> {
|
||||
type Output = T;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.0[index % N]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Problem {
|
||||
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)?;
|
||||
}
|
||||
|
||||
// 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) = self
|
||||
.start
|
||||
.iter()
|
||||
print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
||||
let mut color = ColorSpec::new();
|
||||
if let Some(i) = self
|
||||
.start
|
||||
.iter()
|
||||
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||
{
|
||||
color.set_fg(Some(COLORS[i]));
|
||||
(color, "s")
|
||||
} else if let Some(i) = self
|
||||
.end
|
||||
.iter()
|
||||
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||
{
|
||||
color.set_fg(Some(COLORS[i]));
|
||||
(color, "t")
|
||||
} else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| {
|
||||
v.iter()
|
||||
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||
{
|
||||
write!(f, "{}", "s".color(COLORS[i]))?;
|
||||
} else if let Some(i) = self
|
||||
.end
|
||||
.iter()
|
||||
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||
{
|
||||
write!(f, "{}", "t".color(COLORS[i]))?;
|
||||
} else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| {
|
||||
v.iter()
|
||||
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||
.map(|j| (i, j))
|
||||
}) {
|
||||
if self.path[i][p].x < self.path[i][p + 1].x {
|
||||
write!(f, "{}", "→".color(COLORS[i]))?;
|
||||
} else if self.path[i][p].x > self.path[i][p + 1].x {
|
||||
write!(f, "{}", "←".color(COLORS[i]))?;
|
||||
} else if self.path[i][p].y < self.path[i][p + 1].y {
|
||||
write!(f, "{}", "↓".color(COLORS[i]))?;
|
||||
} else if self.path[i][p].y > self.path[i][p + 1].y {
|
||||
write!(f, "{}", "↑".color(COLORS[i]))?;
|
||||
}
|
||||
} else if self.map.get(x, y).blocked {
|
||||
write!(f, "#")?;
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
write!(f, "∙")?;
|
||||
.map(|j| (i, j))
|
||||
}) {
|
||||
color.set_fg(Some(COLORS[i]));
|
||||
if self.path[i][p].x < self.path[i][p + 1].x {
|
||||
(color, "→")
|
||||
} else if self.path[i][p].x > self.path[i][p + 1].x {
|
||||
(color, "←")
|
||||
} else if self.path[i][p].y < self.path[i][p + 1].y {
|
||||
(color, "↓")
|
||||
} else if self.path[i][p].y > self.path[i][p + 1].y {
|
||||
(color, "↑")
|
||||
} else {
|
||||
write!(f, " ")?;
|
||||
unreachable!()
|
||||
}
|
||||
} else if self.map.get(x as usize, y as usize).blocked {
|
||||
(color, "#")
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
(color, "∙")
|
||||
} else {
|
||||
(color, " ")
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -339,4 +324,110 @@ pub mod problems {
|
|||
|
||||
p
|
||||
}
|
||||
|
||||
pub fn belt_madness_level_5() -> Problem {
|
||||
let mut p = Problem::new(31, 29);
|
||||
|
||||
// power stations
|
||||
p.set_blocked_range(8, 8, 9, 9, true);
|
||||
p.set_blocked_range(21, 8, 22, 9, true);
|
||||
p.set_blocked_range(8, 19, 9, 20, true);
|
||||
p.set_blocked_range(21, 19, 22, 20, true);
|
||||
|
||||
// solar panels
|
||||
p.set_blocked_range(12, 11, 14, 13, true);
|
||||
p.set_blocked_range(16, 11, 18, 13, true);
|
||||
p.set_blocked_range(12, 15, 14, 17, true);
|
||||
p.set_blocked_range(16, 15, 18, 17, true);
|
||||
|
||||
// Top
|
||||
p.set_blocked_range(7, 0, 8, 2, true);
|
||||
p.set_blocked(8, 3, true);
|
||||
p.set_blocked(9, 4, true);
|
||||
p.set_blocked_range(10, 5, 20, 5, true);
|
||||
p.set_blocked(21, 4, true);
|
||||
p.set_blocked(22, 3, true);
|
||||
p.set_blocked_range(22, 0, 23, 2, true);
|
||||
|
||||
p.set_blocked_range(2, 1, 2, 2, true);
|
||||
p.set_blocked_range(4, 1, 4, 2, true);
|
||||
p.set_blocked_range(1, 4, 2, 4, true);
|
||||
|
||||
p.set_blocked_range(12, 1, 12, 2, true);
|
||||
p.set_blocked_range(14, 1, 14, 2, true);
|
||||
p.set_blocked_range(16, 1, 16, 2, true);
|
||||
p.set_blocked_range(18, 1, 18, 2, true);
|
||||
|
||||
p.set_blocked_range(28, 4, 29, 4, true);
|
||||
p.set_blocked_range(26, 1, 26, 2, true);
|
||||
p.set_blocked_range(28, 1, 28, 2, true);
|
||||
|
||||
// Bottom
|
||||
p.set_blocked_range(7, 26, 8, 28, true);
|
||||
p.set_blocked(8, 25, true);
|
||||
p.set_blocked(9, 24, true);
|
||||
p.set_blocked_range(10, 23, 20, 23, true);
|
||||
p.set_blocked(21, 24, true);
|
||||
p.set_blocked(22, 25, true);
|
||||
p.set_blocked_range(22, 26, 23, 28, true);
|
||||
|
||||
p.set_blocked_range(1, 26, 2, 26, true);
|
||||
p.set_blocked_range(4, 26, 4, 27, true);
|
||||
p.set_blocked_range(1, 24, 2, 24, true);
|
||||
|
||||
p.set_blocked_range(12, 26, 12, 27, true);
|
||||
p.set_blocked_range(14, 26, 14, 27, true);
|
||||
p.set_blocked_range(16, 26, 16, 27, true);
|
||||
p.set_blocked_range(18, 26, 18, 27, true);
|
||||
|
||||
p.set_blocked_range(28, 24, 29, 24, true);
|
||||
p.set_blocked_range(26, 26, 26, 27, true);
|
||||
p.set_blocked_range(28, 26, 29, 26, true);
|
||||
|
||||
// Left
|
||||
p.set_blocked_range(0, 7, 2, 8, true);
|
||||
p.set_blocked(3, 8, true);
|
||||
p.set_blocked(4, 9, true);
|
||||
p.set_blocked_range(5, 10, 5, 18, true);
|
||||
p.set_blocked(4, 19, true);
|
||||
p.set_blocked(3, 20, true);
|
||||
p.set_blocked_range(0, 20, 2, 21, true);
|
||||
|
||||
p.set_blocked_range(1, 11, 2, 11, true);
|
||||
p.set_blocked_range(1, 13, 2, 13, true);
|
||||
p.set_blocked_range(1, 15, 2, 15, true);
|
||||
p.set_blocked_range(1, 17, 2, 17, true);
|
||||
|
||||
// Right
|
||||
p.set_blocked_range(28, 7, 30, 8, true);
|
||||
p.set_blocked(27, 8, true);
|
||||
p.set_blocked(26, 9, true);
|
||||
p.set_blocked_range(25, 10, 25, 18, true);
|
||||
p.set_blocked(26, 19, true);
|
||||
p.set_blocked(27, 20, true);
|
||||
p.set_blocked_range(28, 20, 30, 21, true);
|
||||
|
||||
p.set_blocked_range(28, 11, 29, 11, true);
|
||||
p.set_blocked_range(28, 13, 29, 13, true);
|
||||
p.set_blocked_range(28, 15, 29, 15, true);
|
||||
p.set_blocked_range(28, 17, 29, 17, true);
|
||||
|
||||
// Path
|
||||
p.add_connection(Position::new(4, 3), Position::new(26, 25));
|
||||
p.add_connection(Position::new(12, 3), Position::new(18, 25));
|
||||
p.add_connection(Position::new(14, 3), Position::new(3, 26));
|
||||
p.add_connection(Position::new(16, 3), Position::new(14, 25));
|
||||
p.add_connection(Position::new(3, 4), Position::new(27, 24));
|
||||
p.add_connection(Position::new(3, 11), Position::new(27, 17));
|
||||
p.add_connection(Position::new(3, 13), Position::new(27, 26));
|
||||
p.add_connection(Position::new(3, 15), Position::new(27, 13));
|
||||
p.add_connection(Position::new(27, 15), Position::new(2, 3));
|
||||
p.add_connection(Position::new(3, 17), Position::new(18, 3));
|
||||
p.add_connection(Position::new(3, 24), Position::new(26, 3));
|
||||
p.add_connection(Position::new(4, 25), Position::new(27, 4));
|
||||
p.add_connection(Position::new(12, 25), Position::new(27, 11));
|
||||
p.add_connection(Position::new(16, 25), Position::new(28, 3));
|
||||
|
||||
p
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Map<T> {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue