diff --git a/src/bin/station.rs b/src/bin/station.rs index 8df3c25..eb044f2 100644 --- a/src/bin/station.rs +++ b/src/bin/station.rs @@ -1,30 +1,135 @@ -use clap::Parser; +use clap::{Parser, Subcommand}; use factorio_blueprint::blueprint::{ - belt::Beltspeed, station::basic_unload_station, BlueprintString, + belt::{Beltspeed, Belttype}, + station::{basic_unload_station, station_unload}, + BlueprintBook, BlueprintBookEntry, BlueprintString, }; #[derive(Parser)] struct Args { - locomotives: usize, - length: usize, - outputs: usize, - beltspeed: Beltspeed, + #[command(subcommand)] + command: Command, +} + +#[derive(Subcommand)] +enum Command { + Book, + Single { + locomotives: usize, + length: usize, + outputs: usize, + beltspeed: Beltspeed, + #[arg(default_value = "full")] + belttype: Belttype, + }, } fn main() { let args = Args::parse(); - let b = BlueprintString::Blueprint(basic_unload_station( - args.locomotives, - args.length, - args.outputs, - args.beltspeed, - )); + match args.command { + Command::Book => { + let mut b = Vec::new(); - println!("{}", serde_json::to_string_pretty(&b).unwrap()); + let layouts = [ + (1, 1), + (1, 2), + (1, 4), + (2, 4), + (1, 8), + (2, 8), + (3, 8), + (4, 8), + ]; - println!( - "{}", - factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap()) - ); + for (i, (locomotives, cargo)) in layouts.into_iter().enumerate() { + let mut inner_b = Vec::new(); + + let mut j = 0; + for beltspeed in [ + Beltspeed::Normal, + Beltspeed::Fast, + Beltspeed::Express, + Beltspeed::Turbo, + ] { + let belttypes: &[_] = match beltspeed { + Beltspeed::Normal => &[Belttype::Full, Belttype::Left, Belttype::Right], + _ => &[Belttype::Full], + }; + for &belttype in belttypes { + let mut inner_inner_b = Vec::new(); + + for (l, o) in (0..=(cargo as u32).ilog2()).enumerate() { + let o = 1 << o; + + let blueprint = + basic_unload_station(locomotives, cargo, o, beltspeed, belttype); + + inner_inner_b.push(BlueprintBookEntry::new( + BlueprintString::Blueprint(blueprint), + l as u32, + )); + } + + inner_b.push(BlueprintBookEntry::new( + BlueprintString::BlueprintBook( + BlueprintBook::builder() + .blueprints(inner_inner_b) + .active_index(0) + .label(format!("{:?}-{:?}", beltspeed, belttype)) + .build(), + ), + j, + )); + j += 1; + } + } + + b.push(BlueprintBookEntry::new( + BlueprintString::BlueprintBook( + BlueprintBook::builder() + .blueprints(inner_b) + .active_index(0) + .label(format!("{locomotives}-{cargo}")) + .build(), + ), + i as u32, + )); + } + + let b = BlueprintString::BlueprintBook( + BlueprintBook::builder() + .blueprints(b) + .active_index(0) + .build(), + ); + + println!( + "{}", + factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap()) + ); + } + Command::Single { + locomotives, + length, + outputs, + beltspeed, + belttype, + } => { + let b = BlueprintString::Blueprint(basic_unload_station( + locomotives, + length, + outputs, + beltspeed, + belttype, + )); + + // println!("{}", serde_json::to_string_pretty(&b).unwrap()); + + println!( + "{}", + factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap()) + ); + } + } } diff --git a/src/blueprint/belt.rs b/src/blueprint/belt.rs index 6a26c79..1b8f6e2 100644 --- a/src/blueprint/belt.rs +++ b/src/blueprint/belt.rs @@ -61,6 +61,30 @@ impl Beltspeed { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] +pub enum Belttype { + Full, + Left, + Right, +} + +impl Belttype { + pub fn contains_left(self) -> bool { + match self { + Belttype::Full => true, + Belttype::Left => true, + Belttype::Right => false, + } + } + pub fn contains_right(self) -> bool { + match self { + Belttype::Full => true, + Belttype::Left => false, + Belttype::Right => true, + } + } +} + pub fn convert_belt_to_blueprint( belt: &PathField, speed: &Beltspeed, diff --git a/src/blueprint/station.rs b/src/blueprint/station.rs index 6a7b7c5..753cb96 100644 --- a/src/blueprint/station.rs +++ b/src/blueprint/station.rs @@ -1,6 +1,9 @@ use std::sync::Arc; -use super::{belt::Beltspeed, Blueprint, BlueprintEntity, BlueprintPosition}; +use super::{ + belt::{Beltspeed, Belttype}, + Blueprint, BlueprintEntity, BlueprintPosition, +}; pub fn station_unload( length: usize, @@ -171,118 +174,356 @@ pub fn station_unload( .build() } +pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Vec, f64) { + match beltspeed { + Beltspeed::Normal => { + let mut e = vec![BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + 0, + BlueprintPosition::new(3.5, -1.5), + ) + .build()]; + + if belttype.contains_left() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(5.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(5.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(4.5, -1.5), + ) + .direction(4) + .build(), + ]); + } + + if belttype.contains_right() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(1.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(1.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(2.5, -1.5), + ) + .direction(12) + .build(), + ]); + } + + (e, -2.5) + } + Beltspeed::Fast => { + let mut e = vec![BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + 0, + BlueprintPosition::new(3.5, -3.5), + ) + .build()]; + + if belttype.contains_left() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(1.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(1.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(1.5, -2.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + offset + 3, + BlueprintPosition::new(1.5, -3.5), + ) + .direction(4) + .build(), + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset + 4, + BlueprintPosition::new(2.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 5, + BlueprintPosition::new(2.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 6, + BlueprintPosition::new(2.5, -2.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + offset + 7, + BlueprintPosition::new(2.5, -3.5), + ) + .direction(4) + .build(), + ]); + } + + if belttype.contains_right() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(4.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(4.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(4.5, -2.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + offset + 3, + BlueprintPosition::new(4.5, -3.5), + ) + .direction(12) + .build(), + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset + 4, + BlueprintPosition::new(5.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 5, + BlueprintPosition::new(5.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-inserter".to_owned(), + offset + 6, + BlueprintPosition::new(5.5, -2.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "fast-transport-belt".to_owned(), + offset + 7, + BlueprintPosition::new(5.5, -3.5), + ) + .direction(12) + .build(), + ]); + } + + (e, -4.5) + } + Beltspeed::Express => { + let mut e = vec![BlueprintEntity::builder( + "express-transport-belt".to_owned(), + 0, + BlueprintPosition::new(3.5, -3.5), + ) + .build()]; + + if belttype.contains_left() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(1.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(1.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(1.5, -2.5), + ) + .direction(8) + .override_stack_size(8) + .build(), + BlueprintEntity::builder( + "express-transport-belt".to_owned(), + offset + 3, + BlueprintPosition::new(1.5, -3.5), + ) + .direction(4) + .build(), + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset + 4, + BlueprintPosition::new(2.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 5, + BlueprintPosition::new(2.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 6, + BlueprintPosition::new(2.5, -2.5), + ) + .direction(8) + .override_stack_size(8) + .build(), + BlueprintEntity::builder( + "express-transport-belt".to_owned(), + offset + 7, + BlueprintPosition::new(2.5, -3.5), + ) + .direction(4) + .build(), + ]); + } + + if belttype.contains_right() { + let offset = e.len() as u32; + e.extend_from_slice(&[ + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset, + BlueprintPosition::new(4.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 1, + BlueprintPosition::new(4.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 2, + BlueprintPosition::new(4.5, -2.5), + ) + .direction(8) + .override_stack_size(8) + .build(), + BlueprintEntity::builder( + "express-transport-belt".to_owned(), + offset + 3, + BlueprintPosition::new(4.5, -3.5), + ) + .direction(12) + .build(), + BlueprintEntity::builder( + "steel-chest".to_owned(), + offset + 4, + BlueprintPosition::new(5.5, -1.5), + ) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 5, + BlueprintPosition::new(5.5, -0.5), + ) + .direction(8) + .build(), + BlueprintEntity::builder( + "bulk-inserter".to_owned(), + offset + 6, + BlueprintPosition::new(5.5, -2.5), + ) + .direction(8) + .override_stack_size(8) + .build(), + BlueprintEntity::builder( + "express-transport-belt".to_owned(), + offset + 7, + BlueprintPosition::new(5.5, -3.5), + ) + .direction(12) + .build(), + ]); + } + + (e, -4.5) + } + Beltspeed::Turbo => (Vec::new(), -4.5), + } +} + pub fn basic_unload_station( locomotives: usize, length: usize, outputs: usize, beltspeed: Beltspeed, + belttype: Belttype, ) -> Blueprint { - let top = vec![ - BlueprintEntity::builder( - "steel-chest".to_owned(), - 0, - BlueprintPosition::new(1.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 1, - BlueprintPosition::new(1.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - 2, - BlueprintPosition::new(2.5, -1.5), - ) - .direction(12) - .build(), - BlueprintEntity::builder( - "fast-transport-belt".to_owned(), - 3, - BlueprintPosition::new(3.5, -1.5), - ) - .build(), - ]; - - let bottom = vec![ - BlueprintEntity::builder( - "steel-chest".to_owned(), - 0, - BlueprintPosition::new(1.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 1, - BlueprintPosition::new(1.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - 2, - BlueprintPosition::new(2.5, -1.5), - ) - .direction(12) - .build(), - BlueprintEntity::builder( - "fast-transport-belt".to_owned(), - 3, - BlueprintPosition::new(3.5, -1.5), - ) - .build(), - ]; - - let full = vec![ - BlueprintEntity::builder( - "steel-chest".to_owned(), - 0, - BlueprintPosition::new(1.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 1, - BlueprintPosition::new(1.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - 2, - BlueprintPosition::new(2.5, -1.5), - ) - .direction(12) - .build(), - BlueprintEntity::builder( - "steel-chest".to_owned(), - 0, - BlueprintPosition::new(5.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 1, - BlueprintPosition::new(5.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - 2, - BlueprintPosition::new(4.5, -1.5), - ) - .direction(4) - .build(), - BlueprintEntity::builder( - "fast-transport-belt".to_owned(), - 3, - BlueprintPosition::new(3.5, -1.5), - ) - .build(), - ]; - - station_unload(length, locomotives, &full, beltspeed, outputs, 3.5, -2.5) + let (unloader, output_y) = unloader( + beltspeed.halvings((length / outputs).ilog2() as usize), + belttype, + ); + station_unload( + length, + locomotives, + &unloader, + beltspeed, + outputs, + 3.5, + output_y, + ) }