use crate::graph::wheighted_graph::WheightedGraph; use crate::misc::Map; use crate::{ graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap, }; use std::ops::Index; use termcolor::{Color, ColorSpec}; use self::common::{print_map, Direction, Position, PositionType}; 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, start: Vec<(Position, Direction)>, end: Vec<(Position, Direction)>, path: Vec>, } 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, " ") } }); } } pub static COLORS: Cyclic = Cyclic([ Color::Red, Color::Green, Color::Yellow, Color::Blue, Color::Magenta, Color::Cyan, ]); pub struct Cyclic([T; N]); impl Index for Cyclic { type Output = T; fn index(&self, index: usize) -> &Self::Output { &self.0[index % N] } } struct MapInternal<'a> { map: &'a Map, 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::>(&m, self.start[i], self.end[i]); if let Some(p) = p { self.path[i] = p; } } } } pub mod problems { use super::{ common::{Direction, Position}, Problem, }; 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 } }