515 lines
16 KiB
Rust
515 lines
16 KiB
Rust
use crate::common::color::COLORS;
|
|
use crate::graph::wheighted_graph::WheightedGraph;
|
|
use crate::misc::Map;
|
|
use crate::{
|
|
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
|
|
};
|
|
use termcolor::ColorSpec;
|
|
|
|
use self::common::print_map;
|
|
use crate::prelude::*;
|
|
|
|
pub mod brute_force;
|
|
pub mod common;
|
|
pub mod conflict_avoidance;
|
|
|
|
#[derive(Default, Clone, Copy)]
|
|
pub struct Field {
|
|
pub blocked: bool,
|
|
weight: f64,
|
|
}
|
|
|
|
pub struct Problem {
|
|
map: Map<Field>,
|
|
start: Vec<(Position, Direction)>,
|
|
end: Vec<(Position, Direction)>,
|
|
path: Vec<Vec<(Position, Direction)>>,
|
|
}
|
|
|
|
impl Problem {
|
|
pub fn new(width: usize, height: usize) -> Self {
|
|
Self {
|
|
map: Map::new(width, height),
|
|
start: Vec::new(),
|
|
end: Vec::new(),
|
|
path: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
|
|
self.start.push(start);
|
|
self.end.push(end);
|
|
self.path.push(Vec::new());
|
|
}
|
|
|
|
pub fn set_blocked(&mut self, x: usize, y: usize, blocked: bool) {
|
|
self.map.get_mut(x, y).blocked = blocked;
|
|
}
|
|
|
|
pub fn set_blocked_range(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, blocked: bool) {
|
|
for x in x1..=x2 {
|
|
for y in y1..=y2 {
|
|
self.set_blocked(x, y, blocked);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn calculate_wheights(&mut self, without: usize) {
|
|
for x in 0..self.map.width {
|
|
for y in 0..self.map.height {
|
|
let mut weight = 0.0;
|
|
|
|
if self.map.get(x, y).blocked {
|
|
weight += 100.0;
|
|
}
|
|
|
|
self.map.get_mut(x, y).weight = weight;
|
|
}
|
|
}
|
|
|
|
for (i, path) in self.path.iter().enumerate() {
|
|
if i != without {
|
|
for p in path {
|
|
let weight = 1.0;
|
|
let x = p.0.x as usize;
|
|
let y = p.0.y as usize;
|
|
|
|
self.map.get_mut(x, y).weight += weight;
|
|
}
|
|
}
|
|
}
|
|
|
|
// for p in &self.start {
|
|
// self.map.get_mut(p.0.x as usize, p.0.y as usize).weight = f64::INFINITY;
|
|
// }
|
|
|
|
// for p in &self.end {
|
|
// self.map.get_mut(p.0.x as usize, p.0.y as usize).weight = f64::INFINITY;
|
|
// }
|
|
}
|
|
|
|
pub fn print(&self) {
|
|
let _ = 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.0 == 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.0 == 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.0 == Position::new(x as PositionType, y as PositionType))
|
|
.map(|j| (i, j))
|
|
}) {
|
|
color.set_fg(Some(COLORS[i]));
|
|
let c = &self.path[i][p];
|
|
match c.1 {
|
|
Direction::Up => (color, "↑"),
|
|
Direction::Right => (color, "→"),
|
|
Direction::Down => (color, "↓"),
|
|
Direction::Left => (color, "←"),
|
|
}
|
|
} else if self.map.get(x as usize, y as usize).blocked {
|
|
(color, "#")
|
|
} else if x % 8 == 0 || y % 8 == 0 {
|
|
(color, "∙")
|
|
} else {
|
|
(color, " ")
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
struct MapInternal<'a> {
|
|
map: &'a Map<Field>,
|
|
end: (Position, Direction),
|
|
}
|
|
|
|
impl<'a> WheightedGraph for MapInternal<'a> {
|
|
type Node = (Position, Direction);
|
|
|
|
fn edge(&self, node: &Self::Node, num: usize) -> Option<(Self::Node, f64)> {
|
|
let next = node.0.in_direction(&node.1, 1);
|
|
next.in_range(
|
|
&Position::new(0, 0),
|
|
&Position::new(
|
|
self.map.width as PositionType,
|
|
self.map.height as PositionType,
|
|
),
|
|
)?;
|
|
if self.map.get(next.x as usize, next.y as usize).blocked && self.end != (next, node.1) {
|
|
return None;
|
|
}
|
|
|
|
let penalty = self.map.get(next.x as usize, next.y as usize).weight;
|
|
match num {
|
|
0 => Some(((next, node.1), 1.5 + penalty)),
|
|
1 => Some(((next, node.1.counter_clockwise()), 1.5 + penalty)),
|
|
2 => Some(((next, node.1.clockwise()), 1.5 + penalty)),
|
|
_ => {
|
|
let mut count = 2;
|
|
for l in 2..=6 {
|
|
let n = node.0.in_direction(&node.1, l);
|
|
n.in_range(
|
|
&Position::new(0, 0),
|
|
&Position::new(
|
|
self.map.width as PositionType,
|
|
self.map.height as PositionType,
|
|
),
|
|
)?;
|
|
if !self.map.get(n.x as usize, n.y as usize).blocked {
|
|
count += 1;
|
|
if count == num {
|
|
let penalty = penalty + self.map.get(n.x as usize, n.y as usize).weight;
|
|
return Some(((n, node.1), 17.5 + penalty));
|
|
}
|
|
}
|
|
}
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Problem {
|
|
pub fn find_path(&mut self) {
|
|
for i in 0..self.start.len() {
|
|
self.calculate_wheights(i);
|
|
let m = MapInternal {
|
|
map: &self.map,
|
|
end: self.end[i],
|
|
};
|
|
let p = dijkstra::<MapInternal, FibonacciHeap<_>>(&m, self.start[i], self.end[i]);
|
|
if let Some(p) = p {
|
|
self.path[i] = p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod problems {
|
|
use super::Problem;
|
|
use crate::prelude::*;
|
|
|
|
pub fn simple() -> Problem {
|
|
let mut p = Problem::new(5, 3);
|
|
|
|
p.set_blocked_range(2, 0, 2, 2, true);
|
|
|
|
p.add_connection(
|
|
(Position::new(0, 1), Direction::Right),
|
|
(Position::new(4, 1), Direction::Right),
|
|
);
|
|
|
|
p
|
|
}
|
|
|
|
pub fn belt_madness_level_1() -> Problem {
|
|
let mut p = Problem::new(17, 13);
|
|
|
|
p.set_blocked(0, 3, true);
|
|
|
|
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(2, 7), Direction::Right),
|
|
(Position::new(13, 4), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 8), Direction::Right),
|
|
(Position::new(13, 5), Direction::Right),
|
|
);
|
|
|
|
p.add_connection(
|
|
(Position::new(2, 4), Direction::Right),
|
|
(Position::new(13, 8), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 5), Direction::Right),
|
|
(Position::new(13, 7), Direction::Right),
|
|
);
|
|
|
|
p
|
|
}
|
|
|
|
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(2, 4), Direction::Right),
|
|
(Position::new(13, 2), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 7), Direction::Right),
|
|
(Position::new(13, 3), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 10), Direction::Right),
|
|
(Position::new(13, 4), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 9), Direction::Right),
|
|
(Position::new(13, 5), Direction::Right),
|
|
);
|
|
|
|
p.add_connection(
|
|
(Position::new(2, 2), Direction::Right),
|
|
(Position::new(13, 7), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 3), Direction::Right),
|
|
(Position::new(13, 8), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 5), Direction::Right),
|
|
(Position::new(13, 9), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 8), Direction::Right),
|
|
(Position::new(13, 10), Direction::Right),
|
|
);
|
|
|
|
p
|
|
}
|
|
|
|
pub fn belt_madness_level_3() -> Problem {
|
|
let mut p = Problem::new(33, 13);
|
|
|
|
p.set_blocked_range(1, 3, 2, 5, true);
|
|
p.set_blocked_range(1, 7, 2, 9, true);
|
|
|
|
p.set_blocked(0, 3, true);
|
|
p.set_blocked(0, 8, true);
|
|
|
|
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);
|
|
p.set_blocked_range(30, 7, 31, 9, true);
|
|
p.set_blocked(32, 3, true);
|
|
p.set_blocked(32, 9, true);
|
|
|
|
p.add_connection(
|
|
(Position::new(2, 3), Direction::Right),
|
|
(Position::new(29, 7), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 4), Direction::Right),
|
|
(Position::new(29, 9), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 5), Direction::Right),
|
|
(Position::new(29, 8), Direction::Right),
|
|
);
|
|
|
|
p.add_connection(
|
|
(Position::new(2, 7), Direction::Right),
|
|
(Position::new(29, 3), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 8), Direction::Right),
|
|
(Position::new(29, 5), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 9), Direction::Right),
|
|
(Position::new(29, 4), Direction::Right),
|
|
);
|
|
|
|
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, 2), Direction::Down),
|
|
(Position::new(26, 25), Direction::Down),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(12, 2), Direction::Down),
|
|
(Position::new(18, 25), Direction::Down),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(14, 2), Direction::Down),
|
|
(Position::new(3, 26), Direction::Left),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(16, 2), Direction::Down),
|
|
(Position::new(14, 25), Direction::Down),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 4), Direction::Right),
|
|
(Position::new(27, 24), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 11), Direction::Right),
|
|
(Position::new(27, 17), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 13), Direction::Right),
|
|
(Position::new(27, 26), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 15), Direction::Right),
|
|
(Position::new(27, 13), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(28, 15), Direction::Left),
|
|
(Position::new(2, 3), Direction::Up),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 17), Direction::Right),
|
|
(Position::new(18, 3), Direction::Up),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(2, 24), Direction::Right),
|
|
(Position::new(26, 3), Direction::Up),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(4, 26), Direction::Up),
|
|
(Position::new(27, 4), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(12, 26), Direction::Up),
|
|
(Position::new(27, 11), Direction::Right),
|
|
);
|
|
p.add_connection(
|
|
(Position::new(16, 26), Direction::Up),
|
|
(Position::new(28, 3), Direction::Up),
|
|
);
|
|
|
|
p
|
|
}
|
|
}
|