Refactor common types.

This commit is contained in:
hal8174 2024-08-21 20:56:03 +02:00
parent f284b692cc
commit 48419b4674
14 changed files with 376 additions and 250 deletions

42
Cargo.lock generated
View file

@ -272,6 +272,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "factorio_blueprint"
version = "0.1.0"
@ -283,6 +289,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"serde_yaml",
"termcolor",
]
@ -313,6 +320,12 @@ version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
version = "0.5.0"
@ -328,6 +341,16 @@ dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -596,6 +619,19 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "strsim"
version = "0.11.0"
@ -653,6 +689,12 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "utf8parse"
version = "0.2.1"

View file

@ -22,4 +22,5 @@ flate2 = "1.0.28"
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"

View file

@ -1,20 +1,23 @@
use factorio_blueprint::{
belt_finding::common::Position,
layout::{Layout, Problem},
};
use factorio_blueprint::layout::Layout;
use rand::SeedableRng;
fn main() {
let mut p = Problem::new(Position::new(10, 10));
// let mut p = Problem::new(Position::new(10, 10));
let b1 = p.add_block(Position::new(3, 2));
let b2 = p.add_block(Position::new(5, 2));
let b3 = p.add_block(Position::new(5, 7));
// let b1 = p.add_block(Position::new(3, 2));
// let b2 = p.add_block(Position::new(5, 2));
// let b3 = p.add_block(Position::new(5, 7));
p.add_connection(b1, Position::new(0, 0), b2, Position::new(0, 0));
p.add_connection(b2, Position::new(3, 1), b3, Position::new(4, 6));
// p.add_connection(b1, Position::new(1, 0), b2, Position::new(1, 0));
// p.add_connection(b2, Position::new(3, 1), b3, Position::new(4, 6));
for i in 0..10 {
let file = std::fs::File::open("layout.yml").unwrap();
let p = serde_yaml::from_reader(file).unwrap();
dbg!(&p);
for i in 0..1 {
let mut rng = rand::rngs::SmallRng::seed_from_u64(i);
let l = Layout::new(&p, &mut rng);

40
layout.yml Normal file
View file

@ -0,0 +1,40 @@
size:
x: 10
y: 10
blocks:
- size:
x: 3
y: 2
input:
- offset:
x: 1
y: 1
dir: Down
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: Left
output:
connections:
- startblock: 1
startpoint: 0
endblock: 0
endpoint: 0

View file

@ -1,8 +1,9 @@
use super::{
common::{print_map, Direction, PathField, PositionType},
Position, COLORS,
common::{print_map, PathField},
Position,
};
use crate::misc::Map;
use crate::prelude::*;
use termcolor::ColorSpec;
#[derive(Default, Debug, Clone)]
@ -651,7 +652,7 @@ impl Bruteforce {
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
if let Some((i, c)) = m.get(x as usize, y as usize) {
let mut color = ColorSpec::new();
color.set_fg(Some(COLORS[*i]));
color.set_fg(Some(crate::common::color::COLORS[*i]));
(color, *c)
} else if self.map.get(x as usize, y as usize).blocked {
(ColorSpec::new(), "#")

View file

@ -1,170 +1,8 @@
use core::panic;
use std::io::{self, Write};
use rand::prelude::Distribution;
use termcolor::{ColorSpec, StandardStream, WriteColor};
pub type PositionType = i32;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Direction {
Up,
Right,
Down,
Left,
}
impl Direction {
pub fn from_neighbors(pos: &Position, neighbor: &Position) -> Self {
let x_diff = pos.x as i64 - neighbor.x as i64;
let y_diff = pos.y as i64 - neighbor.y as i64;
match (x_diff, y_diff) {
(1, 0) => Direction::Left,
(0, 1) => Direction::Up,
(-1, 0) => Direction::Right,
(0, -1) => Direction::Down,
_ => {
panic!("Positions are not neighbors.")
}
}
}
pub fn vertical(&self) -> bool {
match self {
Direction::Up => true,
Direction::Right => false,
Direction::Down => true,
Direction::Left => false,
}
}
pub fn horizontal(&self) -> bool {
!self.vertical()
}
pub fn reverse(&self) -> Self {
match self {
Direction::Up => Direction::Down,
Direction::Right => Direction::Left,
Direction::Down => Direction::Up,
Direction::Left => Direction::Right,
}
}
pub fn clockwise(&self) -> Self {
match self {
Direction::Up => Direction::Right,
Direction::Right => Direction::Down,
Direction::Down => Direction::Left,
Direction::Left => Direction::Up,
}
}
pub fn counter_clockwise(&self) -> Self {
match self {
Direction::Up => Direction::Left,
Direction::Right => Direction::Up,
Direction::Down => Direction::Right,
Direction::Left => Direction::Down,
}
}
pub fn get_index(&self) -> u8 {
match self {
Direction::Up => 0,
Direction::Right => 1,
Direction::Down => 2,
Direction::Left => 3,
}
}
pub fn from_index(i: u8) -> Self {
match i {
0 => Direction::Up,
1 => Direction::Right,
2 => Direction::Down,
3 => Direction::Left,
_ => panic!(),
}
}
}
impl Distribution<Direction> for rand::distributions::Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Direction {
let a = [
Direction::Up,
Direction::Right,
Direction::Down,
Direction::Left,
];
let r = rng.gen_range(0..4);
a[r]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Position {
pub x: PositionType,
pub y: PositionType,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Dimension {
pub width: usize,
pub height: usize,
}
impl Position {
pub fn new(x: PositionType, y: PositionType) -> Self {
Self { x, y }
}
pub fn in_direction(&self, dir: &Direction, len: PositionType) -> Position {
match dir {
Direction::Up => Position::new(self.x, self.y - len),
Direction::Right => Position::new(self.x + len, self.y),
Direction::Down => Position::new(self.x, self.y + len),
Direction::Left => Position::new(self.x - len, self.y),
}
}
pub fn in_range(&self, min: &Position, max: &Position) -> Option<&Position> {
if self.x < min.x {
return None;
}
if self.x >= max.x {
return None;
}
if self.y < min.y {
return None;
}
if self.y >= max.y {
return None;
}
Some(self)
}
}
impl std::ops::Add for Position {
type Output = Position;
fn add(mut self, rhs: Self) -> Self::Output {
self.x += rhs.x;
self.y += rhs.y;
self
}
}
impl std::ops::Sub for Position {
type Output = Position;
fn sub(mut self, rhs: Self) -> Self::Output {
self.x -= rhs.x;
self.y -= rhs.y;
self
}
}
use crate::prelude::*;
#[derive(Clone, Debug, Copy)]
pub enum PathField {

View file

@ -1,7 +1,8 @@
use super::{
common::{print_map, Direction, PathField, Position, PositionType},
Problem, COLORS,
common::{print_map, PathField},
Problem,
};
use crate::prelude::*;
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
use std::ops::RangeInclusive;
use termcolor::ColorSpec;
@ -520,7 +521,7 @@ impl ConflictAvoidance {
}
if let Some((i, c)) = m.get(x as usize, y as usize) {
color.set_fg(Some(COLORS[*i]));
color.set_fg(Some(crate::common::color::COLORS[*i]));
(color, c)
} else if self.map.get(x as usize, y as usize).blocked {
(color, "#")

View file

@ -1,12 +1,13 @@
use crate::common::color::COLORS;
use crate::graph::wheighted_graph::WheightedGraph;
use crate::misc::Map;
use crate::{
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
};
use std::ops::Index;
use termcolor::{Color, ColorSpec};
use termcolor::ColorSpec;
use self::common::{print_map, Direction, Position, PositionType};
use self::common::print_map;
use crate::prelude::*;
pub mod brute_force;
pub mod common;
@ -128,25 +129,6 @@ impl Problem {
}
}
pub static COLORS: Cyclic<Color, 6> = Cyclic([
Color::Red,
Color::Green,
Color::Yellow,
Color::Blue,
Color::Magenta,
Color::Cyan,
]);
pub struct Cyclic<T, const N: usize>([T; N]);
impl<T, const N: usize> Index<usize> for Cyclic<T, N> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index % N]
}
}
struct MapInternal<'a> {
map: &'a Map<Field>,
end: (Position, Direction),
@ -215,10 +197,8 @@ impl Problem {
}
pub mod problems {
use super::{
common::{Direction, Position},
Problem,
};
use super::Problem;
use crate::prelude::*;
pub fn simple() -> Problem {
let mut p = Problem::new(5, 3);

21
src/common/color.rs Normal file
View file

@ -0,0 +1,21 @@
use std::ops::Index;
use termcolor::Color;
pub static COLORS: Cyclic<Color, 6> = Cyclic([
Color::Red,
Color::Green,
Color::Yellow,
Color::Blue,
Color::Magenta,
Color::Cyan,
]);
pub struct Cyclic<T, const N: usize>([T; N]);
impl<T, const N: usize> Index<usize> for Cyclic<T, N> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index % N]
}
}

99
src/common/direction.rs Normal file
View file

@ -0,0 +1,99 @@
use crate::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Deserialize, Serialize)]
pub enum Direction {
Up,
Right,
Down,
Left,
}
impl Direction {
pub fn from_neighbors(pos: &Position, neighbor: &Position) -> Self {
let x_diff = pos.x as i64 - neighbor.x as i64;
let y_diff = pos.y as i64 - neighbor.y as i64;
match (x_diff, y_diff) {
(1, 0) => Direction::Left,
(0, 1) => Direction::Up,
(-1, 0) => Direction::Right,
(0, -1) => Direction::Down,
_ => {
panic!("Positions are not neighbors.")
}
}
}
pub fn vertical(&self) -> bool {
match self {
Direction::Up => true,
Direction::Right => false,
Direction::Down => true,
Direction::Left => false,
}
}
pub fn horizontal(&self) -> bool {
!self.vertical()
}
pub fn reverse(&self) -> Self {
match self {
Direction::Up => Direction::Down,
Direction::Right => Direction::Left,
Direction::Down => Direction::Up,
Direction::Left => Direction::Right,
}
}
pub fn clockwise(&self) -> Self {
match self {
Direction::Up => Direction::Right,
Direction::Right => Direction::Down,
Direction::Down => Direction::Left,
Direction::Left => Direction::Up,
}
}
pub fn counter_clockwise(&self) -> Self {
match self {
Direction::Up => Direction::Left,
Direction::Right => Direction::Up,
Direction::Down => Direction::Right,
Direction::Left => Direction::Down,
}
}
pub fn get_index(&self) -> u8 {
match self {
Direction::Up => 0,
Direction::Right => 1,
Direction::Down => 2,
Direction::Left => 3,
}
}
pub fn from_index(i: u8) -> Self {
match i {
0 => Direction::Up,
1 => Direction::Right,
2 => Direction::Down,
3 => Direction::Left,
_ => panic!(),
}
}
}
impl rand::prelude::Distribution<Direction> for rand::distributions::Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Direction {
let a = [
Direction::Up,
Direction::Right,
Direction::Down,
Direction::Left,
];
let r = rng.gen_range(0..4);
a[r]
}
}

3
src/common/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod color;
pub mod direction;
pub mod position;

67
src/common/position.rs Normal file
View file

@ -0,0 +1,67 @@
use crate::prelude::*;
use serde::{Deserialize, Serialize};
pub type PositionType = i32;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct Position {
pub x: PositionType,
pub y: PositionType,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Dimension {
pub width: usize,
pub height: usize,
}
impl Position {
pub fn new(x: PositionType, y: PositionType) -> Self {
Self { x, y }
}
pub fn in_direction(&self, dir: &Direction, len: PositionType) -> Position {
match dir {
Direction::Up => Position::new(self.x, self.y - len),
Direction::Right => Position::new(self.x + len, self.y),
Direction::Down => Position::new(self.x, self.y + len),
Direction::Left => Position::new(self.x - len, self.y),
}
}
pub fn in_range(&self, min: &Position, max: &Position) -> Option<&Position> {
if self.x < min.x {
return None;
}
if self.x >= max.x {
return None;
}
if self.y < min.y {
return None;
}
if self.y >= max.y {
return None;
}
Some(self)
}
}
impl std::ops::Add for Position {
type Output = Position;
fn add(mut self, rhs: Self) -> Self::Output {
self.x += rhs.x;
self.y += rhs.y;
self
}
}
impl std::ops::Sub for Position {
type Output = Position;
fn sub(mut self, rhs: Self) -> Self::Output {
self.x -= rhs.x;
self.y -= rhs.y;
self
}
}

View file

@ -1,32 +1,36 @@
use crate::{
belt_finding::{
common::{print_map, Direction, Position},
COLORS,
},
misc::Map,
};
use crate::prelude::*;
use crate::{belt_finding::common::print_map, misc::Map};
use rand::Rng;
use serde::{Deserialize, Serialize};
use termcolor::ColorSpec;
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
struct Block {
size: Position,
input: Vec<Interface>,
output: Vec<Interface>,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
struct Interface {
offset: Position,
// dir: Direction,
target: (usize, usize),
dir: Direction,
}
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
struct Connection {
startblock: usize,
startpoint: usize,
endblock: usize,
endpoint: usize,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Problem {
size: Position,
blocks: Vec<Block>,
connections: Vec<Connection>,
}
#[derive(Debug, Clone, Copy)]
@ -43,6 +47,7 @@ impl Problem {
Self {
size,
blocks: Vec::new(),
connections: Vec::new(),
}
}
@ -56,26 +61,26 @@ impl Problem {
BlockHandle(self.blocks.len() - 1)
}
pub fn add_connection(
&mut self,
starthandle: BlockHandle,
startoffset: Position,
endhandle: BlockHandle,
endoffset: Position,
) {
let startinterface = self.blocks[starthandle.0].output.len();
let endinterface = self.blocks[endhandle.0].input.len();
// pub fn add_connection(
// &mut self,
// starthandle: BlockHandle,
// startoffset: Position,
// endhandle: BlockHandle,
// endoffset: Position,
// ) {
// let startinterface = self.blocks[starthandle.0].output.len();
// let endinterface = self.blocks[endhandle.0].input.len();
self.blocks[starthandle.0].output.push(Interface {
offset: startoffset,
target: (endhandle.0, endinterface),
});
// self.blocks[starthandle.0].output.push(Interface {
// offset: startoffset,
// target: (endhandle.0, endinterface),
// });
self.blocks[endhandle.0].input.push(Interface {
offset: endoffset,
target: (starthandle.0, startinterface),
})
}
// self.blocks[endhandle.0].input.push(Interface {
// offset: endoffset,
// target: (starthandle.0, startinterface),
// })
// }
}
impl Layout<'_> {
@ -176,17 +181,20 @@ impl Layout<'_> {
pub fn score(&self) -> i32 {
let mut sum = 0;
for ((pos, dir), b) in self.blocks.iter().zip(self.problem.blocks.iter()) {
for i in &b.output {
let startpos = Self::transform(*pos, *dir, i.offset);
let endpos = Self::transform(
self.blocks[i.target.0].0,
self.blocks[i.target.0].1,
self.problem.blocks[i.target.0].input[i.target.1].offset,
);
sum += (startpos.x - endpos.x).abs() + (startpos.y - endpos.y).abs();
}
for c in &self.problem.connections {
let startpos = Self::transform(
self.blocks[c.startblock].0,
self.blocks[c.startblock].1,
self.problem.blocks[c.startblock].output[c.startpoint].offset,
);
let endpos = Self::transform(
self.blocks[c.endblock].0,
self.blocks[c.endblock].1,
self.problem.blocks[c.endblock].input[c.endpoint].offset,
);
sum += (startpos.x - endpos.x).abs() + (startpos.y - endpos.y).abs();
}
sum
@ -202,7 +210,7 @@ impl Layout<'_> {
}
pub fn print(&self) {
let mut m: Map<Option<usize>> =
let mut m: Map<Option<(usize, &str)>> =
Map::new(self.problem.size.x as usize, self.problem.size.y as usize);
for (i, ((p, d), b)) in self
@ -215,16 +223,32 @@ impl Layout<'_> {
for x in npos.x..(npos.x + nsize.x) {
for y in npos.y..(npos.y + nsize.y) {
m.set(x as usize, y as usize, Some(i));
m.set(x as usize, y as usize, Some((i, "#")));
}
}
let pos = Self::transform(*p, *d, Position::new(0, 0));
m.set(pos.x as usize, pos.y as usize, Some((i, "X")));
for input in &b.input {
let pos = Self::transform(*p, *d, input.offset);
m.set(pos.x as usize, pos.y as usize, Some((i, "i")));
}
for output in &b.output {
let pos = Self::transform(*p, *d, output.offset);
m.set(pos.x as usize, pos.y as usize, Some((i, "o")));
}
}
let _ = print_map(self.problem.size.x, self.problem.size.y, |x, y| {
if let Some(i) = m.get(x as usize, y as usize) {
let mut color = ColorSpec::new();
color.set_fg(Some(COLORS[*i]));
(color, "#")
color.set_fg(Some(crate::common::color::COLORS[i.0]));
(color, i.1)
} else {
(ColorSpec::new(), " ")
}

View file

@ -1,6 +1,12 @@
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 prelude {
pub use crate::common::direction::Direction;
pub use crate::common::position::{Position, PositionType};
}