Add factory generator

This commit is contained in:
hal8174 2025-01-31 23:37:45 +01:00
parent 295490858b
commit 6fbff67e61
14 changed files with 308 additions and 15 deletions

2
Cargo.lock generated
View file

@ -566,7 +566,9 @@ dependencies = [
"clap 4.5.27", "clap 4.5.27",
"factorio-blueprint", "factorio-blueprint",
"factorio-core", "factorio-core",
"factorio-layout",
"factorio-pathfinding", "factorio-pathfinding",
"rand",
"serde_json", "serde_json",
] ]

View file

@ -5,7 +5,9 @@ edition = "2024"
[dependencies] [dependencies]
factorio-pathfinding = { path = "../factorio-pathfinding" } factorio-pathfinding = { path = "../factorio-pathfinding" }
factorio-layout = { path = "../factorio-layout" }
factorio-core = { path = "../factorio-core" } factorio-core = { path = "../factorio-core" }
factorio-blueprint = { path = "../factorio-blueprint" } factorio-blueprint = { path = "../factorio-blueprint" }
serde_json = "1.0.135" serde_json = "1.0.135"
clap = { version = "4.5.26", features = ["derive"] } clap = { version = "4.5.26", features = ["derive"] }
rand = { version = "0.8.5", features = ["small_rng"] }

View file

@ -28,7 +28,7 @@ pub fn assembly_line(assembly_machines: usize) -> Blueprint {
for i in 0..assembly_machines { for i in 0..assembly_machines {
blueprint.add_entity(Entity::new_production( blueprint.add_entity(Entity::new_production(
"assembling-machine-3", "assembling-machine-3",
"iron-gears", "iron-gear-wheel",
Position::new(3 + 6 * i as PositionType, 9), Position::new(3 + 6 * i as PositionType, 9),
Direction::Up, Direction::Up,
Position::new(6, 6), Position::new(6, 6),

View file

@ -0,0 +1,39 @@
use clap::Parser;
use factorio_blueprint::{BlueprintString, encode};
use factorio_blueprint_generator::factory::generate_factory;
use factorio_core::prelude::*;
use factorio_layout::valid_layout::ValidLayout;
use factorio_pathfinding::belt_finding::ConflictAvoidance;
use rand::{SeedableRng, rngs::SmallRng};
#[derive(Parser)]
struct Args {
#[arg(default_value_t = 0)]
seed: u64,
#[arg(short, long)]
json: bool,
}
fn main() {
let args = Args::parse();
let l = ValidLayout {
max_tries: 10,
retries: 10,
start_size: Position::new(100, 100),
growth: Position::new(5, 5),
};
let p = ConflictAvoidance {
timeout: Some(std::time::Duration::from_millis(20)),
};
let mut rng = SmallRng::seed_from_u64(args.seed);
let b = BlueprintString::Blueprint(generate_factory(&l, &p, &mut rng).to_blueprint());
if args.json {
println!("{}", serde_json::to_string_pretty(&b).unwrap());
}
println!("{}", encode(&serde_json::to_string(&b).unwrap()));
}

View file

@ -0,0 +1,122 @@
use factorio_blueprint::abstraction::Blueprint;
use factorio_core::{beltoptions::Beltspeed, prelude::*};
use factorio_layout::{Connection, Interface, LayoutInput, Layouter, MacroBlock};
use factorio_pathfinding::Pathfinder;
use rand::Rng;
use crate::assembly::assembly_line;
pub fn generate_factory<L: Layouter, P: Pathfinder>(
layouter: &L,
pathfinder: &P,
rng: &mut impl Rng,
) -> Blueprint {
// 2 * gears
// 3 * copper wires
// 2 * green circuits
// 2 * inserter
let input = vec![
Interface {
offset: Position::new(0, 1),
dir: Direction::Right,
},
Interface {
offset: Position::new(0, 7),
dir: Direction::Right,
},
Interface {
offset: Position::new(0, 8),
dir: Direction::Right,
},
];
let output = vec![Interface {
offset: Position::new(0, 0),
dir: Direction::Left,
}];
let blocks = vec![
MacroBlock {
size: Position::new(6, 9),
input: input.clone(),
output: output.clone(),
},
MacroBlock {
size: Position::new(9, 9),
input: input.clone(),
output: output.clone(),
},
MacroBlock {
size: Position::new(6, 9),
input: input.clone(),
output: output.clone(),
},
MacroBlock {
size: Position::new(6, 9),
input: input.clone(),
output: output.clone(),
},
];
let connections = vec![
Connection {
startblock: 0,
startpoint: 0,
endblock: 3,
endpoint: 0,
lanes: 1,
beltspeed: Beltspeed::Fast,
},
Connection {
startblock: 1,
startpoint: 0,
endblock: 2,
endpoint: 0,
lanes: 1,
beltspeed: Beltspeed::Fast,
},
Connection {
startblock: 2,
startpoint: 0,
endblock: 3,
endpoint: 1,
lanes: 1,
beltspeed: Beltspeed::Fast,
},
];
let l = layouter
.layout(
&LayoutInput {
blocks,
connections,
},
pathfinder,
rng,
)
.unwrap();
let blueprints = vec![
assembly_line(2),
assembly_line(3),
assembly_line(2),
assembly_line(2),
];
let mut b = Blueprint::new();
for (block, mut assembly_blueprint) in l.positions.iter().zip(blueprints) {
let offset = match block.dir() {
Direction::Up => Position::new(0, 0),
Direction::Right => Position::new(2, 0),
Direction::Down => Position::new(2, 2),
Direction::Left => Position::new(0, 2),
};
assembly_blueprint.transform(Transformation::new(block.dir(), offset + 2 * block.pos()));
b.add_blueprint(assembly_blueprint);
}
for path in &l.path_result {
b.add_path(&path[1..], Beltspeed::Fast);
}
b
}

View file

@ -1,6 +1,7 @@
pub mod assembly; pub mod assembly;
pub mod balancer; pub mod balancer;
pub mod binary_merger; pub mod binary_merger;
pub mod factory;
pub mod multistation; pub mod multistation;
pub mod station; pub mod station;
pub mod train; pub mod train;

View file

@ -39,7 +39,7 @@ connections:
startpoint: 0 startpoint: 0
endblock: 0 endblock: 0
endpoint: 0 endpoint: 0
lanes: 1 lanes: 2
beltspeed: Normal beltspeed: Normal
- startblock: 0 - startblock: 0
startpoint: 0 startpoint: 0

View file

@ -0,0 +1,127 @@
size:
x: 50
y: 50
blocks:
- size:
x: 3
y: 2
input:
- offset:
x: 1
y: 1
dir: Up
output:
- offset:
x: 1
y: 0
dir: Up
- size:
x: 5
y: 2
input:
output:
- offset:
x: 1
y: 1
dir: Down
- size:
x: 5
y: 7
input:
- offset:
x: 0
y: 1
dir: Right
output:
- size:
x: 5
y: 5
input:
- offset:
x: 0
y: 1
dir: Right
output:
- offset:
x: 0
y: 3
dir: Left
- size:
x: 10
y: 10
input:
- offset:
x: 0
y: 1
dir: Right
- offset:
x: 0
y: 3
dir: Right
output:
- offset:
x: 9
y: 1
dir: Right
- offset:
x: 9
y: 3
dir: Right
- size:
x: 10
y: 5
input:
- offset:
x: 0
y: 1
dir: Right
- offset:
x: 0
y: 3
dir: Right
output:
- offset:
x: 9
y: 1
dir: Right
- offset:
x: 9
y: 3
dir: Right
connections:
- startblock: 1
startpoint: 0
endblock: 0
endpoint: 0
lanes: 2
beltspeed: Normal
- startblock: 0
startpoint: 0
endblock: 3
endpoint: 0
lanes: 1
beltspeed: Normal
- startblock: 3
startpoint: 0
endblock: 4
endpoint: 0
lanes: 1
beltspeed: Normal
- startblock: 4
startpoint: 0
endblock: 5
endpoint: 0
lanes: 1
beltspeed: Normal
- startblock: 4
startpoint: 1
endblock: 5
endpoint: 1
lanes: 1
beltspeed: Normal
- startblock: 5
startpoint: 0
endblock: 2
endpoint: 0
lanes: 1
beltspeed: Normal

View file

@ -31,12 +31,12 @@ fn main() {
}; };
let p = ConflictAvoidance { let p = ConflictAvoidance {
timeout: Some(std::time::Duration::from_millis(100)), timeout: Some(std::time::Duration::from_millis(5)),
}; };
let mut rng = SmallRng::seed_from_u64(args.seed); let mut rng = SmallRng::seed_from_u64(args.seed);
let r = l.layout(&problem, &p, &mut rng); let r = l.layout(&problem, &p, &mut rng);
dbg!(r); // dbg!(r);
} }

View file

@ -152,20 +152,20 @@ pub fn valid_path_layout<'a, R: Rng + ?Sized>(
} }
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub(crate) struct MacroBlock { pub(crate) struct MacroBlock {
pub(crate) size: Position, pub(crate) size: Position,
pub(crate) input: Vec<Interface>, pub(crate) input: Vec<Interface>,
pub(crate) output: Vec<Interface>, pub(crate) output: Vec<Interface>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub(crate) struct Interface { pub(crate) struct Interface {
pub(crate) offset: Position, pub(crate) offset: Position,
pub(crate) dir: Direction, pub(crate) dir: Direction,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub(crate) struct Connection { pub(crate) struct Connection {
pub(crate) startblock: usize, pub(crate) startblock: usize,
pub(crate) startpoint: usize, pub(crate) startpoint: usize,
@ -173,7 +173,7 @@ pub(crate) struct Connection {
pub(crate) endpoint: usize, pub(crate) endpoint: usize,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Problem { pub struct Problem {
pub(crate) size: Position, pub(crate) size: Position,
pub(crate) blocks: Vec<MacroBlock>, pub(crate) blocks: Vec<MacroBlock>,

View file

@ -3,21 +3,20 @@ use factorio_pathfinding::Pathfinder;
use rand::Rng; use rand::Rng;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod block;
pub mod genetic_algorithm_v1; pub mod genetic_algorithm_v1;
pub mod genetic_algorithm_v2; pub mod genetic_algorithm_v2;
pub mod layout; pub mod layout;
pub mod misc; pub mod misc;
pub mod valid_layout; pub mod valid_layout;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct MacroBlock { pub struct MacroBlock {
pub size: Position, pub size: Position,
pub input: Vec<Interface>, pub input: Vec<Interface>,
pub output: Vec<Interface>, pub output: Vec<Interface>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub struct Interface { pub struct Interface {
pub offset: Position, pub offset: Position,
pub dir: Direction, pub dir: Direction,

View file

@ -267,7 +267,7 @@ impl ConflictAvoidance {
while b.next_finish_state(timeout) { while b.next_finish_state(timeout) {
// println!("{}", b); // println!("{}", b);
// b.print(); // b.print();
b.print_visualization(); // b.print_visualization();
let c = b.cost(); let c = b.cost();
if c < min_cost { if c < min_cost {
min_cost = c; min_cost = c;

View file

@ -40,13 +40,14 @@ impl SinglePathfinder for ConflictAvoidance {
); );
} }
p.print_visualization(); // p.print_visualization();
if p.find_path() { if p.find_path() {
let mut c = conflict_avoidance::ConflictAvoidance::new(&p); let mut c = conflict_avoidance::ConflictAvoidance::new(&p);
c.print_visualization(); // c.print_visualization();
if c.remove_all_conflicts(self.timeout) { if c.remove_all_conflicts(self.timeout) {
c.print_visualization();
Some(c.get_paths().to_vec()) Some(c.get_paths().to_vec())
} else { } else {
None None

View file

@ -64,7 +64,7 @@ where
start_dir: c.start_dir, start_dir: c.start_dir,
end_pos: c end_pos: c
.end_pos .end_pos
.in_direction(&c.start_dir.clockwise(), i as PositionType), .in_direction(&c.end_dir.clockwise(), i as PositionType),
end_dir: c.end_dir, end_dir: c.end_dir,
beltspeed: c.beltspeed, beltspeed: c.beltspeed,
}) })