Refactor layouting into separate crate

This commit is contained in:
hal8174 2025-01-27 22:09:59 +01:00
parent c3bb980fcf
commit 5c8010c23b
15 changed files with 124 additions and 55 deletions

16
Cargo.lock generated
View file

@ -584,6 +584,21 @@ dependencies = [
"termcolor",
]
[[package]]
name = "factorio-layout"
version = "0.1.0"
dependencies = [
"clap 4.5.26",
"factorio-core",
"factorio-pathfinding",
"image",
"miette",
"rand",
"serde",
"serde_json",
"serde_yaml",
]
[[package]]
name = "factorio-pathfinding"
version = "0.1.0"
@ -599,7 +614,6 @@ dependencies = [
"miette",
"proptest",
"proptest-derive",
"rand",
"serde",
"serde_json",
"serde_yaml",

View file

@ -1,5 +1,5 @@
[workspace]
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core",
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core", "factorio-layout",
"factorio-pathfinding"
]
resolver = "2"

View file

@ -85,6 +85,7 @@ fn main() {
// ],
8,
)
.0
.to_blueprint(),
);

View file

@ -40,7 +40,10 @@ fn calculate_station_height(
station_height
}
pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint {
pub fn multistation(
stations: &[StationSpec],
stacker_size: usize,
) -> (Blueprint, PositionType, Vec<PositionType>) {
let longest_train = stations
.iter()
.map(|s| s.locomotives + s.wagons)
@ -144,6 +147,7 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint
let inrail_x = 10 - 4 * stacker_length as PositionType;
let outrail_x = inrail_x + 52 + 4 * (7 * longest_train).div_ceil(2) as PositionType;
let mut output_heights = Vec::new();
let mut previous_station_heights = 0;
// station
for (i, station) in stations.iter().enumerate() {
@ -269,6 +273,8 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint
let station_height =
calculate_station_height(output_height, station.lanes, station.beltspeed);
output_heights.push(30 + total_stacker_height + previous_station_heights + output_height);
// rail crossing
let (beltdirection, underground_left, underground_right) = match station.load {
true => (
@ -629,5 +635,5 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint
blueprint.transform(Transformation::new(Direction::Right, Position::new(0, 0)));
blueprint
(blueprint, outrail_x + 5, output_heights)
}

View file

@ -1,9 +1,5 @@
use factorio_core::{
aabb::AABB,
beltoptions::Beltspeed,
direction,
pathfield::PathField,
prelude::{Direction, Position, PositionType, Transformable, Transformation},
aabb::AABB, beltoptions::Beltspeed, pathfield::PathField, prelude::*,
quaterdirection::QuaterDirection,
};
use std::{collections::HashMap, sync::atomic::AtomicUsize};

View file

@ -0,0 +1,15 @@
[package]
name = "factorio-layout"
version = "0.1.0"
edition = "2024"
[dependencies]
factorio-core = { path = "../factorio-core" }
factorio-pathfinding = { path = "../factorio-pathfinding" }
rand = { version = "0.8.5", features = ["small_rng"] }
serde = { version = "1.0.192", features = ["derive"] }
image = "0.25.2"
serde_json = "1.0.108"
clap = { version = "4.4.8", features = ["derive"] }
miette = { version = "7.2.0", features = ["fancy"] }
serde_yaml = "0.9.34"

View file

@ -1,8 +1,8 @@
use clap::{Parser, Subcommand};
use factorio_core::visualize::Visualize;
use factorio_pathfinding::layout::{genetic_algorithm2, GeneticAlgorithm, PathLayout};
use factorio_layout::layout::{GeneticAlgorithm, PathLayout, genetic_algorithm2};
use miette::{Context, IntoDiagnostic, Result};
use rand::{rngs::SmallRng, SeedableRng};
use rand::{SeedableRng, rngs::SmallRng};
use std::path::PathBuf;
#[derive(Debug, Parser)]

View file

@ -1,10 +1,10 @@
use crate::belt_finding::conflict_avoidance::ConflictAvoidance;
use factorio_core::{
pathfield::PathField,
prelude::*,
visualize::{image_grid, Color, Symbol, Visualization, Visualize},
visualize::{Color, Symbol, Visualization, Visualize, image_grid},
};
use rand::{seq::SliceRandom, Rng};
use factorio_pathfinding::belt_finding::{self, conflict_avoidance::ConflictAvoidance};
use rand::{Rng, seq::SliceRandom};
use serde::{Deserialize, Serialize};
use std::{sync::atomic::AtomicU32, time::Instant};
@ -195,9 +195,48 @@ pub struct PathLayout<'a> {
score: usize,
}
pub fn beltfinding_problem_from_layout(l: &Layout) -> belt_finding::Problem {
let mut p = belt_finding::Problem::new(l.problem.size.x as usize, l.problem.size.y as usize);
for b in &l.blocks {
let aabb = b.get_aabb();
p.set_blocked_range(
aabb.min().x as usize,
aabb.min().y as usize,
aabb.max().x as usize,
aabb.max().y as usize,
true,
);
}
for c in &l.problem.connections {
let start_transform = l.blocks[c.startblock].block_to_world();
let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
.offset
.transform(start_transform);
let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
.dir
.transform(start_transform);
let end_transform = l.blocks[c.endblock].block_to_world();
let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
.offset
.transform(end_transform);
let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
.dir
.transform(end_transform);
p.add_connection(
(startpos, startdir),
(endpos.in_direction(&enddir, -1), enddir),
);
}
p
}
impl<'a> PathLayout<'a> {
pub fn new(layout: Layout<'a>) -> Option<PathLayout<'a>> {
let mut p = crate::belt_finding::Problem::from_layout(&layout);
let mut p = beltfinding_problem_from_layout(&layout);
if !p.find_path() {
return None;
@ -343,7 +382,7 @@ impl Layout<'_> {
let b = &problem.blocks[blocks.len()];
for _ in 0..1000 {
let dir = rng.gen::<Direction>();
let dir = rng.r#gen::<Direction>();
let pos = match dir {
Direction::Up => Position::new(
@ -433,7 +472,7 @@ impl Layout<'_> {
fn mutate_replace<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool {
let i = rng.gen_range(0..layout.blocks.len());
let dir = rng.gen::<Direction>();
let dir = rng.r#gen::<Direction>();
let b = &layout.problem.blocks[i];
@ -492,7 +531,7 @@ impl Layout<'_> {
fn mutate_jiggle<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool {
let i = rng.gen_range(0..layout.blocks.len());
let dir = rng.gen::<Direction>();
let dir = rng.r#gen::<Direction>();
let step = [(1, 10), (2, 5), (3, 5)]
.choose_weighted(rng, |i| i.1)
.unwrap()

View file

@ -0,0 +1 @@
pub mod layout;

View file

@ -24,7 +24,6 @@ image = "0.25.2"
miette = { version = "7.2.0", features = ["fancy"] }
proptest = "1.5.0"
proptest-derive = "0.5.0"
rand = { version = "0.8.5", features = ["small_rng"] }
serde = { version = "1.0.192", features = ["derive"] }
serde_json = "1.0.108"
serde_yaml = "0.9.34"

View file

@ -1,6 +1,5 @@
use crate::graph::wheighted_graph::shortest_path::dijkstra;
use crate::graph::wheighted_graph::WheightedGraph;
use crate::layout::Layout;
use crate::misc::Map;
use crate::priority_queue::BinaryHeap;
use factorio_core::{prelude::*, visualize::Visualize};
@ -34,44 +33,44 @@ impl Problem {
}
}
pub fn from_layout(l: &Layout) -> Self {
let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
// pub fn from_layout(l: &Layout) -> Self {
// let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
for b in &l.blocks {
let aabb = b.get_aabb();
// for b in &l.blocks {
// let aabb = b.get_aabb();
p.set_blocked_range(
aabb.min().x as usize,
aabb.min().y as usize,
aabb.max().x as usize,
aabb.max().y as usize,
true,
);
}
// p.set_blocked_range(
// aabb.min().x as usize,
// aabb.min().y as usize,
// aabb.max().x as usize,
// aabb.max().y as usize,
// true,
// );
// }
for c in &l.problem.connections {
let start_transform = l.blocks[c.startblock].block_to_world();
let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
.offset
.transform(start_transform);
let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
.dir
.transform(start_transform);
let end_transform = l.blocks[c.endblock].block_to_world();
let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
.offset
.transform(end_transform);
let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
.dir
.transform(end_transform);
p.add_connection(
(startpos, startdir),
(endpos.in_direction(&enddir, -1), enddir),
);
}
// for c in &l.problem.connections {
// let start_transform = l.blocks[c.startblock].block_to_world();
// let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
// .offset
// .transform(start_transform);
// let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
// .dir
// .transform(start_transform);
// let end_transform = l.blocks[c.endblock].block_to_world();
// let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
// .offset
// .transform(end_transform);
// let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
// .dir
// .transform(end_transform);
// p.add_connection(
// (startpos, startdir),
// (endpos.in_direction(&enddir, -1), enddir),
// );
// }
p
}
// p
// }
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
self.start.push(start);

View file

@ -1,5 +1,4 @@
pub mod belt_finding;
pub mod graph;
pub mod layout;
pub mod misc;
pub mod priority_queue;