Add PathFinder trait

This commit is contained in:
hal8174 2025-01-28 21:54:20 +01:00
parent 5c8010c23b
commit 08eb0a8e11
8 changed files with 688 additions and 373 deletions

View file

@ -1,7 +1,10 @@
use crate::graph::wheighted_graph::shortest_path::dijkstra;
use crate::examples::HashMapMap;
use crate::graph::wheighted_graph::WheightedGraph;
use crate::misc::Map;
use crate::priority_queue::BinaryHeap;
use crate::Connection;
use crate::Map as _;
use crate::{graph::wheighted_graph::shortest_path::dijkstra, SinglePathfinder};
use factorio_core::{prelude::*, visualize::Visualize};
use serde::{Deserialize, Serialize};
@ -9,6 +12,45 @@ pub mod brute_force;
pub mod conflict_avoidance;
pub struct ConflictAvoidance {
timeout: Option<std::time::Duration>,
}
impl SinglePathfinder for ConflictAvoidance {
fn find_paths(
&self,
input: &[crate::SingleConnection],
map: impl crate::Map,
) -> Option<Vec<Vec<factorio_core::pathfield::PathField>>> {
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));
}
if p.find_path() {
let mut c = conflict_avoidance::ConflictAvoidance::new(&p);
if c.remove_all_conflicts(self.timeout) {
Some(c.get_paths().to_vec())
} else {
None
}
} else {
None
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
pub struct Field {
pub blocked: bool,
@ -33,45 +75,6 @@ impl Problem {
}
}
// pub fn from_layout(l: &Layout) -> Self {
// let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
// for b in &l.blocks {
// let aabb = b.get_aabb();
// p.set_blocked_range(
// aabb.min().x as usize,
// aabb.min().y as usize,
// aabb.max().x as usize,
// aabb.max().y as usize,
// true,
// );
// }
// for c in &l.problem.connections {
// let start_transform = l.blocks[c.startblock].block_to_world();
// let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
// .offset
// .transform(start_transform);
// let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
// .dir
// .transform(start_transform);
// let end_transform = l.blocks[c.endblock].block_to_world();
// let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
// .offset
// .transform(end_transform);
// let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
// .dir
// .transform(end_transform);
// p.add_connection(
// (startpos, startdir),
// (endpos.in_direction(&enddir, -1), enddir),
// );
// }
// p
// }
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
self.start.push(start);
self.end.push(end);
@ -125,6 +128,27 @@ impl Problem {
}
}
impl From<(Vec<Connection>, HashMapMap)> for Problem {
fn from((input, map): (Vec<Connection>, 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(
@ -247,321 +271,3 @@ impl Problem {
true
}
}
pub mod problems {
use super::Problem;
use factorio_core::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
}
}

View file

@ -1,8 +1,9 @@
use clap::{Parser, Subcommand, ValueEnum};
use factorio_blueprint::{encode, Blueprint, BlueprintString};
use factorio_core::{beltoptions::Beltspeed, visualize::Visualize};
use factorio_pathfinding::belt_finding::{
conflict_avoidance::ConflictAvoidance, problems, Problem,
use factorio_pathfinding::{
belt_finding::{conflict_avoidance::ConflictAvoidance, Problem},
examples,
};
use std::{io, path::PathBuf};
@ -26,11 +27,11 @@ enum ProblemCase {
impl ProblemCase {
fn get_problem(&self) -> Problem {
match self {
ProblemCase::Simple => problems::simple(),
ProblemCase::Level1 => problems::belt_madness_level_1(),
ProblemCase::Level2 => problems::belt_madness_level_2(),
ProblemCase::Level3 => problems::belt_madness_level_3(),
ProblemCase::Level5 => problems::belt_madness_level_5(),
ProblemCase::Simple => examples::simple().into(),
ProblemCase::Level1 => examples::belt_madness_level_1().into(),
ProblemCase::Level2 => examples::belt_madness_level_2().into(),
ProblemCase::Level3 => examples::belt_madness_level_3().into(),
ProblemCase::Level5 => examples::belt_madness_level_5().into(),
ProblemCase::File { filename } => {
let file = std::fs::File::open(filename).unwrap();
serde_json::from_reader(file).unwrap()

View file

@ -0,0 +1,527 @@
use crate::{Connection, Map};
use factorio_core::{
beltoptions::Beltspeed,
prelude::*,
visualize::{Visualization, Visualize},
};
use std::collections::HashSet;
pub struct HashMapMap {
map: HashSet<Position>,
size: Position,
}
impl HashMapMap {
fn new(size: impl Into<Position>) -> Self {
Self {
map: HashSet::new(),
size: size.into(),
}
}
fn set_blocked_range(
&mut self,
min_pos: impl Into<Position>,
max_pos: impl Into<Position>,
block: bool,
) {
let min_pos = min_pos.into();
let max_pos = max_pos.into();
for x in min_pos.x..=max_pos.x {
for y in min_pos.y..=max_pos.y {
self.set_blocked(Position::new(x, y), block);
}
}
}
fn set_blocked(&mut self, pos: impl Into<Position>, block: bool) {
let pos = pos.into();
if block {
self.map.insert(pos);
} else {
self.map.remove(&pos);
}
}
}
impl Visualize for HashMapMap {
fn visualize(&self) -> factorio_core::visualize::Visualization {
let mut v = Visualization::new(self.size);
for &p in &self.map {
v.add_symbol(p, factorio_core::visualize::Symbol::Block, None, None);
}
v
}
}
impl Map for HashMapMap {
fn get_position(&self, pos: Position) -> bool {
if pos.x < 0 || pos.y < 0 || pos.x >= self.size.x || pos.y >= self.size.y {
false
} else {
!self.map.contains(&pos)
}
}
fn area(&self) -> (Position, Position) {
(Position::new(0, 0), self.size)
}
}
pub fn simple() -> (Vec<Connection>, HashMapMap) {
let mut m = HashMapMap::new((5, 3));
m.set_blocked_range((2, 0), (2, 2), true);
(
vec![Connection {
start_pos: Position::new(0, 1),
start_dir: Direction::Right,
end_pos: Position::new(4, 1),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
}],
m,
)
}
pub fn belt_madness_level_1() -> (Vec<Connection>, HashMapMap) {
let mut m = HashMapMap::new((17, 13));
m.set_blocked((0, 3), true);
m.set_blocked((1, 4), true);
m.set_blocked((2, 4), true);
m.set_blocked((1, 5), true);
m.set_blocked((2, 5), true);
m.set_blocked((1, 7), true);
m.set_blocked((2, 7), true);
m.set_blocked((1, 8), true);
m.set_blocked((2, 8), true);
m.set_blocked((0, 9), true);
m.set_blocked((16, 3), true);
m.set_blocked((14, 4), true);
m.set_blocked((15, 4), true);
m.set_blocked((14, 5), true);
m.set_blocked((15, 5), true);
m.set_blocked((14, 7), true);
m.set_blocked((15, 7), true);
m.set_blocked((14, 8), true);
m.set_blocked((15, 8), true);
m.set_blocked((16, 9), true);
(
vec![
Connection {
start_pos: Position::new(2, 7),
start_dir: Direction::Right,
end_pos: Position::new(13, 4),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 8),
start_dir: Direction::Right,
end_pos: Position::new(13, 5),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 4),
start_dir: Direction::Right,
end_pos: Position::new(13, 8),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 5),
start_dir: Direction::Right,
end_pos: Position::new(13, 7),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
],
m,
)
}
pub fn belt_madness_level_2() -> (Vec<Connection>, HashMapMap) {
let mut m = HashMapMap::new((17, 13));
m.set_blocked((0, 3), true);
m.set_blocked_range((1, 2), (2, 5), true);
m.set_blocked_range((1, 7), (2, 10), true);
m.set_blocked((0, 9), true);
m.set_blocked((16, 3), true);
m.set_blocked_range((14, 2), (15, 5), true);
m.set_blocked_range((14, 7), (15, 10), true);
m.set_blocked((16, 9), true);
(
vec![
Connection {
start_pos: Position::new(2, 4),
start_dir: Direction::Right,
end_pos: Position::new(13, 2),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 7),
start_dir: Direction::Right,
end_pos: Position::new(13, 3),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 10),
start_dir: Direction::Right,
end_pos: Position::new(13, 4),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 9),
start_dir: Direction::Right,
end_pos: Position::new(13, 5),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 2),
start_dir: Direction::Right,
end_pos: Position::new(13, 7),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 3),
start_dir: Direction::Right,
end_pos: Position::new(13, 8),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 5),
start_dir: Direction::Right,
end_pos: Position::new(13, 9),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 8),
start_dir: Direction::Right,
end_pos: Position::new(13, 10),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
],
m,
)
}
pub fn belt_madness_level_3() -> (Vec<Connection>, HashMapMap) {
let mut m = HashMapMap::new((33, 13));
m.set_blocked_range((1, 3), (2, 5), true);
m.set_blocked_range((1, 7), (2, 9), true);
m.set_blocked((0, 3), true);
m.set_blocked((0, 8), true);
m.set_blocked_range((10, 0), (21, 2), true);
m.set_blocked_range((10, 5), (21, 7), true);
m.set_blocked_range((10, 10), (21, 12), true);
m.set_blocked_range((30, 3), (31, 5), true);
m.set_blocked_range((30, 7), (31, 9), true);
m.set_blocked((32, 3), true);
m.set_blocked((32, 9), true);
(
vec![
Connection {
start_pos: Position::new(2, 3),
start_dir: Direction::Right,
end_pos: Position::new(29, 7),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 4),
start_dir: Direction::Right,
end_pos: Position::new(29, 9),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 5),
start_dir: Direction::Right,
end_pos: Position::new(29, 8),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 7),
start_dir: Direction::Right,
end_pos: Position::new(29, 3),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 8),
start_dir: Direction::Right,
end_pos: Position::new(29, 5),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 9),
start_dir: Direction::Right,
end_pos: Position::new(29, 4),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
],
m,
)
}
pub fn belt_madness_level_5() -> (Vec<Connection>, HashMapMap) {
let mut m = HashMapMap::new((31, 29));
// power stations
m.set_blocked_range((8, 8), (9, 9), true);
m.set_blocked_range((21, 8), (22, 9), true);
m.set_blocked_range((8, 19), (9, 20), true);
m.set_blocked_range((21, 19), (22, 20), true);
// solar panels
m.set_blocked_range((12, 11), (14, 13), true);
m.set_blocked_range((16, 11), (18, 13), true);
m.set_blocked_range((12, 15), (14, 17), true);
m.set_blocked_range((16, 15), (18, 17), true);
// Top
m.set_blocked_range((7, 0), (8, 2), true);
m.set_blocked((8, 3), true);
m.set_blocked((9, 4), true);
m.set_blocked_range((10, 5), (20, 5), true);
m.set_blocked((21, 4), true);
m.set_blocked((22, 3), true);
m.set_blocked_range((22, 0), (23, 2), true);
m.set_blocked_range((2, 1), (2, 2), true);
m.set_blocked_range((4, 1), (4, 2), true);
m.set_blocked_range((1, 4), (2, 4), true);
m.set_blocked_range((12, 1), (12, 2), true);
m.set_blocked_range((14, 1), (14, 2), true);
m.set_blocked_range((16, 1), (16, 2), true);
m.set_blocked_range((18, 1), (18, 2), true);
m.set_blocked_range((28, 4), (29, 4), true);
m.set_blocked_range((26, 1), (26, 2), true);
m.set_blocked_range((28, 1), (28, 2), true);
// Bottom
m.set_blocked_range((7, 26), (8, 28), true);
m.set_blocked((8, 25), true);
m.set_blocked((9, 24), true);
m.set_blocked_range((10, 23), (20, 23), true);
m.set_blocked((21, 24), true);
m.set_blocked((22, 25), true);
m.set_blocked_range((22, 26), (23, 28), true);
m.set_blocked_range((1, 26), (2, 26), true);
m.set_blocked_range((4, 26), (4, 27), true);
m.set_blocked_range((1, 24), (2, 24), true);
m.set_blocked_range((12, 26), (12, 27), true);
m.set_blocked_range((14, 26), (14, 27), true);
m.set_blocked_range((16, 26), (16, 27), true);
m.set_blocked_range((18, 26), (18, 27), true);
m.set_blocked_range((28, 24), (29, 24), true);
m.set_blocked_range((26, 26), (26, 27), true);
m.set_blocked_range((28, 26), (29, 26), true);
// Left
m.set_blocked_range((0, 7), (2, 8), true);
m.set_blocked((3, 8), true);
m.set_blocked((4, 9), true);
m.set_blocked_range((5, 10), (5, 18), true);
m.set_blocked((4, 19), true);
m.set_blocked((3, 20), true);
m.set_blocked_range((0, 20), (2, 21), true);
m.set_blocked_range((1, 11), (2, 11), true);
m.set_blocked_range((1, 13), (2, 13), true);
m.set_blocked_range((1, 15), (2, 15), true);
m.set_blocked_range((1, 17), (2, 17), true);
// Right
m.set_blocked_range((28, 7), (30, 8), true);
m.set_blocked((27, 8), true);
m.set_blocked((26, 9), true);
m.set_blocked_range((25, 10), (25, 18), true);
m.set_blocked((26, 19), true);
m.set_blocked((27, 20), true);
m.set_blocked_range((28, 20), (30, 21), true);
m.set_blocked_range((28, 11), (29, 11), true);
m.set_blocked_range((28, 13), (29, 13), true);
m.set_blocked_range((28, 15), (29, 15), true);
m.set_blocked_range((28, 17), (29, 17), true);
// Path
(
vec![
Connection {
start_pos: Position::new(4, 2),
start_dir: Direction::Down,
end_pos: Position::new(26, 25),
end_dir: Direction::Down,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(12, 2),
start_dir: Direction::Down,
end_pos: Position::new(18, 25),
end_dir: Direction::Down,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(14, 2),
start_dir: Direction::Down,
end_pos: Position::new(3, 26),
end_dir: Direction::Left,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(16, 2),
start_dir: Direction::Down,
end_pos: Position::new(14, 25),
end_dir: Direction::Down,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 4),
start_dir: Direction::Right,
end_pos: Position::new(27, 24),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 11),
start_dir: Direction::Right,
end_pos: Position::new(27, 17),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 13),
start_dir: Direction::Right,
end_pos: Position::new(27, 26),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 15),
start_dir: Direction::Right,
end_pos: Position::new(27, 13),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(28, 15),
start_dir: Direction::Left,
end_pos: Position::new(2, 3),
end_dir: Direction::Up,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 17),
start_dir: Direction::Right,
end_pos: Position::new(18, 3),
end_dir: Direction::Up,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(2, 24),
start_dir: Direction::Right,
end_pos: Position::new(26, 3),
end_dir: Direction::Up,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(4, 26),
start_dir: Direction::Up,
end_pos: Position::new(27, 4),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(12, 26),
start_dir: Direction::Up,
end_pos: Position::new(27, 11),
end_dir: Direction::Right,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
Connection {
start_pos: Position::new(16, 26),
start_dir: Direction::Up,
end_pos: Position::new(28, 3),
end_dir: Direction::Up,
beltspeed: Beltspeed::Normal,
lanes: 1,
},
],
m,
)
}

View file

@ -1,4 +1,74 @@
use factorio_core::{beltoptions::Beltspeed, pathfield::PathField, prelude::*};
pub mod belt_finding;
pub mod examples;
pub mod graph;
pub mod misc;
pub mod priority_queue;
pub struct Connection {
pub start_pos: Position,
pub start_dir: Direction,
pub end_pos: Position,
pub end_dir: Direction,
pub beltspeed: Beltspeed,
pub lanes: usize,
}
pub trait Map {
/// Returns true if the position is useable
fn get_position(&self, pos: Position) -> bool;
/// Returns the relevant area as (pos, size)
fn area(&self) -> (Position, Position);
}
pub trait Pathfinder {
fn find_paths(&self, input: &[Connection], map: impl Map) -> Option<Vec<Vec<PathField>>>;
}
struct SingleConnection {
pub start_pos: Position,
pub start_dir: Direction,
pub end_pos: Position,
pub end_dir: Direction,
pub beltspeed: Beltspeed,
}
trait SinglePathfinder {
fn find_paths(&self, input: &[SingleConnection], map: impl Map) -> Option<Vec<Vec<PathField>>>;
}
impl<P> Pathfinder for P
where
P: SinglePathfinder,
{
fn find_paths(&self, input: &[Connection], map: impl Map) -> Option<Vec<Vec<PathField>>> {
let inner_input = input
.iter()
.flat_map(|c| {
(0..c.lanes).map(|i| SingleConnection {
start_pos: c
.start_pos
.in_direction(&c.start_dir.clockwise(), i as PositionType),
start_dir: c.start_dir,
end_pos: c
.end_pos
.in_direction(&c.start_dir.clockwise(), i as PositionType),
end_dir: c.end_dir,
beltspeed: c.beltspeed,
})
})
.collect::<Vec<_>>();
let inner_result = self.find_paths(&inner_input, map)?;
let mut inner_iterator = inner_result.into_iter();
Some(
input
.iter()
.map(|i| inner_iterator.by_ref().take(i.lanes).flatten().collect())
.collect(),
)
}
}