Refactor layouting into separate crate
This commit is contained in:
parent
c3bb980fcf
commit
5c8010c23b
15 changed files with 124 additions and 55 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -584,6 +584,21 @@ dependencies = [
|
||||||
"termcolor",
|
"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]]
|
[[package]]
|
||||||
name = "factorio-pathfinding"
|
name = "factorio-pathfinding"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -599,7 +614,6 @@ dependencies = [
|
||||||
"miette",
|
"miette",
|
||||||
"proptest",
|
"proptest",
|
||||||
"proptest-derive",
|
"proptest-derive",
|
||||||
"rand",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core",
|
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core", "factorio-layout",
|
||||||
"factorio-pathfinding"
|
"factorio-pathfinding"
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ fn main() {
|
||||||
// ],
|
// ],
|
||||||
8,
|
8,
|
||||||
)
|
)
|
||||||
|
.0
|
||||||
.to_blueprint(),
|
.to_blueprint(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ fn calculate_station_height(
|
||||||
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
|
let longest_train = stations
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.locomotives + s.wagons)
|
.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 inrail_x = 10 - 4 * stacker_length as PositionType;
|
||||||
let outrail_x = inrail_x + 52 + 4 * (7 * longest_train).div_ceil(2) 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;
|
let mut previous_station_heights = 0;
|
||||||
// station
|
// station
|
||||||
for (i, station) in stations.iter().enumerate() {
|
for (i, station) in stations.iter().enumerate() {
|
||||||
|
|
@ -269,6 +273,8 @@ pub fn multistation(stations: &[StationSpec], stacker_size: usize) -> Blueprint
|
||||||
let station_height =
|
let station_height =
|
||||||
calculate_station_height(output_height, station.lanes, station.beltspeed);
|
calculate_station_height(output_height, station.lanes, station.beltspeed);
|
||||||
|
|
||||||
|
output_heights.push(30 + total_stacker_height + previous_station_heights + output_height);
|
||||||
|
|
||||||
// rail crossing
|
// rail crossing
|
||||||
let (beltdirection, underground_left, underground_right) = match station.load {
|
let (beltdirection, underground_left, underground_right) = match station.load {
|
||||||
true => (
|
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.transform(Transformation::new(Direction::Right, Position::new(0, 0)));
|
||||||
|
|
||||||
blueprint
|
(blueprint, outrail_x + 5, output_heights)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
use factorio_core::{
|
use factorio_core::{
|
||||||
aabb::AABB,
|
aabb::AABB, beltoptions::Beltspeed, pathfield::PathField, prelude::*,
|
||||||
beltoptions::Beltspeed,
|
|
||||||
direction,
|
|
||||||
pathfield::PathField,
|
|
||||||
prelude::{Direction, Position, PositionType, Transformable, Transformation},
|
|
||||||
quaterdirection::QuaterDirection,
|
quaterdirection::QuaterDirection,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, sync::atomic::AtomicUsize};
|
use std::{collections::HashMap, sync::atomic::AtomicUsize};
|
||||||
|
|
|
||||||
15
factorio-layout/Cargo.toml
Normal file
15
factorio-layout/Cargo.toml
Normal 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"
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use factorio_core::visualize::Visualize;
|
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 miette::{Context, IntoDiagnostic, Result};
|
||||||
use rand::{rngs::SmallRng, SeedableRng};
|
use rand::{SeedableRng, rngs::SmallRng};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::belt_finding::conflict_avoidance::ConflictAvoidance;
|
|
||||||
use factorio_core::{
|
use factorio_core::{
|
||||||
pathfield::PathField,
|
pathfield::PathField,
|
||||||
prelude::*,
|
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 serde::{Deserialize, Serialize};
|
||||||
use std::{sync::atomic::AtomicU32, time::Instant};
|
use std::{sync::atomic::AtomicU32, time::Instant};
|
||||||
|
|
||||||
|
|
@ -195,9 +195,48 @@ pub struct PathLayout<'a> {
|
||||||
score: usize,
|
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> {
|
impl<'a> PathLayout<'a> {
|
||||||
pub fn new(layout: Layout<'a>) -> Option<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() {
|
if !p.find_path() {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -343,7 +382,7 @@ impl Layout<'_> {
|
||||||
|
|
||||||
let b = &problem.blocks[blocks.len()];
|
let b = &problem.blocks[blocks.len()];
|
||||||
for _ in 0..1000 {
|
for _ in 0..1000 {
|
||||||
let dir = rng.gen::<Direction>();
|
let dir = rng.r#gen::<Direction>();
|
||||||
|
|
||||||
let pos = match dir {
|
let pos = match dir {
|
||||||
Direction::Up => Position::new(
|
Direction::Up => Position::new(
|
||||||
|
|
@ -433,7 +472,7 @@ impl Layout<'_> {
|
||||||
fn mutate_replace<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool {
|
fn mutate_replace<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool {
|
||||||
let i = rng.gen_range(0..layout.blocks.len());
|
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];
|
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 {
|
fn mutate_jiggle<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool {
|
||||||
let i = rng.gen_range(0..layout.blocks.len());
|
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)]
|
let step = [(1, 10), (2, 5), (3, 5)]
|
||||||
.choose_weighted(rng, |i| i.1)
|
.choose_weighted(rng, |i| i.1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
1
factorio-layout/src/lib.rs
Normal file
1
factorio-layout/src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod layout;
|
||||||
|
|
@ -24,7 +24,6 @@ image = "0.25.2"
|
||||||
miette = { version = "7.2.0", features = ["fancy"] }
|
miette = { version = "7.2.0", features = ["fancy"] }
|
||||||
proptest = "1.5.0"
|
proptest = "1.5.0"
|
||||||
proptest-derive = "0.5.0"
|
proptest-derive = "0.5.0"
|
||||||
rand = { version = "0.8.5", features = ["small_rng"] }
|
|
||||||
serde = { version = "1.0.192", features = ["derive"] }
|
serde = { version = "1.0.192", features = ["derive"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
||||||
use crate::graph::wheighted_graph::WheightedGraph;
|
use crate::graph::wheighted_graph::WheightedGraph;
|
||||||
use crate::layout::Layout;
|
|
||||||
use crate::misc::Map;
|
use crate::misc::Map;
|
||||||
use crate::priority_queue::BinaryHeap;
|
use crate::priority_queue::BinaryHeap;
|
||||||
use factorio_core::{prelude::*, visualize::Visualize};
|
use factorio_core::{prelude::*, visualize::Visualize};
|
||||||
|
|
@ -34,44 +33,44 @@ impl Problem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_layout(l: &Layout) -> Self {
|
// pub fn from_layout(l: &Layout) -> Self {
|
||||||
let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
|
// let mut p = Self::new(l.problem.size.x as usize, l.problem.size.y as usize);
|
||||||
|
|
||||||
for b in &l.blocks {
|
// for b in &l.blocks {
|
||||||
let aabb = b.get_aabb();
|
// let aabb = b.get_aabb();
|
||||||
|
|
||||||
p.set_blocked_range(
|
// p.set_blocked_range(
|
||||||
aabb.min().x as usize,
|
// aabb.min().x as usize,
|
||||||
aabb.min().y as usize,
|
// aabb.min().y as usize,
|
||||||
aabb.max().x as usize,
|
// aabb.max().x as usize,
|
||||||
aabb.max().y as usize,
|
// aabb.max().y as usize,
|
||||||
true,
|
// true,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
for c in &l.problem.connections {
|
// for c in &l.problem.connections {
|
||||||
let start_transform = l.blocks[c.startblock].block_to_world();
|
// let start_transform = l.blocks[c.startblock].block_to_world();
|
||||||
let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
|
// let startpos = l.problem.blocks[c.startblock].output[c.startpoint]
|
||||||
.offset
|
// .offset
|
||||||
.transform(start_transform);
|
// .transform(start_transform);
|
||||||
let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
|
// let startdir = l.problem.blocks[c.startblock].output[c.startpoint]
|
||||||
.dir
|
// .dir
|
||||||
.transform(start_transform);
|
// .transform(start_transform);
|
||||||
let end_transform = l.blocks[c.endblock].block_to_world();
|
// let end_transform = l.blocks[c.endblock].block_to_world();
|
||||||
let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
|
// let endpos = l.problem.blocks[c.endblock].input[c.endpoint]
|
||||||
.offset
|
// .offset
|
||||||
.transform(end_transform);
|
// .transform(end_transform);
|
||||||
let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
|
// let enddir = l.problem.blocks[c.endblock].input[c.endpoint]
|
||||||
.dir
|
// .dir
|
||||||
.transform(end_transform);
|
// .transform(end_transform);
|
||||||
p.add_connection(
|
// p.add_connection(
|
||||||
(startpos, startdir),
|
// (startpos, startdir),
|
||||||
(endpos.in_direction(&enddir, -1), enddir),
|
// (endpos.in_direction(&enddir, -1), enddir),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
p
|
// p
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
|
pub fn add_connection(&mut self, start: (Position, Direction), end: (Position, Direction)) {
|
||||||
self.start.push(start);
|
self.start.push(start);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
pub mod belt_finding;
|
pub mod belt_finding;
|
||||||
pub mod graph;
|
pub mod graph;
|
||||||
pub mod layout;
|
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
pub mod priority_queue;
|
pub mod priority_queue;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue