Refactor into different crates
This commit is contained in:
parent
94473c64e0
commit
dfdeae5638
82 changed files with 624 additions and 647 deletions
592
Cargo.lock
generated
592
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
33
Cargo.toml
33
Cargo.toml
|
|
@ -1,31 +1,8 @@
|
|||
[package]
|
||||
name = "factorio_blueprint"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[workspace]
|
||||
members = [ "factorio-blueprint", "factorio-blueprint-generator", "factorio-core",
|
||||
"factorio-pathfinding"
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "bruteforce"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.5"
|
||||
bon = "3.0.2"
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
flate2 = "1.0.28"
|
||||
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"
|
||||
termcolor = "1.4.1"
|
||||
|
|
|
|||
11
factorio-blueprint-generator/Cargo.toml
Normal file
11
factorio-blueprint-generator/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "factorio-blueprint-generator"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
factorio-pathfinding = { path = "../factorio-pathfinding" }
|
||||
factorio-core = { path = "../factorio-core" }
|
||||
factorio-blueprint = { path = "../factorio-blueprint" }
|
||||
serde_json = "1.0.135"
|
||||
clap = { version = "4.5.26", features = ["derive"] }
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
use crate::{belt_finding::common::PathField, prelude::*};
|
||||
|
||||
use super::{
|
||||
belt::{convert_to_blueprint, Beltspeed},
|
||||
Blueprint, BlueprintEntity, BlueprintPosition,
|
||||
use factorio_blueprint::{
|
||||
Blueprint, BlueprintEntity, BlueprintPosition, belt::convert_to_blueprint, misc::Beltspeed,
|
||||
};
|
||||
use factorio_core::{pathfield::PathField, prelude::*};
|
||||
|
||||
pub fn generate_4_lane_balancer() -> Blueprint {
|
||||
let mut e = vec![
|
||||
10
factorio-blueprint-generator/src/bin/balancer_blueprint.rs
Normal file
10
factorio-blueprint-generator/src/bin/balancer_blueprint.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use factorio_blueprint::{BlueprintString, encode};
|
||||
use factorio_blueprint_generator::balancer::generate_4_lane_balancer;
|
||||
|
||||
fn main() {
|
||||
let b = BlueprintString::Blueprint(generate_4_lane_balancer());
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&b).unwrap());
|
||||
|
||||
println!("{}", encode(&serde_json::to_string(&b).unwrap()));
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use factorio_blueprint::blueprint::{
|
||||
belt::{Beltspeed, Belttype},
|
||||
station::{basic_unload_station, station_unload},
|
||||
BlueprintBook, BlueprintBookEntry, BlueprintString,
|
||||
use factorio_blueprint::{
|
||||
BlueprintBook, BlueprintBookEntry, BlueprintString, encode,
|
||||
misc::{Beltspeed, Belttype},
|
||||
};
|
||||
use factorio_blueprint_generator::station::basic_unload_station;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
|
|
@ -104,10 +104,7 @@ fn main() {
|
|||
.build(),
|
||||
);
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap())
|
||||
);
|
||||
println!("{}", encode(&serde_json::to_string(&b).unwrap()));
|
||||
}
|
||||
Command::Single {
|
||||
locomotives,
|
||||
|
|
@ -126,10 +123,7 @@ fn main() {
|
|||
|
||||
// println!("{}", serde_json::to_string_pretty(&b).unwrap());
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap())
|
||||
);
|
||||
println!("{}", encode(&serde_json::to_string(&b).unwrap()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
use factorio_blueprint::blueprint::{
|
||||
train::generate_train, BlueprintBook, BlueprintBookEntry, BlueprintString,
|
||||
};
|
||||
use factorio_blueprint::{BlueprintBook, BlueprintBookEntry, BlueprintString, encode};
|
||||
use factorio_blueprint_generator::train::generate_train;
|
||||
|
||||
fn main() {
|
||||
let layouts = [
|
||||
|
|
@ -38,8 +37,5 @@ fn main() {
|
|||
|
||||
println!("{}", serde_json::to_string_pretty(&b).unwrap());
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap())
|
||||
);
|
||||
println!("{}", encode(&serde_json::to_string(&b).unwrap()));
|
||||
}
|
||||
3
factorio-blueprint-generator/src/lib.rs
Normal file
3
factorio-blueprint-generator/src/lib.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pub mod balancer;
|
||||
pub mod station;
|
||||
pub mod train;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::{
|
||||
belt::{Beltspeed, Belttype},
|
||||
use factorio_blueprint::{
|
||||
Blueprint, BlueprintEntity, BlueprintPosition,
|
||||
misc::{Beltspeed, Belttype},
|
||||
};
|
||||
|
||||
pub fn station_unload(
|
||||
|
|
@ -177,12 +177,14 @@ pub fn station_unload(
|
|||
pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Vec<BlueprintEntity>, f64) {
|
||||
match beltspeed {
|
||||
Beltspeed::Normal => {
|
||||
let mut e = vec![BlueprintEntity::builder(
|
||||
"fast-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -1.5),
|
||||
)
|
||||
.build()];
|
||||
let mut e = vec![
|
||||
BlueprintEntity::builder(
|
||||
"fast-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -1.5),
|
||||
)
|
||||
.build(),
|
||||
];
|
||||
|
||||
if belttype.contains_left() {
|
||||
let offset = e.len() as u32;
|
||||
|
|
@ -239,12 +241,14 @@ pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Vec<BlueprintEntit
|
|||
(e, -2.5)
|
||||
}
|
||||
Beltspeed::Fast => {
|
||||
let mut e = vec![BlueprintEntity::builder(
|
||||
"fast-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -3.5),
|
||||
)
|
||||
.build()];
|
||||
let mut e = vec![
|
||||
BlueprintEntity::builder(
|
||||
"fast-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -3.5),
|
||||
)
|
||||
.build(),
|
||||
];
|
||||
|
||||
if belttype.contains_left() {
|
||||
let offset = e.len() as u32;
|
||||
|
|
@ -369,12 +373,14 @@ pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Vec<BlueprintEntit
|
|||
(e, -4.5)
|
||||
}
|
||||
Beltspeed::Express => {
|
||||
let mut e = vec![BlueprintEntity::builder(
|
||||
"express-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -3.5),
|
||||
)
|
||||
.build()];
|
||||
let mut e = vec![
|
||||
BlueprintEntity::builder(
|
||||
"express-transport-belt".to_owned(),
|
||||
0,
|
||||
BlueprintPosition::new(3.5, -3.5),
|
||||
)
|
||||
.build(),
|
||||
];
|
||||
|
||||
if belttype.contains_left() {
|
||||
let offset = e.len() as u32;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{
|
||||
use factorio_blueprint::{
|
||||
Blueprint, BlueprintEntity, BlueprintInventoryLocation, BlueprintItemID, BlueprintItemRequest,
|
||||
BlueprintPosition, BlueprintStockConnection,
|
||||
};
|
||||
13
factorio-blueprint/Cargo.toml
Normal file
13
factorio-blueprint/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "factorio-blueprint"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
factorio-core = { path = "../factorio-core" }
|
||||
base64 = "0.22.1"
|
||||
bon = "3.3.2"
|
||||
clap = { version = "4.5.26", features = ["derive"] }
|
||||
serde = "1.0.217"
|
||||
serde_json = "1.0.135"
|
||||
flate2 = "1.0.35"
|
||||
1
factorio-blueprint/blueprints/chests.bp
Normal file
1
factorio-blueprint/blueprints/chests.bp
Normal file
|
|
@ -0,0 +1 @@
|
|||
0eNqVkN0OgjAMRt+l14XwVw28ijFmYKNNYCAbRkL27o55oVET42Wbfue0XaBuJx5G0RaqBaTptYFqt4CRk1bt2tOqY6jAWOY2as5sLDgE0Ue+QZU6/DGLcJlUK3b2fR6keQlnbo/A2ooVflhDMR/01NU8ejp+Jw698Zler0rPIaKYELwhKmJyH0aEWnnaNlmXfVNkfysoKAIxT9YLxHLn889HIlx5NCFMm6wsypKooKzMU+fu/rR3Gg==
|
||||
1
factorio-blueprint/blueprints/train-signals-param.bp
Normal file
1
factorio-blueprint/blueprints/train-signals-param.bp
Normal file
|
|
@ -0,0 +1 @@
|
|||
0eNrFld2OmzAQhV9lNZeVWfETkgWpfYJe9i6KLAKTrlWwqW3SRhHv3jE4JLv1ptVetIqExoP9cebMQM6wbwfstZAWyjOIWkkD5fYMRnyVVetysuoQSmiwFg3qqFbdXsjKKg0jAyEb/AllMrLAEasrISNjVX+zNR13DFBaYQXOj5oWJy6Hbo+aWCxwnkGvDB1R0vEJs85o3wnKqMiITbKtVi3f43N1FCSNNhmUDbeKTxQoD1VrkM1M7pg9Nvwq2Z5698ij0HagzKJh3hF9cRUYtDPN8FZ0ghyzergwfe7vkZ9hdExbzVUBOA9feZGyO/a/7cnT02NO7EZorOf7SRo2yWM53WsmlHHZ2xU16CC0uS3MS+orTYElUTHMPaBi3BylcRy7LqvB9oN9PU9/tsWx+hNpGqTlB606LiSBfA/H3TgGrMreadXmv1qVkFVu3bkdTmkJn+Cfe7daQB02YugibMkNLeqoVy0G3XvMvX9r8i+AzBfkfmi/RfR+oKb6Q6z4wtoExjaAXl/LtohtVD+jsXdFTuAAafP+ujeFQ1KjfpBa16ZtwhKWsmzHtilFGUumKHM/imjNVlOOrmzjo5yinKK1zxFvGZW5977joiE1dHk5Sgy+0xhQRdEyhk6pT9JmqXQ3zcmLCfsIkxke7c1gl6AE9/5eZyul8ECcoa3c42NuKNFgT59XlP4beBeXvMAlv+EePjykASR5ISx2boKWvygGRzJmKjNfp8WqKPJ8ladFlozjL1XOQeE=
|
||||
1
factorio-blueprint/blueprints/train-signals.bp
Normal file
1
factorio-blueprint/blueprints/train-signals.bp
Normal file
|
|
@ -0,0 +1 @@
|
|||
0eNrFlM9unDAQxt9lziZaYIHAoU/QY2+rFeLPbGPV2JY9bLNa8e4ZA9msIppWOTRCQuOx/fM33xiu0KoRrZOaoLqC7Iz2UB2u4OVP3aiQ082AUEGPnezRRZ0ZWqkbMg4mAVL3+AxVPImNLeQaqSNPxt4tTaajANQkSeJy1Dy41HocWnTMEhv7BVjjeYvRgc+YPOV1F6iiMmU2yyZnVN3iU3OWLI0XedR9TaaeKVCdGuVRLMw6MC329Ztkuthw5Fk6Gjlz07CsiH6ECjzSQvO1koNkx8iNr8w19+/I7zAFJjVLVQDBw3deJOID+//syePjQ8bsXjrslvk42TZpxdY8188oH7L3I27QSTp/X9gqSTqjI6saQlhawLWEa5TsdrvQZDOSHen9dfq7K4FlLyxp1FSfnBlqqRm0tnA6TtOGU+knnSq+0qmYnQrjwTZuFlrBN/jv1u1voAF7OQ4RKjbDyS6yRuGmeQ/Zal/O9m0gsxuyHdWviL8OdISbjdi9soqNS7uBzt/KJkQVdU/o6UORM3iDVHy+7qIMSG7Ub1Yb2nSIRSwSkR7FIeEoFfEcpeHhiMdiP+f4LYo1yjjKOMrXHPMk4RBcu/2UBZzR+VlEliflviyzbJ8lZRpP0wudqOug
|
||||
59
factorio-blueprint/src/belt.rs
Normal file
59
factorio-blueprint/src/belt.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use factorio_core::{pathfield::PathField, prelude::*};
|
||||
|
||||
use crate::misc::Beltspeed;
|
||||
|
||||
use super::{BlueprintEntity, BlueprintPosition};
|
||||
|
||||
pub fn convert_belt_to_blueprint(
|
||||
belt: &PathField,
|
||||
speed: &Beltspeed,
|
||||
nextfree: &mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> + use<> {
|
||||
match belt {
|
||||
PathField::Belt { pos, dir } => {
|
||||
*nextfree += 1;
|
||||
vec![
|
||||
BlueprintEntity::builder(
|
||||
speed.string(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
*nextfree += 2;
|
||||
let endpos = pos.in_direction(dir, *len as PositionType);
|
||||
vec![
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 2,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("input".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(endpos.x as f64 + 0.5, endpos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("output".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_blueprint<'p, 's, 'n>(
|
||||
path: &'p [PathField],
|
||||
speed: &'s Beltspeed,
|
||||
nextfree: &'n mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> + use<'p, 's, 'n> {
|
||||
path.iter()
|
||||
.flat_map(|b| convert_belt_to_blueprint(b, speed, nextfree))
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
use base64::prelude::*;
|
||||
use clap::Parser;
|
||||
use factorio_blueprint::blueprint::{decode, encode};
|
||||
use factorio_blueprint::{decode, encode};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
|
||||
pub mod misc;
|
||||
|
||||
pub mod structs;
|
||||
pub mod belt;
|
||||
|
||||
pub use structs::*;
|
||||
|
||||
pub mod balancer;
|
||||
pub mod belt;
|
||||
pub mod station;
|
||||
pub mod train;
|
||||
|
||||
pub fn decode(s: &str) -> String {
|
||||
let raw = s.trim().as_bytes();
|
||||
assert!(raw[0] == b'0');
|
||||
|
|
@ -1,9 +1,5 @@
|
|||
use clap::ValueEnum;
|
||||
|
||||
use crate::{belt_finding::common::PathField, prelude::PositionType};
|
||||
|
||||
use super::{Blueprint, BlueprintEntity, BlueprintPosition};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
pub enum Beltspeed {
|
||||
Normal,
|
||||
|
|
@ -84,55 +80,3 @@ impl Belttype {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_belt_to_blueprint(
|
||||
belt: &PathField,
|
||||
speed: &Beltspeed,
|
||||
nextfree: &mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> {
|
||||
match belt {
|
||||
PathField::Belt { pos, dir } => {
|
||||
*nextfree += 1;
|
||||
vec![BlueprintEntity::builder(
|
||||
speed.string(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.direction(dir.get_index() * 4)
|
||||
.build()]
|
||||
.into_iter()
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
*nextfree += 2;
|
||||
let endpos = pos.in_direction(dir, *len as PositionType);
|
||||
vec![
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 2,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("input".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(endpos.x as f64 + 0.5, endpos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("output".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_blueprint<'p, 's, 'n>(
|
||||
path: &'p [PathField],
|
||||
speed: &'s Beltspeed,
|
||||
nextfree: &'n mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> + use<'p, 's, 'n> {
|
||||
path.iter()
|
||||
.flat_map(|b| convert_belt_to_blueprint(b, speed, nextfree))
|
||||
}
|
||||
16
factorio-core/Cargo.toml
Normal file
16
factorio-core/Cargo.toml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
[package]
|
||||
name = "factorio-core"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
||||
[dependencies]
|
||||
image = "0.25.5"
|
||||
proptest = "1.5.0"
|
||||
proptest-derive = "0.5.0"
|
||||
rand = "0.8.5"
|
||||
serde = { version = "1.0.217", features = ["derive"] }
|
||||
termcolor = "1.4.1"
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
pub mod belt_finding;
|
||||
pub mod blueprint;
|
||||
pub mod common;
|
||||
pub mod graph;
|
||||
pub mod layout;
|
||||
pub mod misc;
|
||||
pub mod priority_queue;
|
||||
pub mod aabb;
|
||||
pub mod block;
|
||||
pub mod color;
|
||||
pub mod direction;
|
||||
pub mod pathfield;
|
||||
pub mod position;
|
||||
pub mod transformation;
|
||||
pub mod visualize;
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::common::{
|
||||
pub use crate::{
|
||||
aabb::AABB,
|
||||
block::Block,
|
||||
direction::Direction,
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use super::Visualization;
|
||||
use crate::{common::visualize::Symbol, prelude::Direction};
|
||||
use crate::{prelude::Direction, visualize::Symbol};
|
||||
use image::{GenericImage, Rgba, RgbaImage};
|
||||
|
||||
pub(super) fn draw<I: GenericImage<Pixel = Rgba<u8>>>(v: &Visualization, image: &mut I) {
|
||||
31
factorio-pathfinding/Cargo.toml
Normal file
31
factorio-pathfinding/Cargo.toml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[package]
|
||||
name = "factorio-pathfinding"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3"
|
||||
|
||||
[[bench]]
|
||||
name = "bruteforce"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
factorio-core = { path = "../factorio-core" }
|
||||
factorio-blueprint = { path = "../factorio-blueprint" }
|
||||
base64 = "0.21.5"
|
||||
bon = "3.0.2"
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
flate2 = "1.0.28"
|
||||
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"
|
||||
termcolor = "1.4.1"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
|
||||
use factorio_blueprint::belt_finding::brute_force::problems::{mid, simple, snake};
|
||||
use factorio_pathfinding::belt_finding::brute_force::problems::{mid, simple, snake};
|
||||
|
||||
macro_rules! bench_bruteforce {
|
||||
($b:ident; $i:ident) => {
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
use std::io;
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use factorio_blueprint::{
|
||||
belt_finding::brute_force::{problems, Bruteforce},
|
||||
common::visualize::Visualize,
|
||||
};
|
||||
use factorio_core::visualize::Visualize;
|
||||
use factorio_pathfinding::belt_finding::brute_force::{problems, Bruteforce};
|
||||
use std::io;
|
||||
|
||||
#[derive(ValueEnum, Clone)]
|
||||
enum Mode {
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use clap::Parser;
|
||||
use factorio_blueprint::blueprint;
|
||||
use factorio_blueprint::{decode, BlueprintString};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
|
@ -12,10 +12,10 @@ fn main() {
|
|||
|
||||
let s = std::fs::read_to_string(args.blueprint).unwrap();
|
||||
|
||||
let raw = blueprint::decode(s.trim_end());
|
||||
let raw = decode(s.trim_end());
|
||||
// println!("{}", &raw);
|
||||
|
||||
let bp = serde_json::from_str::<blueprint::structs::BlueprintString>(&raw).unwrap();
|
||||
let bp = serde_json::from_str::<BlueprintString>(&raw).unwrap();
|
||||
|
||||
dbg!(&bp);
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
use factorio_blueprint::priority_queue::{fibonacci_heap::FibonacciHeap, PriorityQueue};
|
||||
use factorio_pathfinding::priority_queue::{fibonacci_heap::FibonacciHeap, PriorityQueue};
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn test_loop<P>()
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use super::{common::PathField, Position};
|
||||
use crate::prelude::*;
|
||||
use crate::{common::visualize::Visualize, misc::Map};
|
||||
use factorio_core::{pathfield::PathField, prelude::*, visualize::Visualize};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::misc::Map;
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct BruteforceField {
|
||||
pub blocked: bool,
|
||||
|
|
@ -590,8 +590,8 @@ impl Bruteforce {
|
|||
}
|
||||
|
||||
impl Visualize for Bruteforce {
|
||||
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||
fn visualize(&self) -> factorio_core::visualize::Visualization {
|
||||
let mut v = factorio_core::visualize::Visualization::new(Position::new(
|
||||
self.map.width as i32,
|
||||
self.map.height as i32,
|
||||
));
|
||||
|
|
@ -601,8 +601,8 @@ impl Visualize for Bruteforce {
|
|||
if self.map.get(x, y).blocked {
|
||||
v.add_symbol(
|
||||
Position::new(x as i32, y as i32),
|
||||
crate::common::visualize::Symbol::Block,
|
||||
Some(crate::common::visualize::Color::white()),
|
||||
factorio_core::visualize::Symbol::Block,
|
||||
Some(factorio_core::visualize::Color::white()),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -615,22 +615,22 @@ impl Visualize for Bruteforce {
|
|||
PathField::Belt { pos, dir } => {
|
||||
v.add_symbol(
|
||||
*pos,
|
||||
crate::common::visualize::Symbol::Arrow(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::Arrow(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
v.add_symbol(
|
||||
*pos,
|
||||
crate::common::visualize::Symbol::ArrowEnter(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::ArrowEnter(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
v.add_symbol(
|
||||
pos.in_direction(dir, *len as i32),
|
||||
crate::common::visualize::Symbol::ArrowExit(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::ArrowExit(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -638,11 +638,11 @@ impl Visualize for Bruteforce {
|
|||
}
|
||||
v.add_symbol(
|
||||
problem.end_pos,
|
||||
crate::common::visualize::Symbol::Char(match problem.finished {
|
||||
factorio_core::visualize::Symbol::Char(match problem.finished {
|
||||
true => 'T',
|
||||
false => 't',
|
||||
}),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
use super::{common::PathField, Problem};
|
||||
use crate::blueprint::belt::{convert_to_blueprint, Beltspeed};
|
||||
use crate::blueprint::BlueprintEntity;
|
||||
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
||||
use crate::{common::visualize::Visualize, prelude::*};
|
||||
use factorio_blueprint::{belt::convert_to_blueprint, misc::Beltspeed, BlueprintEntity};
|
||||
use factorio_core::{pathfield::PathField, prelude::*, visualize::Visualize};
|
||||
use std::{
|
||||
ops::RangeInclusive,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use super::Problem;
|
||||
|
||||
#[derive(Default)]
|
||||
struct Field {
|
||||
blocked: bool,
|
||||
|
|
@ -510,8 +510,8 @@ impl ConflictAvoidance {
|
|||
}
|
||||
|
||||
impl Visualize for ConflictAvoidance {
|
||||
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||
fn visualize(&self) -> factorio_core::visualize::Visualization {
|
||||
let mut v = factorio_core::visualize::Visualization::new(Position::new(
|
||||
self.map.width as i32,
|
||||
self.map.height as i32,
|
||||
));
|
||||
|
|
@ -526,8 +526,8 @@ impl Visualize for ConflictAvoidance {
|
|||
|
||||
v.add_symbol(
|
||||
Position::new(x as i32, y as i32),
|
||||
crate::common::visualize::Symbol::Block,
|
||||
Some(crate::common::visualize::Color::white()),
|
||||
factorio_core::visualize::Symbol::Block,
|
||||
Some(factorio_core::visualize::Color::white()),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -555,22 +555,22 @@ impl Visualize for ConflictAvoidance {
|
|||
PathField::Belt { pos, dir } => {
|
||||
v.add_symbol(
|
||||
*pos,
|
||||
crate::common::visualize::Symbol::Arrow(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::Arrow(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
v.add_symbol(
|
||||
*pos,
|
||||
crate::common::visualize::Symbol::ArrowEnter(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::ArrowEnter(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
v.add_symbol(
|
||||
pos.in_direction(dir, *len as i32),
|
||||
crate::common::visualize::Symbol::ArrowExit(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::ArrowExit(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
|
@ -583,7 +583,7 @@ impl Visualize for ConflictAvoidance {
|
|||
for y in yrange.clone() {
|
||||
v.overwrite_background(
|
||||
Position::new(x, y),
|
||||
Some(crate::common::visualize::Color::new(150, 150, 0)),
|
||||
Some(factorio_core::visualize::Color::new(150, 150, 0)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -594,7 +594,7 @@ impl Visualize for ConflictAvoidance {
|
|||
if conflicts.get(x, y) > &1 {
|
||||
v.overwrite_background(
|
||||
Position::new(x as i32, y as i32),
|
||||
Some(crate::common::visualize::Color::new(100, 80, 80)),
|
||||
Some(factorio_core::visualize::Color::new(100, 80, 80)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,13 @@
|
|||
use crate::common::visualize::Visualize;
|
||||
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
||||
use crate::graph::wheighted_graph::WheightedGraph;
|
||||
use crate::layout::Layout;
|
||||
use crate::misc::Map;
|
||||
use crate::prelude::*;
|
||||
use crate::priority_queue::BinaryHeap;
|
||||
use factorio_core::{prelude::*, visualize::Visualize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod brute_force;
|
||||
pub mod common;
|
||||
|
||||
pub mod conflict_avoidance;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
|
||||
|
|
@ -128,8 +127,8 @@ impl Problem {
|
|||
}
|
||||
|
||||
impl Visualize for Problem {
|
||||
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||
fn visualize(&self) -> factorio_core::visualize::Visualization {
|
||||
let mut v = factorio_core::visualize::Visualization::new(Position::new(
|
||||
self.map.width as i32,
|
||||
self.map.height as i32,
|
||||
));
|
||||
|
|
@ -139,8 +138,8 @@ impl Visualize for Problem {
|
|||
if self.map.get(x, y).blocked {
|
||||
v.add_symbol(
|
||||
Position::new(x as i32, y as i32),
|
||||
crate::common::visualize::Symbol::Block,
|
||||
Some(crate::common::visualize::Color::white()),
|
||||
factorio_core::visualize::Symbol::Block,
|
||||
Some(factorio_core::visualize::Color::white()),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
|
@ -150,8 +149,8 @@ impl Visualize for Problem {
|
|||
for (i, (p, _d)) in self.start.iter().enumerate() {
|
||||
v.add_symbol(
|
||||
*p,
|
||||
crate::common::visualize::Symbol::Char('S'),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::Char('S'),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
|
@ -159,8 +158,8 @@ impl Visualize for Problem {
|
|||
for (i, (p, _d)) in self.end.iter().enumerate() {
|
||||
v.add_symbol(
|
||||
*p,
|
||||
crate::common::visualize::Symbol::Char('T'),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::Char('T'),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
|
@ -169,8 +168,8 @@ impl Visualize for Problem {
|
|||
for (pos, dir) in p {
|
||||
v.add_symbol(
|
||||
*pos,
|
||||
crate::common::visualize::Symbol::Arrow(*dir),
|
||||
Some(crate::common::visualize::Color::index(i)),
|
||||
factorio_core::visualize::Symbol::Arrow(*dir),
|
||||
Some(factorio_core::visualize::Color::index(i)),
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
|
@ -252,7 +251,7 @@ impl Problem {
|
|||
|
||||
pub mod problems {
|
||||
use super::Problem;
|
||||
use crate::prelude::*;
|
||||
use factorio_core::prelude::*;
|
||||
|
||||
pub fn simple() -> Problem {
|
||||
let mut p = Problem::new(5, 3);
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use factorio_blueprint::{
|
||||
belt_finding::{conflict_avoidance::ConflictAvoidance, problems, Problem},
|
||||
blueprint::{Blueprint, BlueprintString},
|
||||
common::visualize::Visualize,
|
||||
use factorio_blueprint::{encode, misc::Beltspeed, Blueprint, BlueprintString};
|
||||
use factorio_core::visualize::Visualize;
|
||||
use factorio_pathfinding::belt_finding::{
|
||||
conflict_avoidance::ConflictAvoidance, problems, Problem,
|
||||
};
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
|
|
@ -49,10 +49,7 @@ struct Args {
|
|||
|
||||
fn output_blueprint(conflict: &ConflictAvoidance) {
|
||||
let mut offset = 0;
|
||||
let belts = conflict.belt_blueprint(
|
||||
&factorio_blueprint::blueprint::belt::Beltspeed::Normal,
|
||||
&mut offset,
|
||||
);
|
||||
let belts = conflict.belt_blueprint(&Beltspeed::Normal, &mut offset);
|
||||
|
||||
let bp = BlueprintString::Blueprint(
|
||||
Blueprint::builder()
|
||||
|
|
@ -61,10 +58,7 @@ fn output_blueprint(conflict: &ConflictAvoidance) {
|
|||
.build(),
|
||||
);
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&bp).unwrap())
|
||||
);
|
||||
println!("{}", encode(&serde_json::to_string(&bp).unwrap()));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
use clap::Parser;
|
||||
use factorio_blueprint::{
|
||||
belt_finding::{conflict_avoidance::ConflictAvoidance, Problem},
|
||||
common::visualize::{image_grid, Visualize},
|
||||
};
|
||||
use factorio_core::visualize::image_grid;
|
||||
use factorio_core::visualize::Visualize;
|
||||
use factorio_pathfinding::belt_finding::{conflict_avoidance::ConflictAvoidance, Problem};
|
||||
use std::{fs::File, path::PathBuf};
|
||||
|
||||
#[derive(Parser)]
|
||||
98
factorio-pathfinding/src/bin/layout.rs
Normal file
98
factorio-pathfinding/src/bin/layout.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use factorio_core::visualize::Visualize;
|
||||
use factorio_pathfinding::layout::{genetic_algorithm2, GeneticAlgorithm, PathLayout};
|
||||
use miette::{Context, IntoDiagnostic, Result};
|
||||
use rand::{rngs::SmallRng, SeedableRng};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
#[clap(short, long, default_value_t = 0)]
|
||||
seed: u64,
|
||||
|
||||
problem: PathBuf,
|
||||
|
||||
#[command(subcommand)]
|
||||
subcommand: Commands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
V1,
|
||||
V2,
|
||||
Bench {
|
||||
#[clap(short, long, default_value_t = 100)]
|
||||
runs: usize,
|
||||
|
||||
#[clap(short, long, default_value_t = 100)]
|
||||
mutations: usize,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut rng = SmallRng::seed_from_u64(args.seed);
|
||||
let file = std::fs::File::open(args.problem)
|
||||
.into_diagnostic()
|
||||
.context("Failed to open problem file.")?;
|
||||
let p = serde_yaml::from_reader(file)
|
||||
.into_diagnostic()
|
||||
.context("Failed to parse yaml.")?;
|
||||
|
||||
match args.subcommand {
|
||||
Commands::V1 => {
|
||||
let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng);
|
||||
|
||||
for i in 0..100 {
|
||||
println!("Generatrion {i}");
|
||||
g.generation(&mut rng);
|
||||
}
|
||||
|
||||
g.output_population();
|
||||
}
|
||||
Commands::V2 => {
|
||||
let mut m: Option<PathLayout> = None;
|
||||
for _ in 0..20 {
|
||||
let g = genetic_algorithm2(&p, 10, 320, 10000, &mut rng);
|
||||
|
||||
g.print_visualization();
|
||||
if m.as_ref().is_none_or(|m| g.score() < m.score()) {
|
||||
m = Some(g);
|
||||
}
|
||||
}
|
||||
|
||||
m.unwrap().print_visualization();
|
||||
}
|
||||
Commands::Bench { runs, mutations } => {
|
||||
let mut map = Vec::new();
|
||||
|
||||
let mut m: Option<PathLayout> = None;
|
||||
let start = std::time::Instant::now();
|
||||
for _ in 0..runs {
|
||||
let g = genetic_algorithm2(&p, 1, mutations, mutations, &mut rng);
|
||||
|
||||
map.push(g.score());
|
||||
if m.as_ref().is_none_or(|m| g.score() < m.score()) {
|
||||
m = Some(g);
|
||||
}
|
||||
}
|
||||
|
||||
println!("Time: {:.2}", start.elapsed().as_secs_f32());
|
||||
|
||||
let mean = map.iter().sum::<usize>() / runs;
|
||||
println!("Mean: {}", mean);
|
||||
let min = map.iter().min().unwrap();
|
||||
println!("Min: {}", min);
|
||||
let max = map.iter().max().unwrap();
|
||||
println!("Max: {}", max);
|
||||
let stddev =
|
||||
((map.iter().map(|v| (v - mean) * (v - mean)).sum::<usize>() / runs) as f64).sqrt();
|
||||
println!("Stddev: {:.1}", stddev);
|
||||
|
||||
m.unwrap().print_visualization();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::belt_finding::common::PathField;
|
||||
use crate::belt_finding::conflict_avoidance::ConflictAvoidance;
|
||||
use crate::common::visualize::{image_grid, Color, Symbol, Visualization, Visualize};
|
||||
use crate::prelude::*;
|
||||
use factorio_core::pathfield::PathField;
|
||||
use factorio_core::prelude::*;
|
||||
use factorio_core::visualize::{image_grid, Color, Symbol, Visualization, Visualize};
|
||||
use rand::{seq::SliceRandom, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
|
@ -241,7 +241,7 @@ impl<'a> PathLayout<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Visualize for PathLayout<'a> {
|
||||
fn visualize(&self) -> Visualization {
|
||||
fn visualize(&self) -> factorio_core::visualize::Visualization {
|
||||
let mut v = self.layout.visualize();
|
||||
let offset = self.layout.blocks.len();
|
||||
|
||||
5
factorio-pathfinding/src/lib.rs
Normal file
5
factorio-pathfinding/src/lib.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
pub mod belt_finding;
|
||||
pub mod graph;
|
||||
pub mod layout;
|
||||
pub mod misc;
|
||||
pub mod priority_queue;
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
use factorio_blueprint::blueprint::{balancer::generate_4_lane_balancer, BlueprintString};
|
||||
|
||||
fn main() {
|
||||
let b = BlueprintString::Blueprint(generate_4_lane_balancer());
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&b).unwrap());
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap())
|
||||
);
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use factorio_blueprint::{
|
||||
common::visualize::Visualize,
|
||||
layout::{genetic_algorithm2, GeneticAlgorithm, PathLayout},
|
||||
};
|
||||
use miette::{Context, IntoDiagnostic, Result};
|
||||
use rand::{rngs::SmallRng, SeedableRng};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
#[clap(short, long, default_value_t = 0)]
|
||||
seed: u64,
|
||||
|
||||
problem: PathBuf,
|
||||
|
||||
#[command(subcommand)]
|
||||
subcommand: Commands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Commands {
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut rng = SmallRng::seed_from_u64(args.seed);
|
||||
let file = std::fs::File::open(args.problem)
|
||||
.into_diagnostic()
|
||||
.context("Failed to open problem file.")?;
|
||||
let p = serde_yaml::from_reader(file)
|
||||
.into_diagnostic()
|
||||
.context("Failed to parse yaml.")?;
|
||||
|
||||
match args.subcommand {
|
||||
Commands::V1 => {
|
||||
let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng);
|
||||
|
||||
for i in 0..100 {
|
||||
println!("Generatrion {i}");
|
||||
g.generation(&mut rng);
|
||||
}
|
||||
|
||||
g.output_population();
|
||||
}
|
||||
Commands::V2 => {
|
||||
let mut m: Option<PathLayout> = None;
|
||||
for _ in 0..20 {
|
||||
let g = genetic_algorithm2(&p, 10, 320, &mut rng);
|
||||
|
||||
g.print_visualization();
|
||||
if m.as_ref().is_none_or(|m| g.score() < m.score()) {
|
||||
m = Some(g);
|
||||
}
|
||||
}
|
||||
|
||||
m.unwrap().print_visualization();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
pub mod aabb;
|
||||
pub mod block;
|
||||
pub mod color;
|
||||
pub mod direction;
|
||||
pub mod position;
|
||||
pub mod transformation;
|
||||
pub mod visualize;
|
||||
Loading…
Add table
Add a link
Reference in a new issue