use std::marker::PhantomData; use crate::Connection; use crate::Map as _; use crate::SinglePathInput; use crate::SinglePathfinder; use crate::examples::HashMapMap; use factorio_core::misc::Map; use factorio_core::{prelude::*, visualize::Visualize}; use factorio_graph::priority_queue::PriorityQueueByKey; use factorio_graph::wheighted_graph::WheightedGraph; use factorio_graph::wheighted_graph::shortest_path::QueueObject; use factorio_graph::wheighted_graph::shortest_path::a_star; use serde::{Deserialize, Serialize}; use tracing::Level; use tracing::span; pub mod brute_force; pub mod conflict_avoidance; pub struct ConflictAvoidance

{ pub timeout: Option, pub priority_queue: PhantomData

, } impl

SinglePathfinder for ConflictAvoidance

where P: PriorityQueueByKey>, { fn find_paths( &self, input: SinglePathInput, ) -> Option>> { let _span = span!(Level::TRACE, "find_paths").entered(); let (pos, size) = input.map.area(); let mut p = Problem::new(size.x as usize, size.y as usize); for x in 0..size.x { for y in 0..size.y { if !input.map.get_position(Position::new(x - pos.x, y - pos.y)) { p.set_blocked(x as usize, y as usize, true); } } } for i in input.connections { p.add_connection( (i.start_pos, i.start_dir), (i.end_pos.in_direction(&i.end_dir, -1), i.end_dir), ); } // p.print_visualization(); if p.find_path::

() { let mut c = conflict_avoidance::ConflictAvoidance::new(&p); // c.print_visualization(); if c.remove_all_conflicts(self.timeout) { // c.print_visualization(); Some(c.get_paths().to_vec()) } else { None } } else { None } } } #[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)] pub struct Field { pub blocked: bool, weight: i64, } #[derive(Debug, Serialize, Deserialize)] 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; if self.map.get(x, y).blocked { weight += 10000; } self.map.get_mut(x, y).weight = weight; } } for (i, path) in self.path.iter().enumerate() { if i != without && !path.is_empty() { for p in &path[1..] { let weight = 1000; 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; // } } } impl From<(Vec, HashMapMap)> for Problem { fn from((input, map): (Vec, HashMapMap)) -> Self { let (pos, size) = map.area(); let mut p = Problem::new(size.x as usize, size.y as usize); for x in 0..size.x { for y in 0..size.y { if !map.get_position(Position::new(x - pos.x, y - pos.y)) { p.set_blocked(x as usize, y as usize, true); } } } for i in input { p.add_connection((i.start_pos, i.start_dir), (i.end_pos, i.end_dir)); } p } } impl Visualize for Problem { fn visualize(&self) -> factorio_core::visualize::Visualization { let mut v = factorio_core::visualize::Visualization::new(Position::new( self.map.width as i32, self.map.height as i32, )); for x in 0..self.map.width { for y in 0..self.map.height { if self.map.get(x, y).blocked { v.add_symbol( Position::new(x as i32, y as i32), factorio_core::visualize::Symbol::Block, Some(factorio_core::visualize::Color::white()), None, ) } } } for (i, (p, _d)) in self.start.iter().enumerate() { v.add_symbol( *p, factorio_core::visualize::Symbol::Char('S'), Some(factorio_core::visualize::Color::index(i)), None, ) } for (i, (p, _d)) in self.end.iter().enumerate() { v.add_symbol( *p, factorio_core::visualize::Symbol::Char('T'), Some(factorio_core::visualize::Color::index(i)), None, ) } for (i, p) in self.path.iter().enumerate() { for (pos, dir) in p { v.add_symbol( *pos, factorio_core::visualize::Symbol::Arrow(*dir), Some(factorio_core::visualize::Color::index(i)), None, ) } } v } } struct MapInternal<'a> { map: &'a Map, end: (Position, Direction), } impl WheightedGraph for MapInternal<'_> { type Node = (Position, Direction); fn edge( &self, node: &(Position, Direction), num: usize, ) -> Option<((Position, Direction), i64)> { 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), 3 + penalty)), 1 => Some(((next, node.1.counter_clockwise()), 4 + penalty)), 2 => Some(((next, node.1.clockwise()), 4 + 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), 35 + penalty)); } } } None } } } } impl Problem { pub fn find_path

(&mut self) -> bool where P: PriorityQueueByKey>, { let _span = span!(Level::TRACE, "find_path").entered(); 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]) a_star::( &m, self.start[i], |&n| n == self.end[i], |&(p, _)| { 3 * (PositionType::abs_diff(p.x, self.end[i].0.x) + PositionType::abs_diff(p.y, self.end[i].0.y)) as i64 }, ) }; if let Some(p) = p { self.path[i] = p; } else { return false; } } true } }