Improve factory generation

This commit is contained in:
hal8174 2025-02-03 22:59:37 +01:00
parent 0f8bf5000c
commit ec869d4c18
7 changed files with 107 additions and 46 deletions

View file

@ -1,49 +1,58 @@
subfactories: subfactories:
- !SubFactory - !SubFactory
recipe: iron-gear-wheel recipe: iron-gear-wheel
machines: 2 machines: 6
machine: assembly-machine-3 machine: assembly-machine-3
- !SubFactory - !SubFactory
recipe: copper-cable recipe: copper-cable
machines: 3 machines: 9
machine: assembly-machine-3 machine: assembly-machine-3
- !SubFactory - !SubFactory
recipe: electronic-circuit recipe: electronic-circuit
machines: 2 machines: 6
machine: assembly-machine-3 machine: assembly-machine-3
- !SubFactory - !SubFactory
recipe: inserter recipe: inserter
machines: 2 machines: 6
machine: assembly-machine-3 machine: assembly-machine-3
- !ExternalConnection - !ExternalConnection
inputs: 1 inputs: 1
outputs: 5 outputs: 5
- !SideLoader
factory_connections: factory_connections:
- item: iron-gear-wheel - item: iron-gear-wheel
amount: 5
from: 0
to: 3
- item: copper-cable
amount: 15 amount: 15
from: 0
to: 5
- item: copper-cable
amount: 45
from: 1 from: 1
to: 2 to: 2
- item: electronic-circuit
amount: 5
from: 2
to: 3
- item: iron-plate - item: iron-plate
amount: 10 amount: 30
from: 4 from: 4
to: 0 to: 0
- item: iron-plate - item: iron-plate
amount: 5 amount: 15
from: 4 from: 4
to: 2 to: 2
- item: copper-plate - item: copper-plate
amount: 7.5 amount: 22.5
from: 4 from: 4
to: 1 to: 1
- item: inserter - item: inserter
amount: 5 amount: 15
from: 3 from: 3
to: 4 to: 4
- item: iron-plate
amount: 15
from: 4
to: 5
- item: iron-plate;iron-gear-wheel
amount: 30
from: 5
to: 3
- item: electronic-circuit
amount: 15
from: 2
to: 3

View file

@ -415,7 +415,8 @@ pub fn assembly_line_2_input(
Direction::Right, Direction::Right,
)); ));
} }
if i < (3 * halve_machines - 1) { if i < (3 * halve_machines - 2) || (halve_machines % 3 == 1 && i < (3 * halve_machines - 1))
{
blueprint.add_entity(Entity::new_belt( blueprint.add_entity(Entity::new_belt(
output_belt, output_belt,
Position::new(1 + 2 * i as PositionType, 15), Position::new(1 + 2 * i as PositionType, 15),

View file

@ -29,16 +29,16 @@ fn main() {
let l = ValidLayout { let l = ValidLayout {
max_tries: 10, max_tries: 10,
retries: 20, retries: 20,
start_size: Position::new(20, 20), start_size: Position::new(48, 48),
growth: Position::new(5, 5), growth: Position::new(0, 0),
}; };
let l = GeneticAlgorithm { let l = GeneticAlgorithm {
mutation_retries: 20, mutation_retries: 20,
population_size: 10, population_size: 20,
population_keep: 2, population_keep: 1,
population_new: 2, population_new: 2,
generations: 20, generations: 50,
valid_layout: l, valid_layout: l,
}; };
let p = ConflictAvoidance { let p = ConflictAvoidance {

View file

@ -1,4 +1,4 @@
use factorio_blueprint::abstraction::Blueprint; use factorio_blueprint::abstraction::{Blueprint, Entity};
use factorio_core::{beltoptions::Beltspeed, prelude::*}; use factorio_core::{beltoptions::Beltspeed, prelude::*};
use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock}; use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
use factorio_pathfinding::Pathfinder; use factorio_pathfinding::Pathfinder;
@ -25,6 +25,7 @@ pub enum Building {
outputs: usize, outputs: usize,
}, },
BeltPool, BeltPool,
SideLoader,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
@ -46,7 +47,7 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
let mut connections = Vec::new(); let mut connections = Vec::new();
let mut used_connections = Vec::new(); let mut used_connections = Vec::new();
for b in &factory_graph.subfactories { for (i, b) in factory_graph.subfactories.iter().enumerate() {
match b { match b {
Building::SubFactory { Building::SubFactory {
recipe, recipe,
@ -55,12 +56,22 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
} => { } => {
assert!(machine == "assembly-machine-3"); assert!(machine == "assembly-machine-3");
let input_count = factory_graph
.factory_connections
.iter()
.filter(|&c| c.to == i)
.count();
let (b, size, y_output, y_inputs) = assembly_line_2_input( let (b, size, y_output, y_inputs) = assembly_line_2_input(
*machines, *machines,
recipe, recipe,
Beltspeed::Normal, Beltspeed::Express,
Some(Beltspeed::Normal), if input_count == 2 {
Beltspeed::Normal, Some(Beltspeed::Express)
} else {
None
},
Beltspeed::Express,
); );
blueprints.push(b); blueprints.push(b);
@ -101,6 +112,34 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
blueprints.push(Blueprint::new()); blueprints.push(Blueprint::new());
used_connections.push((0, 0)); used_connections.push((0, 0));
} }
Building::SideLoader => {
let mut blueprint = Blueprint::new();
blueprint.add_entity(Entity::new_belt(
Beltspeed::Fast,
Position::new(1, 1),
Direction::Up,
));
blocks.push(MacroBlock {
size: Position::new(1, 1),
input: vec![
Interface {
offset: Position::new(0, 0),
dir: Direction::Right,
},
Interface {
offset: Position::new(0, 0),
dir: Direction::Left,
},
],
output: vec![Interface {
offset: Position::new(0, 0),
dir: Direction::Up,
}],
});
blueprints.push(blueprint);
used_connections.push((0, 0));
}
Building::BeltPool => todo!(), Building::BeltPool => todo!(),
} }
} }
@ -112,7 +151,7 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
endblock: c.to, endblock: c.to,
endpoint: used_connections[c.to].1, endpoint: used_connections[c.to].1,
lanes: 1, lanes: 1,
beltspeed: Beltspeed::Normal, beltspeed: Beltspeed::from_items_per_second(c.amount),
}); });
used_connections[c.from].0 += 1; used_connections[c.from].0 += 1;
@ -122,16 +161,11 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
// dbg!(&blocks); // dbg!(&blocks);
// dbg!(&connections); // dbg!(&connections);
let l = layouter let layout_input = LayoutInput {
.layout( blocks,
&LayoutInput { connections,
blocks, };
connections, let l = layouter.layout(&layout_input, pathfinder, rng).unwrap();
},
pathfinder,
rng,
)
.unwrap();
let mut b = Blueprint::new(); let mut b = Blueprint::new();
for (block, mut assembly_blueprint) in l.positions.iter().zip(blueprints) { for (block, mut assembly_blueprint) in l.positions.iter().zip(blueprints) {
@ -146,8 +180,8 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
b.add_blueprint(assembly_blueprint); b.add_blueprint(assembly_blueprint);
} }
for path in &l.path_result { for (path, connection) in l.path_result.iter().zip(layout_input.connections.iter()) {
b.add_path(&path[1..], Beltspeed::Fast); b.add_path(&path[1..], connection.beltspeed);
} }
b b

View file

@ -56,6 +56,20 @@ impl Beltspeed {
} }
s s
} }
pub fn from_items_per_second(x: f64) -> Self {
if x <= 15.0 {
Beltspeed::Normal
} else if x <= 30.0 {
Beltspeed::Fast
} else if x <= 45.0 {
Beltspeed::Express
} else if x <= 60.0 {
Beltspeed::Turbo
} else {
unreachable!()
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)] #[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]

View file

@ -31,10 +31,11 @@ impl Layouter for GeneticAlgorithm {
} }
} }
} }
population.sort_by_key(|(_, s)| *s);
let mut best_result = population[0].clone();
for g in 0..self.generations { for g in 0..self.generations {
population.sort_by_key(|(_, s)| *s);
for i in 0..(self.population_size - self.population_keep - self.population_new) { for i in 0..(self.population_size - self.population_keep - self.population_new) {
loop { loop {
let parent = &population[i % self.population_keep].0; let parent = &population[i % self.population_keep].0;
@ -71,11 +72,13 @@ impl Layouter for GeneticAlgorithm {
} }
} }
population.sort_by_key(|(_, s)| *s);
if population[0].1 < best_result.1 {
best_result = population[0].clone();
}
println!("completed generation {g}\nscore: {}", population[0].1); println!("completed generation {g}\nscore: {}", population[0].1);
} }
population.sort_by_key(|(_, s)| *s); Some(best_result.0)
population.into_iter().next().map(|(l, _)| l)
} }
} }

View file

@ -38,7 +38,7 @@ pub struct LayoutInput {
pub connections: Vec<Connection>, pub connections: Vec<Connection>,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct LayoutResult { pub struct LayoutResult {
pub size: Position, pub size: Position,
pub positions: Vec<Block>, pub positions: Vec<Block>,