From aee56af22f83d53d981b8f0744c4e131d18ab786 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Mon, 31 Mar 2025 23:28:18 +0200 Subject: [PATCH] Add automatic distribution --- ...factory_graph_blue_science_distributor.yml | 141 +++++++++++++++ .../src/bin/generate_factory.rs | 2 +- factorio-blueprint-generator/src/factory.rs | 169 +++++++++++++++++- .../src/multistation.rs | 13 +- factorio-blueprint/src/abstraction.rs | 75 +++++++- 5 files changed, 386 insertions(+), 14 deletions(-) create mode 100644 factorio-blueprint-generator/factory_graph_blue_science_distributor.yml diff --git a/factorio-blueprint-generator/factory_graph_blue_science_distributor.yml b/factorio-blueprint-generator/factory_graph_blue_science_distributor.yml new file mode 100644 index 0000000..a33e31e --- /dev/null +++ b/factorio-blueprint-generator/factory_graph_blue_science_distributor.yml @@ -0,0 +1,141 @@ +subfactories: + - !SubFactory + recipe: chemical-science-pack + machines: 96 + machine: assembly-machine-3 + - !SubFactory + recipe: engine-unit + machines: 80 + machine: assembly-machine-3 + - !SubFactory + recipe: iron-gear-wheel + machines: 4 + machine: assembly-machine-3 + - !SubFactory + recipe: pipe + machines: 8 + machine: assembly-machine-3 + - !SubFactory + recipe: advanced-circuit + machines: 72 + machine: assembly-machine-3 + - !SubFactory + recipe: electronic-circuit + machines: 6 + machine: assembly-machine-3 + - !SubFactory + recipe: electronic-circuit + machines: 6 + machine: assembly-machine-3 + - !SubFactory + recipe: copper-cable + machines: 10 + machine: assembly-machine-3 + - !SubFactory + recipe: copper-cable + machines: 10 + machine: assembly-machine-3 + - !SubFactory + recipe: copper-cable + machines: 10 + machine: assembly-machine-3 + - !ExternalConnection + - !Distributor + - !Distributor +factory_connections: + - item: chemical-science-pack + amount: 10 + from: 0 + to: 10 + - item: engine-unit + amount: 10 + from: 1 + to: 0 + - item: advanced-circuit + amount: 15 + from: 4 + to: 0 + - item: sulfur + amount: 5 + from: 10 + to: 0 + - item: steel + amount: 10 + from: 10 + to: 1 + - item: iron-gear-wheel + amount: 10 + from: 2 + to: 1 + - item: pipe + amount: 20 + from: 3 + to: 1 + - item: iron-plate + amount: 20 + from: 10 + to: 2 + - item: iron-plate + amount: 20 + from: 10 + to: 3 + - item: electronic-circuit + amount: 30 + from: 12 + to: 4 + - item: electronic-circuit + amount: 15 + from: 5 + to: 12 + - item: electronic-circuit + amount: 15 + from: 6 + to: 12 + - item: plastic + amount: 30 + from: 10 + to: 4 + - item: iron-plate + amount: 15 + from: 10 + to: 5 + - item: iron-plate + amount: 15 + from: 10 + to: 6 + - item: copper-plate + amount: 25 + from: 10 + to: 7 + - item: copper-plate + amount: 25 + from: 10 + to: 8 + - item: copper-plate + amount: 25 + from: 10 + to: 9 + - item: copper-cable + amount: 45 + from: 11 + to: 5 + - item: copper-cable + amount: 60 + from: 11 + to: 4 + - item: copper-cable + amount: 50 + from: 7 + to: 11 + - item: copper-cable + amount: 50 + from: 8 + to: 11 + - item: copper-cable + amount: 45 + from: 11 + to: 6 + - item: copper-cable + amount: 50 + from: 9 + to: 11 diff --git a/factorio-blueprint-generator/src/bin/generate_factory.rs b/factorio-blueprint-generator/src/bin/generate_factory.rs index dff3778..8784b9c 100644 --- a/factorio-blueprint-generator/src/bin/generate_factory.rs +++ b/factorio-blueprint-generator/src/bin/generate_factory.rs @@ -30,7 +30,7 @@ struct Args { #[arg(short, long, default_value = "none")] tracing: Tracing, - #[arg(long, default_value = "ca-fbh")] + #[arg(long, default_value = "ca-bq")] pathfinder: PathfinderArg, } diff --git a/factorio-blueprint-generator/src/factory.rs b/factorio-blueprint-generator/src/factory.rs index 4e0b1ed..15a2f5c 100644 --- a/factorio-blueprint-generator/src/factory.rs +++ b/factorio-blueprint-generator/src/factory.rs @@ -1,3 +1,7 @@ +use crate::{ + assembly::assembly_line_2_input, + multistation::{StationSpec, multistation}, +}; use factorio_blueprint::abstraction::{Blueprint, Entity}; use factorio_core::{beltoptions::Beltspeed, prelude::*, visualize::Visualize}; use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock}; @@ -6,11 +10,6 @@ use rand::{Rng, SeedableRng}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::{ - assembly::assembly_line_2_input, - multistation::{StationSpec, multistation}, -}; - #[derive(Debug, Serialize, Deserialize, Clone)] pub struct FactoryGraph { pub subfactories: Vec, @@ -27,6 +26,7 @@ pub enum Building { ExternalConnection, Splitter, SideLoader, + Distributor, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -37,11 +37,13 @@ pub struct FactoryConnection { pub to: usize, } +#[derive(Debug)] struct IntermediateConnection { input: HashMap, output: HashMap, } +#[derive(Debug)] struct IntermediateConnectionEntry { block: Option, interface: usize, @@ -446,6 +448,163 @@ pub fn generate_factory>(), }); } + Building::Distributor => { + let mut blueprint = Blueprint::new(); + blueprint.add_entity(Entity::new_splitter_with_priority( + Beltspeed::from_items_per_second( + input_connections + .iter() + .chain(output_connections.iter()) + .map(|&(_, c)| c.amount) + .max_by(|x, y| x.partial_cmp(y).unwrap()) + .unwrap_or(1.0), + ), + Position::new(2, 1), + Direction::Up, + None, + Some(true), + )); + + let macro_block = MacroBlock { + size: Position::new(2, 1), + input: vec![ + Interface { + offset: Position::new(0, 0), + dir: Direction::Up, + }, + Interface { + offset: Position::new(1, 0), + dir: Direction::Up, + }, + ], + output: vec![ + Interface { + offset: Position::new(0, 0), + dir: Direction::Up, + }, + Interface { + offset: Position::new(1, 0), + dir: Direction::Up, + }, + ], + }; + + let mut output_index = 0; + let mut input_index = 1; + let mut amount = input_connections[0].1.amount; + + let mut intermediate_connections_input = HashMap::from([( + input_connections[0].0, + IntermediateConnectionEntry { + block: Some(block_index), + interface: 0, + }, + )]); + let mut intermediate_connections_output = HashMap::new(); + + loop { + while input_index < input_connections.len() + && amount + input_connections[input_index].1.amount + < output_connections[output_index].1.amount + { + if input_index > 1 || output_index > 0 { + connections.push(Connection { + startblock: Some(blocks.len() - 1), + startpoint: 1, + endblock: Some(blocks.len()), + endpoint: 0, + lanes: 1, + beltspeed: Beltspeed::Turbo, + }); + } + intermediate_connections_input.insert( + input_connections[input_index].0, + IntermediateConnectionEntry { + block: Some(blocks.len()), + interface: 1, + }, + ); + + blueprints.push(blueprint.clone()); + blocks.push(macro_block.clone()); + amount += input_connections[input_index].1.amount; + input_index += 1; + } + + if input_index > 1 || output_index > 0 { + connections.push(Connection { + startblock: Some(blocks.len() - 1), + startpoint: 1, + endblock: Some(blocks.len()), + endpoint: 0, + lanes: 1, + beltspeed: Beltspeed::Turbo, + }); + } + + if amount >= output_connections[output_index].1.amount { + intermediate_connections_output.insert( + output_connections[output_index].0, + IntermediateConnectionEntry { + block: Some(blocks.len()), + interface: 0, + }, + ); + + blueprints.push(blueprint.clone()); + blocks.push(macro_block.clone()); + } else { + intermediate_connections_output.insert( + output_connections[output_index].0, + IntermediateConnectionEntry { + block: Some(blocks.len()), + interface: 0, + }, + ); + intermediate_connections_input.insert( + input_connections[input_index].0, + IntermediateConnectionEntry { + block: Some(blocks.len()), + interface: 1, + }, + ); + + blueprints.push(blueprint.clone()); + blocks.push(macro_block.clone()); + amount += input_connections[input_index].1.amount; + input_index += 1; + } + amount -= output_connections[output_index].1.amount; + output_index += 1; + + if output_index >= output_connections.len() - 1 { + break; + } + } + + if output_connections.len() > 1 { + intermediate_connections_output.insert( + output_connections.last().unwrap().0, + IntermediateConnectionEntry { + block: Some(blocks.len() - 1), + interface: 1, + }, + ); + } + + // dbg!( + // &input_connections, + // &output_connections, + // &intermediate_connections_input, + // &intermediate_connections_output, + // amount, + // ); + + intermediate_connections.push(IntermediateConnection { + input: intermediate_connections_input, + output: intermediate_connections_output, + }); + } } } // dbg!(&intermediate_connections); diff --git a/factorio-blueprint-generator/src/multistation.rs b/factorio-blueprint-generator/src/multistation.rs index f7c66f9..11e03ab 100644 --- a/factorio-blueprint-generator/src/multistation.rs +++ b/factorio-blueprint-generator/src/multistation.rs @@ -1,7 +1,8 @@ -use factorio_blueprint::abstraction::{Blueprint, Entity, RailType, UndergroundType}; -use factorio_core::{beltoptions::Beltspeed, prelude::*}; - use crate::{balancer::binary_balancer, station::basic_station}; +use factorio_blueprint::abstraction::{ + Blueprint, ElectricPoleType, Entity, RailType, UndergroundType, +}; +use factorio_core::{beltoptions::Beltspeed, prelude::*}; pub struct StationSpec { pub locomotives: usize, @@ -52,6 +53,12 @@ pub fn multistation( let mut blueprint = Blueprint::new(); + // connection power pole + blueprint.add_entity(Entity::new_electric_pole( + ElectricPoleType::Big, + Position::new(32, 0), + )); + // stacker let stacker_length = (longest_train * 5).div_ceil(2); blueprint.add_entity(Entity::new_rail( diff --git a/factorio-blueprint/src/abstraction.rs b/factorio-blueprint/src/abstraction.rs index 98e9852..db9a56d 100644 --- a/factorio-blueprint/src/abstraction.rs +++ b/factorio-blueprint/src/abstraction.rs @@ -140,7 +140,11 @@ pub struct Entity { pub enum EntityType { Belt(Beltspeed), UndergroundBelt(Beltspeed, UndergroundType), - Splitter(Beltspeed), + Splitter { + beltspeed: Beltspeed, + input_priority_left: Option, + output_priority_left: Option, + }, ElectricPole(ElectricPoleType), Inserter { inserter_type: InserterType, @@ -203,9 +207,34 @@ impl Entity { } pub fn new_splitter(beltspeed: Beltspeed, position: Position, direction: Direction) -> Self { - Self::new(EntityType::Splitter(beltspeed), position, direction) + Self::new( + EntityType::Splitter { + beltspeed, + input_priority_left: None, + output_priority_left: None, + }, + position, + direction, + ) } + pub fn new_splitter_with_priority( + beltspeed: Beltspeed, + position: Position, + direction: Direction, + input_priority_left: Option, + output_priority_left: Option, + ) -> Self { + Self::new( + EntityType::Splitter { + beltspeed, + input_priority_left, + output_priority_left, + }, + position, + direction, + ) + } pub fn new_inserter( inserter_type: InserterType, override_stack_size: Option, @@ -288,7 +317,11 @@ impl Entity { EntityType::UndergroundBelt(beltspeed, _underground_type) => { beltspeed.string_underground() } - EntityType::Splitter(beltspeed) => beltspeed.string_splitter(), + EntityType::Splitter { + beltspeed, + input_priority_left: _, + output_priority_left: _, + } => beltspeed.string_splitter(), EntityType::Unknown { name, size: _, @@ -340,9 +373,38 @@ impl Entity { } } + pub fn get_maybe_input_priority(&self) -> Option { + match self.entity { + EntityType::Splitter { + beltspeed: _, + input_priority_left, + output_priority_left: _, + } => match input_priority_left { + Some(true) => Some("left".to_string()), + Some(false) => Some("right".to_string()), + None => None, + }, + _ => None, + } + } + + pub fn get_maybe_output_priority(&self) -> Option { + match self.entity { + EntityType::Splitter { + beltspeed: _, + input_priority_left: _, + output_priority_left, + } => match output_priority_left { + Some(true) => Some("left".to_string()), + Some(false) => Some("right".to_string()), + None => None, + }, + _ => None, + } + } pub fn size(&self) -> Position { match &self.entity { - EntityType::Splitter(_) => Position::new(4, 2), + EntityType::Splitter { .. } => Position::new(4, 2), EntityType::Unknown { name: _, size, @@ -416,7 +478,7 @@ impl Entity { ); } }, - EntityType::Splitter(_beltspeed) => (), + EntityType::Splitter { .. } => (), EntityType::ElectricPole(electric_pole_type) => match electric_pole_type { ElectricPoleType::Small => v.add_symbol( (self.position - Position::new(1, 1)) / 2 + offset, @@ -473,6 +535,7 @@ pub struct EntityKey(usize); static ENTITY_COUNTER: AtomicUsize = AtomicUsize::new(0); +#[derive(Clone)] pub struct Blueprint { entities: Vec<(EntityKey, Entity)>, keys: HashMap, @@ -566,6 +629,8 @@ impl Blueprint { .maybe_underground_type(e.get_maybe_underground_type_string()) .maybe_override_stack_size(e.get_maybe_override_stack_size()) .maybe_recipe(e.get_maybe_recipe()) + .maybe_input_priority(e.get_maybe_input_priority()) + .maybe_output_priority(e.get_maybe_output_priority()) .build() }) .collect();