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:
- !SubFactory
recipe: iron-gear-wheel
machines: 2
machines: 6
machine: assembly-machine-3
- !SubFactory
recipe: copper-cable
machines: 3
machines: 9
machine: assembly-machine-3
- !SubFactory
recipe: electronic-circuit
machines: 2
machines: 6
machine: assembly-machine-3
- !SubFactory
recipe: inserter
machines: 2
machines: 6
machine: assembly-machine-3
- !ExternalConnection
inputs: 1
outputs: 5
- !SideLoader
factory_connections:
- item: iron-gear-wheel
amount: 5
from: 0
to: 3
- item: copper-cable
amount: 15
from: 0
to: 5
- item: copper-cable
amount: 45
from: 1
to: 2
- item: electronic-circuit
amount: 5
from: 2
to: 3
- item: iron-plate
amount: 10
amount: 30
from: 4
to: 0
- item: iron-plate
amount: 5
amount: 15
from: 4
to: 2
- item: copper-plate
amount: 7.5
amount: 22.5
from: 4
to: 1
- item: inserter
amount: 5
amount: 15
from: 3
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,
));
}
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(
output_belt,
Position::new(1 + 2 * i as PositionType, 15),

View file

@ -29,16 +29,16 @@ fn main() {
let l = ValidLayout {
max_tries: 10,
retries: 20,
start_size: Position::new(20, 20),
growth: Position::new(5, 5),
start_size: Position::new(48, 48),
growth: Position::new(0, 0),
};
let l = GeneticAlgorithm {
mutation_retries: 20,
population_size: 10,
population_keep: 2,
population_size: 20,
population_keep: 1,
population_new: 2,
generations: 20,
generations: 50,
valid_layout: l,
};
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_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
use factorio_pathfinding::Pathfinder;
@ -25,6 +25,7 @@ pub enum Building {
outputs: usize,
},
BeltPool,
SideLoader,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
@ -46,7 +47,7 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
let mut 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 {
Building::SubFactory {
recipe,
@ -55,12 +56,22 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
} => {
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(
*machines,
recipe,
Beltspeed::Normal,
Some(Beltspeed::Normal),
Beltspeed::Normal,
Beltspeed::Express,
if input_count == 2 {
Some(Beltspeed::Express)
} else {
None
},
Beltspeed::Express,
);
blueprints.push(b);
@ -101,6 +112,34 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
blueprints.push(Blueprint::new());
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!(),
}
}
@ -112,7 +151,7 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
endblock: c.to,
endpoint: used_connections[c.to].1,
lanes: 1,
beltspeed: Beltspeed::Normal,
beltspeed: Beltspeed::from_items_per_second(c.amount),
});
used_connections[c.from].0 += 1;
@ -122,16 +161,11 @@ pub fn generate_factory<L: Layouter, P: Pathfinder>(
// dbg!(&blocks);
// dbg!(&connections);
let l = layouter
.layout(
&LayoutInput {
blocks,
connections,
},
pathfinder,
rng,
)
.unwrap();
let layout_input = LayoutInput {
blocks,
connections,
};
let l = layouter.layout(&layout_input, pathfinder, rng).unwrap();
let mut b = Blueprint::new();
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);
}
for path in &l.path_result {
b.add_path(&path[1..], Beltspeed::Fast);
for (path, connection) in l.path_result.iter().zip(layout_input.connections.iter()) {
b.add_path(&path[1..], connection.beltspeed);
}
b

View file

@ -56,6 +56,20 @@ impl Beltspeed {
}
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)]

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 {
population.sort_by_key(|(_, s)| *s);
for i in 0..(self.population_size - self.population_keep - self.population_new) {
loop {
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);
}
population.sort_by_key(|(_, s)| *s);
population.into_iter().next().map(|(l, _)| l)
Some(best_result.0)
}
}

View file

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