Refactor graph and misc

This commit is contained in:
hal8174 2025-03-02 22:51:25 +01:00
parent 5f5fe0c149
commit 8f163269bd
22 changed files with 126 additions and 45 deletions

8
Cargo.lock generated
View file

@ -581,6 +581,13 @@ dependencies = [
"termcolor", "termcolor",
] ]
[[package]]
name = "factorio-graph"
version = "0.1.0"
dependencies = [
"tracing",
]
[[package]] [[package]]
name = "factorio-layout" name = "factorio-layout"
version = "0.1.0" version = "0.1.0"
@ -608,6 +615,7 @@ dependencies = [
"criterion", "criterion",
"factorio-blueprint", "factorio-blueprint",
"factorio-core", "factorio-core",
"factorio-graph",
"flate2", "flate2",
"image", "image",
"miette", "miette",

View file

@ -1,5 +1,5 @@
[workspace] [workspace]
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core", "factorio-layout", members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core", "factorio-graph", "factorio-layout",
"factorio-pathfinding" "factorio-pathfinding"
] ]
resolver = "2" resolver = "2"

View file

@ -3,6 +3,7 @@ pub mod beltoptions;
pub mod block; pub mod block;
pub mod color; pub mod color;
pub mod direction; pub mod direction;
pub mod misc;
pub mod pathfield; pub mod pathfield;
pub mod position; pub mod position;
pub mod quaterdirection; pub mod quaterdirection;

View file

@ -23,7 +23,27 @@ where
data, data,
} }
} }
}
impl<T> Map<T>
where
T: Clone,
{
pub fn new_with(width: usize, height: usize, value: T) -> Self {
let mut data = Vec::new();
for _ in 0..(width * height) {
data.push(value.clone());
}
Self {
width,
height,
data,
}
}
}
impl<T> Map<T> {
fn index(&self, x: usize, y: usize) -> usize { fn index(&self, x: usize, y: usize) -> usize {
x + y * self.width x + y * self.width
} }

View file

@ -91,3 +91,14 @@ impl From<(PositionType, PositionType)> for Position {
Self::new(value.0, value.1) Self::new(value.0, value.1)
} }
} }
impl std::ops::Div<PositionType> for Position {
type Output = Position;
fn div(self, rhs: PositionType) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
}
}
}

View file

@ -85,6 +85,14 @@ impl Color {
Self::new(255, 255, 255) Self::new(255, 255, 255)
} }
pub fn cyan() -> Self {
Self::new(0x0f, 0xf0, 0xfc)
}
pub fn gray(l: u8) -> Self {
Self::new(l, l, l)
}
pub fn index(i: usize) -> Self { pub fn index(i: usize) -> Self {
let c = [ let c = [
Color::new(0xe6, 0x00, 0x49), Color::new(0xe6, 0x00, 0x49),

View file

@ -0,0 +1,7 @@
[package]
name = "factorio-graph"
version = "0.1.0"
edition = "2024"
[dependencies]
tracing = "0.1.41"

View file

@ -1 +1,2 @@
pub mod priority_queue;
pub mod wheighted_graph; pub mod wheighted_graph;

View file

@ -1,5 +1,6 @@
pub mod adjacency_list; pub mod adjacency_list;
pub mod shortest_path; pub mod shortest_path;
pub mod steiner_tree;
pub trait WheightedGraph: Sized { pub trait WheightedGraph: Sized {
type Node; type Node;

View file

@ -56,15 +56,16 @@ impl<N, H> MapObject<N, H> {
} }
} }
pub fn dijkstra<G, P>(graph: &G, start: G::Node, end: G::Node) -> Option<Vec<G::Node>> pub fn dijkstra<G, P, E>(graph: &G, start: G::Node, end: E) -> Option<Vec<G::Node>>
where where
P: PriorityQueue<QueueObject<G::Node>> + Debug, P: PriorityQueue<QueueObject<G::Node>> + Debug,
P::Handle: Debug, P::Handle: Debug,
G::Node: Eq + Hash + Clone + Debug, G::Node: Eq + Hash + Clone + Debug,
G: WheightedGraph, G: WheightedGraph,
E: Fn(&'_ G::Node) -> bool,
{ {
let span = trace_span!("graph", seen_nodes = Empty, visited_nodes = Empty).entered(); let span = trace_span!("graph", seen_nodes = Empty, visited_nodes = Empty).entered();
if start == end { if end(&start) {
return Some(vec![start]); return Some(vec![start]);
} }
@ -75,13 +76,15 @@ where
let mut visited_nodes: usize = 1; let mut visited_nodes: usize = 1;
let mut end_node = None;
while let Some(o) = q.pop_min() { while let Some(o) = q.pop_min() {
visited_nodes += 1; visited_nodes += 1;
if let Some(m) = map.get_mut(&o.node) { if let Some(m) = map.get_mut(&o.node) {
m.key = None; m.key = None;
} }
if o.node == end { if end(&o.node) {
end_node = Some(o.node);
break; break;
} }
@ -106,23 +109,27 @@ where
span.record("seen_nodes", map.len()); span.record("seen_nodes", map.len());
span.record("visited_nodes", visited_nodes); span.record("visited_nodes", visited_nodes);
map.get(&end)?; if let Some(end_node) = end_node {
map.get(&end_node)?;
let mut result = vec![end]; let mut result = vec![end_node];
// dbg!(&map); // dbg!(&map);
loop { loop {
let parent = map.get(result.last().expect("last")).expect("get"); let parent = map.get(result.last().expect("last")).expect("get");
result.push(parent.parent.clone()); result.push(parent.parent.clone());
if parent.parent == start { if parent.parent == start {
break; break;
}
} }
result.reverse();
Some(result)
} else {
None
} }
result.reverse();
Some(result)
} }
struct GraphWrapper<'a, G, F> { struct GraphWrapper<'a, G, F> {
@ -141,27 +148,28 @@ impl<G: WheightedGraph, F: Fn(&G::Node) -> f64> WheightedGraph for GraphWrapper<
} }
} }
pub fn a_star<G, P, F>(graph: &G, start: G::Node, end: G::Node, dist: F) -> Option<Vec<G::Node>> pub fn a_star<G, P, E, F>(graph: &G, start: G::Node, end: E, dist: F) -> Option<Vec<G::Node>>
where where
P: PriorityQueue<QueueObject<G::Node>> + Debug, P: PriorityQueue<QueueObject<G::Node>> + Debug,
P::Handle: Debug, P::Handle: Debug,
G::Node: Eq + Hash + Clone + Debug, G::Node: Eq + Hash + Clone + Debug,
G: WheightedGraph, G: WheightedGraph,
E: Fn(&'_ G::Node) -> bool,
F: Fn(&G::Node) -> f64, F: Fn(&G::Node) -> f64,
{ {
let g = GraphWrapper { g: graph, f: dist }; let g = GraphWrapper { g: graph, f: dist };
dijkstra::<GraphWrapper<G, F>, P>(&g, start, end) dijkstra::<GraphWrapper<G, F>, P, E>(&g, start, end)
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::{ use crate::{
graph::wheighted_graph::{
adjacency_list::WheightedAdjacencyList, shortest_path::dijkstra, WheightedGraph,
},
priority_queue::{binary_heap::BinaryHeap, fibonacci_heap::FibonacciHeap}, priority_queue::{binary_heap::BinaryHeap, fibonacci_heap::FibonacciHeap},
wheighted_graph::{
WheightedGraph, adjacency_list::WheightedAdjacencyList, shortest_path::dijkstra,
},
}; };
#[test] #[test]
@ -172,7 +180,7 @@ mod test {
}; };
assert_eq!( assert_eq!(
dijkstra::<WheightedAdjacencyList, BinaryHeap<_>>(&a, 0, 1), dijkstra::<WheightedAdjacencyList, BinaryHeap<_>, _>(&a, 0, |&n| n == 1),
Some(vec![0, 1]) Some(vec![0, 1])
); );
} }
@ -197,19 +205,19 @@ mod test {
}; };
assert_eq!( assert_eq!(
dijkstra::<WheightedAdjacencyList, BinaryHeap<_>>(&a, 0, 4), dijkstra::<WheightedAdjacencyList, BinaryHeap<_>, _>(&a, 0, |&n| n == 4),
Some(vec![0, 1, 2, 5, 4]) Some(vec![0, 1, 2, 5, 4])
); );
assert_eq!( assert_eq!(
dijkstra::<WheightedAdjacencyList, BinaryHeap<_>>(&a, 0, 6), dijkstra::<WheightedAdjacencyList, BinaryHeap<_>, _>(&a, 0, |&n| n == 6),
None None
); );
assert_eq!( assert_eq!(
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 4), dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>, _>(&a, 0, |&n| n == 4),
Some(vec![0, 1, 2, 5, 4]) Some(vec![0, 1, 2, 5, 4])
); );
assert_eq!( assert_eq!(
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 6), dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>, _>(&a, 0, |&n| n == 6),
None None
); );
} }
@ -264,10 +272,6 @@ mod test {
height: 600, height: 600,
}; };
dbg!(dijkstra::<Grid, BinaryHeap<_>>( dbg!(dijkstra::<Grid, BinaryHeap<_>, _>(&g, (0, 0), |&n| n == (g.width - 1, g.height - 1)));
&g,
(0, 0),
(g.width - 1, g.height - 1)
));
} }
} }

View file

@ -0,0 +1,17 @@
use crate::priority_queue::PriorityQueue;
use std::hash::Hash;
use std::{collections::HashSet, fmt::Debug};
use super::{WheightedGraph, shortest_path::QueueObject};
pub fn takaheshi_matsuyama<G, P>(graph: G, nodes: &[G::Node]) -> Option<Vec<Vec<G::Node>>>
where
P: PriorityQueue<QueueObject<G::Node>> + Debug,
P::Handle: Debug,
G::Node: Eq + Hash + Clone,
G: WheightedGraph,
{
let end_nodes: HashSet<G::Node> = HashSet::from_iter(nodes.iter().cloned());
todo!()
}

View file

@ -15,6 +15,7 @@ harness = false
[dependencies] [dependencies]
factorio-core = { path = "../factorio-core" } factorio-core = { path = "../factorio-core" }
factorio-graph = { path = "../factorio-graph" }
factorio-blueprint = { path = "../factorio-blueprint" } factorio-blueprint = { path = "../factorio-blueprint" }
base64 = "0.22.1" base64 = "0.22.1"
bon = "3.0.2" bon = "3.0.2"

View file

@ -1,7 +1,7 @@
use factorio_core::{pathfield::PathField, prelude::*, visualize::Visualize}; use factorio_core::{pathfield::PathField, prelude::*, visualize::Visualize};
use std::time::Instant; use std::time::Instant;
use crate::misc::Map; use factorio_core::misc::Map;
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct BruteforceField { pub struct BruteforceField {

View file

@ -1,5 +1,6 @@
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map}; use crate::belt_finding::brute_force::BruteforceBuilder;
use factorio_blueprint::{belt::convert_to_blueprint, BlueprintEntity}; use factorio_blueprint::{BlueprintEntity, belt::convert_to_blueprint};
use factorio_core::misc::Map;
use factorio_core::{ use factorio_core::{
beltoptions::Beltspeed, pathfield::PathField, prelude::*, visualize::Visualize, beltoptions::Beltspeed, pathfield::PathField, prelude::*, visualize::Visualize,
}; };
@ -7,7 +8,7 @@ use std::{
ops::RangeInclusive, ops::RangeInclusive,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tracing::{span, Level}; use tracing::{Level, span};
use super::Problem; use super::Problem;

View file

@ -3,11 +3,11 @@ use crate::Map as _;
use crate::SinglePathInput; use crate::SinglePathInput;
use crate::SinglePathfinder; use crate::SinglePathfinder;
use crate::examples::HashMapMap; use crate::examples::HashMapMap;
use crate::graph::wheighted_graph::WheightedGraph; use factorio_core::misc::Map;
use crate::graph::wheighted_graph::shortest_path::a_star;
use crate::misc::Map;
use crate::priority_queue::binary_heap::FastBinaryHeap;
use factorio_core::{prelude::*, visualize::Visualize}; use factorio_core::{prelude::*, visualize::Visualize};
use factorio_graph::priority_queue::binary_heap::FastBinaryHeap;
use factorio_graph::wheighted_graph::WheightedGraph;
use factorio_graph::wheighted_graph::shortest_path::a_star;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tracing::Level; use tracing::Level;
use tracing::span; use tracing::span;
@ -222,7 +222,11 @@ struct MapInternal<'a> {
impl WheightedGraph for MapInternal<'_> { impl WheightedGraph for MapInternal<'_> {
type Node = (Position, Direction); type Node = (Position, Direction);
fn edge(&self, node: &Self::Node, num: usize) -> Option<(Self::Node, f64)> { fn edge(
&self,
node: &(Position, Direction),
num: usize,
) -> Option<((Position, Direction), f64)> {
let next = node.0.in_direction(&node.1, 1); let next = node.0.in_direction(&node.1, 1);
next.in_range( next.in_range(
&Position::new(0, 0), &Position::new(0, 0),
@ -276,10 +280,10 @@ impl Problem {
}; };
let p = { let p = {
// dijkstra::<MapInternal, FastBinaryHeap<_>>(&m, self.start[i], self.end[i]) // dijkstra::<MapInternal, FastBinaryHeap<_>>(&m, self.start[i], self.end[i])
a_star::<MapInternal, FastBinaryHeap<_>, _>( a_star::<MapInternal, FastBinaryHeap<_>, _, _>(
&m, &m,
self.start[i], self.start[i],
self.end[i], |&n| n == self.end[i],
|&(p, _)| { |&(p, _)| {
1.5 * (PositionType::abs_diff(p.x, self.end[i].0.x) 1.5 * (PositionType::abs_diff(p.x, self.end[i].0.x)
+ PositionType::abs_diff(p.y, self.end[i].0.y)) + PositionType::abs_diff(p.y, self.end[i].0.y))

View file

@ -2,9 +2,6 @@ use factorio_core::{beltoptions::Beltspeed, pathfield::PathField, prelude::*};
pub mod belt_finding; pub mod belt_finding;
pub mod examples; pub mod examples;
pub mod graph;
pub mod misc;
pub mod priority_queue;
pub struct PathInput<'c, M> { pub struct PathInput<'c, M> {
pub connections: &'c [Connection], pub connections: &'c [Connection],