From c10843ad2f38877ad883c57a0c128ed8642f5c6e Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 10 Dec 2023 14:09:30 +0100 Subject: [PATCH] Multi Path --- examples/solve_belt.rs | 24 +++++++- examples/solve_belt2.rs | 32 +++++++++++ src/belt_finding/mod.rs | 120 +++++++++++++++++++++++++++++----------- 3 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 examples/solve_belt2.rs diff --git a/examples/solve_belt.rs b/examples/solve_belt.rs index a6ea4ca..5606c67 100644 --- a/examples/solve_belt.rs +++ b/examples/solve_belt.rs @@ -1,7 +1,7 @@ use factorio_blueprint::belt_finding::{Position, Problem}; fn main() { - let mut p = Problem::new(17, 13, Position::new(3, 8), Position::new(13, 5)); + let mut p = Problem::new(17, 13); p.set_blocked(0, 3, true); @@ -31,9 +31,27 @@ fn main() { 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); + println!("{}", p); - p.find_path(); - println!("{}", p); } diff --git a/examples/solve_belt2.rs b/examples/solve_belt2.rs new file mode 100644 index 0000000..3f2beca --- /dev/null +++ b/examples/solve_belt2.rs @@ -0,0 +1,32 @@ +use factorio_blueprint::belt_finding::{Position, Problem}; + +fn main() { + 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(3, 3), Position::new(29, 7)); + p.add_connection(Position::new(3, 4), Position::new(29, 9)); + p.add_connection(Position::new(3, 5), Position::new(29, 8)); + + p.add_connection(Position::new(3, 7), Position::new(29, 3)); + p.add_connection(Position::new(3, 8), Position::new(29, 5)); + p.add_connection(Position::new(3, 9), Position::new(29, 4)); + + println!("{p}"); + p.find_path(); + println!("{p}"); +} diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index 1980f29..7810e76 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -2,7 +2,7 @@ use crate::graph::wheighted_graph::shortest_path::dijkstra; use crate::graph::wheighted_graph::WheightedGraph; use crate::priority_queue::BinaryHeap; use crate::{misc::Map, priority_queue::PriorityQueue}; -use colored::Colorize; +use colored::{Color, Colorize}; use std::fmt::{write, Display}; use std::io::Write; @@ -28,30 +28,84 @@ impl Position { #[derive(Default, Clone, Copy)] pub struct Field { pub blocked: bool, + wheight: f64, } pub struct Problem { map: Map, - start: Position, - end: Position, - path: Vec, + start: Vec, + end: Vec, + path: Vec>, } impl Problem { - pub fn new(width: usize, height: usize, start: Position, end: Position) -> Self { + pub fn new(width: usize, height: usize) -> Self { Self { map: Map::new(width, height), - start, - end, + start: Vec::new(), + end: Vec::new(), path: Vec::new(), } } + pub fn add_connection(&mut self, start: Position, end: Position) { + 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 wheight = 1.0; + + if self.map.get(x, y).blocked { + wheight += 100.0; + } + + self.map.get_mut(x, y).wheight = wheight; + } + } + + for (i, path) in self.path.iter().enumerate() { + if i != without { + for p in path { + self.map.get_mut(p.x, p.y).wheight += 50.0; + } + } + } + + for p in &self.start { + self.map.get_mut(p.x, p.y).wheight += 200.0; + } + + for p in &self.end { + self.map.get_mut(p.x, p.y).wheight += 200.0; + } + } } +static COLORS: [Color; 6] = [ + Color::Red, + Color::Green, + Color::Yellow, + Color::Blue, + Color::Magenta, + Color::Cyan, +]; + impl Display for Problem { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let width_digits = self.map.width.ilog10() + 1; @@ -83,22 +137,28 @@ impl Display for Problem { write!(f, "{:1$}", y, height_digits as usize)?; for x in 0..self.map.width { - if self.start == Position::new(x, y) { - write!(f, "{}", "s".blue())?; - } else if self.end == Position::new(x, y) { - write!(f, "{}", "t".blue())?; - } else if let Some(p) = self.path.iter().position(|p| p == &Position::new(x, y)) { - if self.path[p].x < self.path[p + 1].x { - write!(f, "{}", "→".blue())?; - } else if self.path[p].x > self.path[p + 1].x { - write!(f, "{}", "←".blue())?; - } else if self.path[p].y < self.path[p + 1].y { - write!(f, "{}", "↓".blue())?; - } else if self.path[p].y > self.path[p + 1].y { - write!(f, "{}", "↑".blue())?; + if let Some(i) = self.start.iter().position(|p| p == &Position::new(x, y)) { + write!(f, "{}", "s".color(COLORS[i]))?; + } else if let Some(i) = self.end.iter().position(|p| p == &Position::new(x, y)) { + 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, y)) + .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, "∙")?; } else { write!(f, " ")?; } @@ -143,10 +203,7 @@ impl<'a> WheightedGraph for MapInternal<'a> { } else { let t = self.get_direction(*node); - let v = t - .iter() - .flatten() - .filter_map(|&p| (!self.map.get(p.x, p.y).blocked).then_some(p)); + let v = t.iter().flatten(); v.count() } @@ -157,20 +214,21 @@ impl<'a> WheightedGraph for MapInternal<'a> { t.iter() .flatten() - .filter_map(|&p| (!self.map.get(p.x, p.y).blocked).then_some(p)) .nth(num) - .map(|p| (p, 1.0)) + .map(|&p| (p, self.map.get(p.x, p.y).wheight)) } } impl Problem { pub fn find_path(&mut self) { - let m = MapInternal { map: &self.map }; + for i in 0..self.start.len() { + self.calculate_wheights(i); + let m = MapInternal { map: &self.map }; + let p = dijkstra::>(&m, self.start[i], self.end[i]); - let p = dijkstra::>(&m, self.start, self.end); - - if let Some(p) = p { - self.path = p; + if let Some(p) = p { + self.path[i] = p; + } } } }