diff --git a/factorio-blueprint-generator/src/balancer.rs b/factorio-blueprint-generator/src/balancer.rs index e5abf42..d53a6e8 100644 --- a/factorio-blueprint-generator/src/balancer.rs +++ b/factorio-blueprint-generator/src/balancer.rs @@ -1,125 +1,108 @@ -use factorio_blueprint::{ - Blueprint, BlueprintEntity, BlueprintPosition, - abstraction::{self, Entity}, - belt::convert_to_blueprint, -}; +use factorio_blueprint::abstraction::{Blueprint, Entity}; use factorio_core::{beltoptions::Beltspeed, pathfield::PathField, prelude::*}; fn balancer_path() -> Vec { vec![ PathField::Belt { - pos: Position::new(0, 1), - dir: Direction::Up, - }, - PathField::Belt { - pos: Position::new(3, 1), - dir: Direction::Up, - }, - PathField::Belt { - pos: Position::new(0, 2), - dir: Direction::Up, - }, - PathField::Belt { - pos: Position::new(3, 2), - dir: Direction::Up, - }, - PathField::Belt { - pos: Position::new(0, 3), - dir: Direction::Up, + pos: Position::new(1, 0), + dir: Direction::Right, }, PathField::Belt { pos: Position::new(1, 3), - dir: Direction::Left, + dir: Direction::Right, + }, + PathField::Belt { + pos: Position::new(2, 0), + dir: Direction::Right, }, PathField::Belt { pos: Position::new(2, 3), dir: Direction::Right, }, + PathField::Belt { + pos: Position::new(3, 0), + dir: Direction::Down, + }, + PathField::Belt { + pos: Position::new(3, 1), + dir: Direction::Right, + }, + PathField::Belt { + pos: Position::new(3, 2), + dir: Direction::Right, + }, PathField::Belt { pos: Position::new(3, 3), dir: Direction::Up, }, PathField::Belt { - pos: Position::new(0, 5), + pos: Position::new(5, 0), dir: Direction::Right, }, PathField::Belt { - pos: Position::new(1, 5), + pos: Position::new(5, 1), dir: Direction::Up, }, PathField::Belt { - pos: Position::new(2, 5), - dir: Direction::Up, + pos: Position::new(5, 2), + dir: Direction::Down, }, PathField::Belt { - pos: Position::new(3, 5), - dir: Direction::Left, + pos: Position::new(5, 3), + dir: Direction::Right, }, PathField::Belt { - pos: Position::new(0, 6), - dir: Direction::Up, + pos: Position::new(6, 0), + dir: Direction::Right, }, PathField::Belt { - pos: Position::new(3, 6), - dir: Direction::Up, + pos: Position::new(6, 3), + dir: Direction::Right, }, PathField::Underground { - pos: Position::new(1, 6), - dir: Direction::Up, + pos: Position::new(2, 1), + dir: Direction::Right, len: 4, }, PathField::Underground { - pos: Position::new(2, 6), - dir: Direction::Up, + pos: Position::new(2, 2), + dir: Direction::Right, len: 4, }, ] } -pub fn generate_4_lane_balancer2() -> Blueprint { - let mut b = abstraction::Blueprint::new(); +pub fn generate_4_lane_balancer(beltspeed: Beltspeed) -> Blueprint { + let mut b = Blueprint::new(); - let splitter_pos = [(2, 1), (6, 1), (4, 3), (4, 9), (2, 15), (6, 15)]; + let splitter_pos = [(1, 2), (1, 6), (3, 4), (9, 4), (15, 2), (15, 6)]; for (x, y) in splitter_pos { b.add_entity(Entity::new_splitter( - Beltspeed::Normal, + beltspeed, Position::new(x, y), - Direction::Up, + Direction::Right, )); } - b.add_path(&balancer_path(), Beltspeed::Normal); + b.add_path(&balancer_path(), beltspeed); - // b.transform(Transformation::new(Direction::Right, Position::new(0, 0))); - b.to_blueprint() + b } -pub fn generate_4_lane_balancer() -> Blueprint { - let mut e = vec![ - BlueprintEntity::builder("splitter".to_owned(), 1, BlueprintPosition::new(1.0, 0.5)) - .build(), - BlueprintEntity::builder("splitter".to_owned(), 2, BlueprintPosition::new(3.0, 0.5)) - .build(), - BlueprintEntity::builder("splitter".to_owned(), 3, BlueprintPosition::new(2.0, 1.5)) - .build(), - BlueprintEntity::builder("splitter".to_owned(), 11, BlueprintPosition::new(2.0, 4.5)) - .build(), - BlueprintEntity::builder("splitter".to_owned(), 20, BlueprintPosition::new(1.0, 7.5)) - .build(), - BlueprintEntity::builder("splitter".to_owned(), 21, BlueprintPosition::new(3.0, 7.5)) - .build(), - ]; +pub fn binary_balancer(lanes: usize, beltspeed: Beltspeed) -> (PositionType, Blueprint) { + match lanes { + 4 => (16, generate_4_lane_balancer(beltspeed)), + 2 => { + let mut b = Blueprint::new(); + b.add_entity(Entity::new_splitter( + beltspeed, + Position::new(1, 2), + Direction::Right, + )); - let mut nextfree = e.len() as u32; - e.extend(convert_to_blueprint( - &balancer_path(), - &Beltspeed::Normal, - &mut nextfree, - )); - - Blueprint::builder() - .label("balancer".to_string()) - .entities(e) - .build() + (2, b) + } + _ => (0, Blueprint::new()), + } } diff --git a/factorio-blueprint-generator/src/bin/balancer_blueprint.rs b/factorio-blueprint-generator/src/bin/balancer_blueprint.rs index 92195ef..5e4ace4 100644 --- a/factorio-blueprint-generator/src/bin/balancer_blueprint.rs +++ b/factorio-blueprint-generator/src/bin/balancer_blueprint.rs @@ -1,13 +1,27 @@ -use factorio_blueprint::{BlueprintString, encode}; -use factorio_blueprint_generator::balancer::{generate_4_lane_balancer, generate_4_lane_balancer2}; +use factorio_blueprint::{BlueprintBook, BlueprintBookEntry, BlueprintString, encode}; +use factorio_blueprint_generator::balancer::{binary_balancer, generate_4_lane_balancer}; fn main() { - let b = BlueprintString::Blueprint(generate_4_lane_balancer()); - let b2 = BlueprintString::Blueprint(generate_4_lane_balancer2()); + let mut v = Vec::new(); + + for i in 0..3 { + let lanes = 1 << i; + + let (_, b) = binary_balancer(lanes, factorio_core::beltoptions::Beltspeed::Normal); + + v.push(BlueprintBookEntry::new( + BlueprintString::Blueprint(b.to_blueprint()), + i + 1, + )); + } + let b = BlueprintString::BlueprintBook( + BlueprintBook::builder() + .blueprints(v) + .active_index(1) + .build(), + ); println!("{}", serde_json::to_string_pretty(&b).unwrap()); - println!("{}", serde_json::to_string_pretty(&b2).unwrap()); println!("{}", encode(&serde_json::to_string(&b).unwrap())); - println!("{}", encode(&serde_json::to_string(&b2).unwrap())); } diff --git a/factorio-blueprint-generator/src/bin/multistation.rs b/factorio-blueprint-generator/src/bin/multistation.rs index 25ef146..7f84724 100644 --- a/factorio-blueprint-generator/src/bin/multistation.rs +++ b/factorio-blueprint-generator/src/bin/multistation.rs @@ -12,63 +12,77 @@ struct Args { fn main() { let args = Args::parse(); - // let stations: Vec<_> = (0..2) - // .map(|_| StationSpec { - // locomotives: 1, - // wagons: 2, - // load: false, - // beltspeed: Beltspeed::Turbo, - // lanes: 2, - // }) - // .collect(); + let stations: Vec<_> = [false, true] + .into_iter() + .flat_map(|load| { + [ + Beltspeed::Normal, + Beltspeed::Fast, + Beltspeed::Express, + Beltspeed::Turbo, + ] + .into_iter() + .flat_map(move |beltspeed| { + (0..6).flat_map(move |i| { + (0..=i).map(move |j| StationSpec { + locomotives: 1, + wagons: 1 << i, + load, + beltspeed, + lanes: 1 << j, + }) + }) + }) + }) + .collect(); let b = BlueprintString::Blueprint( multistation( - // &stations, - &[ - StationSpec { - locomotives: 2, - wagons: 4, - load: false, - beltspeed: Beltspeed::Normal, - lanes: 4, - }, - StationSpec { - locomotives: 3, - wagons: 8, - load: false, - beltspeed: Beltspeed::Turbo, - lanes: 8, - }, - StationSpec { - locomotives: 3, - wagons: 8, - load: false, - beltspeed: Beltspeed::Turbo, - lanes: 4, - }, - StationSpec { - locomotives: 3, - wagons: 8, - load: false, - beltspeed: Beltspeed::Turbo, - lanes: 2, - }, - StationSpec { - locomotives: 3, - wagons: 8, - load: false, - beltspeed: Beltspeed::Turbo, - lanes: 1, - }, - StationSpec { - locomotives: 1, - wagons: 1, - load: false, - beltspeed: Beltspeed::Turbo, - lanes: 1, - }, - ], + &stations, + // &[ + // StationSpec { + // locomotives: 2, + // wagons: 4, + // load: false, + // beltspeed: Beltspeed::Normal, + // lanes: 4, + // }, + // StationSpec { + // locomotives: 3, + // wagons: 8, + // load: false, + // beltspeed: Beltspeed::Turbo, + // lanes: 8, + // }, + // StationSpec { + // locomotives: 3, + // wagons: 8, + // load: false, + // beltspeed: Beltspeed::Turbo, + // lanes: 4, + // }, + // StationSpec { + // locomotives: 3, + // wagons: 8, + // load: false, + // beltspeed: Beltspeed::Turbo, + // lanes: 2, + // }, + // StationSpec { + // locomotives: 3, + // wagons: 8, + // load: false, + // beltspeed: Beltspeed::Turbo, + // lanes: 1, + // }, + // StationSpec { + // locomotives: 1, + // wagons: 1, + // load: false, + // beltspeed: Beltspeed::Turbo, + // lanes: 1, + // }, + // ], 8, ) .to_blueprint(), diff --git a/factorio-blueprint-generator/src/multistation.rs b/factorio-blueprint-generator/src/multistation.rs index 2c08db7..bd4982c 100644 --- a/factorio-blueprint-generator/src/multistation.rs +++ b/factorio-blueprint-generator/src/multistation.rs @@ -1,7 +1,7 @@ -use factorio_blueprint::abstraction::{Blueprint, Entity, EntityType, RailType}; +use factorio_blueprint::abstraction::{Blueprint, Entity, EntityType, RailType, UndergroundType}; use factorio_core::{beltoptions::Beltspeed, prelude::*}; -use crate::station::basic_station; +use crate::{balancer::binary_balancer, station::basic_station}; pub struct StationSpec { pub locomotives: usize, @@ -11,6 +11,35 @@ pub struct StationSpec { pub lanes: usize, } +fn calculate_station_height( + output_height: PositionType, + lanes: usize, + beltspeed: Beltspeed, +) -> PositionType { + let station_height = match beltspeed { + Beltspeed::Normal => { + if lanes == 1 && output_height % 4 == 1 { + 4 + ((3 + output_height) & !0b11) + } else { + 4 + ((15 + output_height) & !0b11) + } + } + Beltspeed::Fast => { + if lanes == 1 || lanes == 2 && output_height % 4 == 3 { + 4 + ((3 + output_height) & !0b11) + } else { + 4 + ((9 + output_height) & !0b11) + } + } + Beltspeed::Express | Beltspeed::Turbo => 4 + ((3 + output_height) & !0b11), + }; + + let station_height = PositionType::max(12, station_height); + assert!(station_height % 4 == 0); + + station_height +} + pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint { let longest_train = stations .iter() @@ -215,6 +244,7 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint )); } + // station let mut b = basic_station( station.load, station.locomotives, @@ -223,9 +253,7 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint station.beltspeed, factorio_core::beltoptions::Belttype::Full, ); - - let station_height = PositionType::max(12, 4 + ((3 - b.bounding_box().min().y) / 4) * 4); - assert!(station_height % 4 == 0); + let output_height = -b.bounding_box().min().y; b.transform(Transformation::new( Direction::Down, @@ -237,6 +265,263 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint blueprint.add_blueprint(b); + // belt output + let station_height = + calculate_station_height(output_height, station.lanes, station.beltspeed); + + // rail crossing + let (beltdirection, underground_left, underground_right) = match station.load { + true => ( + Direction::Left, + UndergroundType::Output, + UndergroundType::Input, + ), + false => ( + Direction::Right, + UndergroundType::Input, + UndergroundType::Output, + ), + }; + let mut belt_x = outrail_x - 28 - 14 * station.locomotives as PositionType - 3 + + 2 * (station.wagons / station.lanes).ilog2() as PositionType; + + let (balancer_length, mut b) = binary_balancer(station.lanes, station.beltspeed); + + if station.load { + b.transform(Transformation::new( + Direction::Down, + Position::new(balancer_length, 2 * station.lanes as PositionType), + )); + } + + b.transform(Transformation::new( + Direction::Up, + Position::new( + belt_x - 1, + 31 + total_stacker_height + previous_station_heights + output_height + - 2 * station.lanes as PositionType, + ), + )); + + blueprint.add_blueprint(b); + + belt_x += balancer_length; + + for j in 0..station.lanes { + let (underground_x, signal) = match station_height + - (output_height - 2 * j as PositionType) + { + 5 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 23, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_right, + Position::new( + outrail_x - 9, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 7, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 23, false) + } + 7 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 17, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + if station.beltspeed != Beltspeed::Turbo { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_right, + Position::new( + outrail_x - 7, + 30 + total_stacker_height + + previous_station_heights + + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 5, + 30 + total_stacker_height + + previous_station_heights + + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + } + (outrail_x - 17, false) + } + 9 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 15, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 15, false) + } + 11 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 11, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 11, false) + } + 13 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 9, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 9, false) + } + 15 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 9, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 9, true) + } + 17 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 7, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 7, false) + } + 19 | 21 | 23 => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 5, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 5, false) + } + _ => { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_left, + Position::new( + outrail_x - 3, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + (outrail_x - 3, false) + } + }; + + if signal { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_right, + Position::new( + outrail_x + 5, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + } else { + blueprint.add_entity(Entity::new_underground_belt( + station.beltspeed, + underground_right, + Position::new( + outrail_x + 3, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + blueprint.add_entity(Entity::new_belt( + station.beltspeed, + Position::new( + outrail_x + 5, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + } + + for l in 0..((underground_x - belt_x) / 2) { + blueprint.add_entity(Entity::new_belt( + station.beltspeed, + Position::new( + belt_x + 2 * l, + 30 + total_stacker_height + previous_station_heights + output_height + - 2 * j as PositionType, + ), + beltdirection, + )); + } + } + // rail connection if i != stations.len() - 1 { for j in 0..(station_height / 4) { @@ -262,7 +547,7 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint RailType::ChainSignal, Position::new( inrail_x - 3, - total_stacker_height + 13 + previous_station_heights, + total_stacker_height + 15 + previous_station_heights, ), 0, )); @@ -270,7 +555,7 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint RailType::RailSignal, Position::new( outrail_x + 3, - total_stacker_height + 13 + previous_station_heights, + total_stacker_height + 15 + previous_station_heights, ), 8, ));