Working roboport power connection.

This commit is contained in:
hal8174 2025-03-25 18:01:23 +01:00
parent a748708998
commit 068297e2c2
5 changed files with 258 additions and 15 deletions

View file

@ -538,7 +538,10 @@ pub fn generate_factory<L: Layouter, P: Pathfinder + Sync, R: Rng + SeedableRng
b.add_blueprint(multistation_blueprint); b.add_blueprint(multistation_blueprint);
b.add_roboport_network(); b.add_roboport_network();
b.print_visualization();
b.connect_roboport_power();
b.print_visualization();
b.connect_power_networks(); b.connect_power_networks();
b b

View file

@ -441,7 +441,7 @@ impl Entity {
} }
} }
ElectricPoleType::Substation => { ElectricPoleType::Substation => {
for (dx, dy) in [(-1, -1), (1, -1), (-1, 1), (1, 1)] { for (dx, dy) in [(-2, -2), (0, -2), (-2, 0), (0, 0)] {
v.add_symbol( v.add_symbol(
(self.position + Position::new(dx, dy)) / 2 + offset, (self.position + Position::new(dx, dy)) / 2 + offset,
factorio_core::visualize::Symbol::Char('S'), factorio_core::visualize::Symbol::Char('S'),
@ -451,6 +451,18 @@ impl Entity {
} }
} }
}, },
EntityType::Roboport => {
for dx in -2..2 {
for dy in -2..2 {
v.add_symbol(
(self.position) / 2 + Position::new(dx, dy) + offset,
factorio_core::visualize::Symbol::Char('R'),
Some(Color::yellow()),
None,
)
}
}
}
_ => (), _ => (),
} }
} }

View file

@ -1,6 +1,10 @@
use std::ops::Index;
use factorio_core::visualize::Visualize;
use factorio_graph::{ use factorio_graph::{
graph::Graph,
priority_queue::binary_heap::FastBinaryHeap, priority_queue::binary_heap::FastBinaryHeap,
wheighted_graph::{WheightedGraph, steiner_tree}, wheighted_graph::{WheightedGraph, shortest_path::dijkstra, steiner_tree},
}; };
use super::*; use super::*;
@ -155,16 +159,6 @@ impl Blueprint {
if let Some(cost) = cost { if let Some(cost) = cost {
let v = power_connections(Position::new(x, y), electric_pole_type) let v = power_connections(Position::new(x, y), electric_pole_type)
// .filter(|&(pos, _)| aabb.contains_pos(pos))
// .inspect(|d| {
// if y == 261 {
// dbg!(d);
// }
// })
// .filter(|&(pos, electric_pole_type)| {
// placibility.placeable(pos, electric_pole_type.size())
// || power_pole_map.contains_key(&(pos, electric_pole_type))
// })
.collect(); .collect();
nodes.insert((Position::new(x, y), electric_pole_type), (v, cost)); nodes.insert((Position::new(x, y), electric_pole_type), (v, cost));
} }
@ -230,3 +224,228 @@ impl Blueprint {
} }
} }
} }
struct MultistartGraph<'a, G: WheightedGraph> {
graph: &'a G,
start_nodes: Vec<G::Node>,
}
impl<G: WheightedGraph> WheightedGraph for MultistartGraph<'_, G>
where
G::Node: Clone,
{
type Node = Option<G::Node>;
fn edge(&self, node: &Self::Node, num: usize) -> Option<(Self::Node, f64)> {
match node {
Some(n) => self.graph.edge(n, num).map(|(e, w)| (Some(e), w)),
None => self.start_nodes.get(num).map(|n| (Some(n.clone()), 0.0)),
}
}
}
impl Blueprint {
pub fn connect_roboport_power(&mut self) {
let mut roboportmap = self
.entities
.iter()
.filter_map(|(k, e)| match e.entity {
EntityType::Roboport => Some(e.position),
_ => None,
})
.collect::<Vec<_>>();
if roboportmap.len() == 0 {
return;
} else if roboportmap.len() == 1 {
let roboport = roboportmap.into_iter().next().unwrap();
for (x, y) in ((roboport.x - 8)..=(roboport.x + 8))
.filter(move |x| x.rem_euclid(2) == 1)
.flat_map(|x| {
((roboport.y - 8)..=(roboport.y + 8))
.filter(move |y| y.rem_euclid(2) == 1)
.map(move |y| (x, y))
})
{
if self.placeable(Position::new(x, y), Position::new(2, 2)) {
self.add_entity(Entity::new_electric_pole(
super::ElectricPoleType::Small,
Position::new(x, y),
));
return;
}
}
panic!("unable to place power pole around roboport");
}
let aabb = self.get_aabb().unwrap();
let start_roboport = roboportmap.pop().unwrap();
let mut start_nodes = Vec::new();
{
let placibility = self.placibility_map();
for (electric_pole_type, dist) in [
(ElectricPoleType::Small, 9),
(ElectricPoleType::Medium, 11),
(ElectricPoleType::Big, 6),
] {
for (x, y) in
((start_roboport.x - dist)..=(start_roboport.x + dist)).flat_map(|x| {
((start_roboport.y - dist)..=(start_roboport.y + dist)).map(move |y| (x, y))
})
{
// dbg!(x, y, electric_pole_type);
let alignment = electric_pole_type.alignment();
if x.rem_euclid(2) == alignment && y.rem_euclid(2) == alignment {
if placibility.placeable(Position::new(x, y), electric_pole_type.size()) {
start_nodes.push(Node {
pos: Position::new(x, y),
electric_pole_type,
node_type: NodeType::In,
});
}
}
}
}
}
let mut visited_roboports = vec![start_roboport];
while !roboportmap.is_empty() {
let placibility = self.placibility_map();
let mut power_pole_map = self
.entities
.iter()
.filter_map(|(k, e)| match e.entity {
EntityType::ElectricPole(electric_pole_type) => {
Some(((e.position, electric_pole_type), *k))
}
_ => None,
})
.collect::<HashMap<_, _>>();
let mut nodes = HashMap::new();
for y in aabb.min().y..=aabb.max().y {
for x in aabb.min().x..=aabb.max().x {
for electric_pole_type in [
ElectricPoleType::Small,
ElectricPoleType::Medium,
ElectricPoleType::Big,
] {
// dbg!(x, y, electric_pole_type);
let alignment = electric_pole_type.alignment();
if x.rem_euclid(2) == alignment
&& y.rem_euclid(2) == alignment
&& visited_roboports
.iter()
.any(|p| p.x.abs_diff(x) < 110 && p.y.abs_diff(y) < 110)
{
let cost = if placibility
.placeable(Position::new(x, y), electric_pole_type.size())
{
Some(match electric_pole_type {
ElectricPoleType::Small => 0.8,
ElectricPoleType::Medium => 1.0,
ElectricPoleType::Big => 1.5,
ElectricPoleType::Substation => todo!(),
})
} else if power_pole_map
.contains_key(&(Position::new(x, y), electric_pole_type))
{
Some(0.0)
} else {
None
};
if let Some(cost) = cost {
let v = power_connections(Position::new(x, y), electric_pole_type)
.collect();
nodes.insert((Position::new(x, y), electric_pole_type), (v, cost));
}
}
}
}
}
let power_graph = PowerGraph { nodes };
let multistart_graph = MultistartGraph {
graph: &power_graph,
start_nodes: start_nodes.clone(),
};
let p = dijkstra::<_, FastBinaryHeap<_>, _>(&multistart_graph, None, |p| {
if let Some(n) = p {
match n.node_type {
NodeType::In => false,
NodeType::Out => {
let dist = match n.electric_pole_type {
ElectricPoleType::Small => 7,
ElectricPoleType::Medium => 9,
ElectricPoleType::Big => 6,
ElectricPoleType::Substation => todo!(),
};
roboportmap.iter().any(|r| {
r.x.abs_diff(n.pos.x) <= dist && r.y.abs_diff(n.pos.y) <= dist
})
}
}
} else {
false
}
});
if let Some(path) = p {
start_nodes = vec![path[1].unwrap()];
let path_iter = path.iter().filter_map(|n| n.as_ref()).filter_map(
|Node {
pos,
electric_pole_type,
node_type,
}| match node_type {
NodeType::In => None,
NodeType::Out => Some((*pos, *electric_pole_type)),
},
);
for p in path_iter.clone() {
match power_pole_map.entry(p) {
std::collections::hash_map::Entry::Occupied(_occupied_entry) => (),
std::collections::hash_map::Entry::Vacant(vacant_entry) => {
let k = self.add_entity(Entity::new_electric_pole(p.1, p.0));
vacant_entry.insert(k);
}
}
}
for (p, n) in path_iter.clone().zip(path_iter.skip(1)) {
self.add_wire(power_pole_map[&n], 5, power_pole_map[&p], 5);
}
let last_node = path.last().unwrap().unwrap();
let dist = match last_node.electric_pole_type {
ElectricPoleType::Small => 7,
ElectricPoleType::Medium => 9,
ElectricPoleType::Big => 6,
ElectricPoleType::Substation => todo!(),
};
let r = roboportmap
.iter()
.position(|r| {
r.x.abs_diff(last_node.pos.x) <= dist
&& r.y.abs_diff(last_node.pos.y) <= dist
})
.unwrap();
let p = roboportmap.swap_remove(r);
visited_roboports.push(p);
} else {
panic!("No path found");
}
}
}
}

View file

@ -1,3 +1,5 @@
use std::collections::HashMap;
use factorio_core::{misc::PositionMap, prelude::Position}; use factorio_core::{misc::PositionMap, prelude::Position};
use factorio_graph::{ use factorio_graph::{
graph::Graph, graph::Graph,
@ -7,7 +9,7 @@ use factorio_graph::{
use crate::abstraction::Entity; use crate::abstraction::Entity;
use super::Blueprint; use super::{Blueprint, EntityType};
struct RoboportGraph<'a> { struct RoboportGraph<'a> {
roboports: &'a [Position], roboports: &'a [Position],
@ -60,7 +62,6 @@ impl Blueprint {
} }
} }
dbg!(universe, sets.len());
let res = greedy_connected_set_cover_priority_queue::<_, _, FastBinaryHeap<_>>( let res = greedy_connected_set_cover_priority_queue::<_, _, FastBinaryHeap<_>>(
universe, universe,
&sets, &sets,
@ -70,7 +71,11 @@ impl Blueprint {
); );
for r in res { for r in res {
if self.placeable(roboports[r], Position::new(8, 8)) {
self.add_entity(Entity::new_roboport(roboports[r])); self.add_entity(Entity::new_roboport(roboports[r]));
} else {
panic!("Roboport not placeable");
}
} }
} }
} }

View file

@ -89,6 +89,10 @@ impl Color {
Self::new(0x0f, 0xf0, 0xfc) Self::new(0x0f, 0xf0, 0xfc)
} }
pub fn yellow() -> Self {
Self::new(0xff, 0xff, 0x00)
}
pub fn gray(l: u8) -> Self { pub fn gray(l: u8) -> Self {
Self::new(l, l, l) Self::new(l, l, l)
} }