From 975176461157c96a0c65931829fd64850ea45186 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 14 Jan 2024 14:28:45 +0100 Subject: [PATCH] Refactor Direction and Position. --- examples/brute_force2.rs | 58 ------------- examples/solve_belt.rs | 2 +- examples/solve_belt2.rs | 2 +- src/belt_finding/brute_force.rs | 137 ++++++++++++------------------ src/belt_finding/common.rs | 146 ++++++++++++++++++++++++++++++++ src/belt_finding/mod.rs | 81 +----------------- 6 files changed, 206 insertions(+), 220 deletions(-) delete mode 100644 examples/brute_force2.rs create mode 100644 src/belt_finding/common.rs diff --git a/examples/brute_force2.rs b/examples/brute_force2.rs deleted file mode 100644 index eedfaf3..0000000 --- a/examples/brute_force2.rs +++ /dev/null @@ -1,58 +0,0 @@ -use factorio_blueprint::belt_finding::{brute_force::BruteforceBuilder, Direction, Position}; - -fn main() { - let mut b = BruteforceBuilder::new(14, 6); - - b.add_path( - (Position::new(0, 0), Direction::Right), - (Position::new(13, 0), Direction::Right), - ); - - b.add_path( - (Position::new(0, 1), Direction::Right), - (Position::new(13, 1), Direction::Right), - ); - - b.add_path( - (Position::new(0, 2), Direction::Right), - (Position::new(13, 2), Direction::Right), - ); - - b.add_path( - (Position::new(0, 3), Direction::Right), - (Position::new(13, 3), Direction::Right), - ); - - b.add_path( - (Position::new(0, 4), Direction::Right), - (Position::new(13, 4), Direction::Right), - ); - - b.add_path( - (Position::new(0, 5), Direction::Right), - (Position::new(13, 5), Direction::Right), - ); - - // b.set_blocked_range(7, 2, 10, 2, true); - // b.set_blocked_range(7, 3, 10, 4, true); - - b.set_blocked_range(3, 2, 10, 3, true); - b.set_blocked(2, 0, true); - b.set_blocked(11, 0, true); - b.set_blocked(2, 5, true); - b.set_blocked(11, 5, true); - - let mut b = b.build(); - - println!("{}\n{}\n{}", b.count(), b.solution_count(), b); - while b.next_finish_state() { - println!("{}\n{}\n{}", b.count(), b.solution_count(), b); - } - println!("{}\n{}", b.count(), b.solution_count()); - - // println!("{}\n{}", b.count(), b); - - // while b.next_state() { - // println!("{}\n{}", b.count(), b); - // } -} diff --git a/examples/solve_belt.rs b/examples/solve_belt.rs index 5606c67..7ab99cd 100644 --- a/examples/solve_belt.rs +++ b/examples/solve_belt.rs @@ -1,4 +1,4 @@ -use factorio_blueprint::belt_finding::{Position, Problem}; +use factorio_blueprint::belt_finding::{common::Position, Problem}; fn main() { let mut p = Problem::new(17, 13); diff --git a/examples/solve_belt2.rs b/examples/solve_belt2.rs index 3f2beca..5b88e0d 100644 --- a/examples/solve_belt2.rs +++ b/examples/solve_belt2.rs @@ -1,4 +1,4 @@ -use factorio_blueprint::belt_finding::{Position, Problem}; +use factorio_blueprint::belt_finding::{common::Position, Problem}; fn main() { let mut p = Problem::new(33, 13); diff --git a/src/belt_finding/brute_force.rs b/src/belt_finding/brute_force.rs index 338695f..c2a7ad6 100644 --- a/src/belt_finding/brute_force.rs +++ b/src/belt_finding/brute_force.rs @@ -4,7 +4,10 @@ use colored::Colorize; use crate::misc::Map; -use super::{Direction, Position, COLORS}; +use super::{ + common::{Dimension, Direction, PathField}, + Position, COLORS, +}; #[derive(Default, Clone)] pub struct BruteforceField { @@ -13,43 +16,6 @@ pub struct BruteforceField { underground_horizontal: bool, } -#[derive(Clone, Debug, Copy)] -pub enum PathField { - Belt { - pos: Position, - dir: Direction, - }, - Underground { - pos: Position, - dir: Direction, - len: u8, - }, -} - -impl PathField { - fn pos(&self) -> &Position { - match self { - PathField::Belt { pos, dir: _ } => pos, - PathField::Underground { - pos, - dir: _, - len: _, - } => pos, - } - } - - fn dir(&self) -> &Direction { - match self { - PathField::Belt { pos: _, dir } => dir, - PathField::Underground { - pos: _, - dir, - len: _, - } => dir, - } - } -} - static MAX_UNDERGROUND_LENGTH: u8 = 6; #[derive(Clone)] @@ -83,12 +49,18 @@ impl BruteforceBuilder { } pub fn build(self) -> Bruteforce { + let dimension = Dimension { + width: self.map.width, + height: self.map.height, + }; + let mut b = Bruteforce { map: self.map, problems: Vec::new(), pointer_stack: vec![0], solution_count: 0, count: 0, + dimension, }; for [start, end] in self.path { @@ -120,6 +92,7 @@ struct Problem { #[derive(Clone)] pub struct Bruteforce { map: Map, + dimension: Dimension, problems: Vec, pointer_stack: Vec, solution_count: u128, @@ -145,7 +118,7 @@ impl Bruteforce { self.map.get_mut(pos.x, pos.y).blocked = true; for i in 0..=*len { - let mid_pos = self.pos_in_direction(pos, dir, i.into()).unwrap(); + let mid_pos = pos.in_direction(dir, i.into(), &self.dimension).unwrap(); if dir.vertical() { self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = true; } else { @@ -155,7 +128,7 @@ impl Bruteforce { } } - let end_pos = self.pos_in_direction(pos, dir, *len as usize).unwrap(); + let end_pos = { pos.in_direction(dir, *len as usize, &self.dimension) }.unwrap(); self.map.get_mut(end_pos.x, end_pos.y).blocked = true; } } @@ -169,7 +142,7 @@ impl Bruteforce { self.map.get_mut(pos.x, pos.y).blocked = false; for i in 0..=len { - let mid_pos = self.pos_in_direction(&pos, &dir, i.into()).unwrap(); + let mid_pos = pos.in_direction(&dir, i.into(), &self.dimension).unwrap(); if dir.vertical() { self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = false; } else { @@ -179,7 +152,7 @@ impl Bruteforce { } } - let end_pos = self.pos_in_direction(&pos, &dir, len.into()).unwrap(); + let end_pos = pos.in_direction(&dir, len.into(), &self.dimension).unwrap(); self.map.get_mut(end_pos.x, end_pos.y).blocked = false; } } @@ -226,12 +199,14 @@ impl Bruteforce { match (last, &path_field) { (PathField::Belt { pos: _, dir: _ }, PathField::Belt { pos: _, dir: _ }) => {} (PathField::Belt { pos: _, dir: _ }, PathField::Underground { pos, dir, len }) => { - let end_pos = self.pos_in_direction(pos, dir, *len as usize).unwrap(); + let end_pos = pos + .in_direction(dir, *len as usize, &self.dimension) + .unwrap(); self.map.get_mut(end_pos.x, end_pos.y).blocked = true; for l in 0..=*len { - let p = self.pos_in_direction(pos, dir, l as usize).unwrap(); + let p = pos.in_direction(dir, l as usize, &self.dimension).unwrap(); match dir.vertical() { true => self.map.get_mut(p.x, p.y).underground_vertical = true, false => self.map.get_mut(p.x, p.y).underground_horizontal = true, @@ -260,11 +235,11 @@ impl Bruteforce { len: new_len, }, ) => { - let last_end_pos = self - .pos_in_direction(&pos, &dir, last_len as usize) + let last_end_pos = pos + .in_direction(&dir, last_len as usize, &self.dimension) .unwrap(); - let new_end_pos = self - .pos_in_direction(&pos, &dir, *new_len as usize) + let new_end_pos = pos + .in_direction(&dir, *new_len as usize, &self.dimension) .unwrap(); self.map.get_mut(last_end_pos.x, last_end_pos.y).blocked = false; @@ -273,7 +248,7 @@ impl Bruteforce { match last_len < *new_len { true => { for l in last_len + 1..=*new_len { - let p = self.pos_in_direction(&pos, &dir, l as usize).unwrap(); + let p = pos.in_direction(&dir, l as usize, &self.dimension).unwrap(); match dir.vertical() { true => self.map.get_mut(p.x, p.y).underground_vertical = true, false => self.map.get_mut(p.x, p.y).underground_horizontal = true, @@ -293,14 +268,14 @@ impl Bruteforce { fn check_finish(&self, i: usize) -> bool { match self.problems[i].path.last().unwrap() { - PathField::Belt { pos, dir } => self - .pos_in_direction(pos, dir, 1) + PathField::Belt { pos, dir } => pos + .in_direction(dir, 1, &self.dimension) .filter(|p| { p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse() }) .is_some(), - PathField::Underground { pos, dir, len } => self - .pos_in_direction(pos, dir, *len as usize + 1) + PathField::Underground { pos, dir, len } => pos + .in_direction(dir, *len as usize + 1, &self.dimension) .filter(|p| { p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse() }) @@ -308,16 +283,6 @@ impl Bruteforce { } } - fn path_field_end(&self, path_field: &PathField) -> (Position, Direction) { - match path_field { - PathField::Belt { pos, dir } => (*pos, *dir), - PathField::Underground { pos, dir, len } => ( - self.pos_in_direction(pos, dir, *len as usize).unwrap(), - *dir, - ), - } - } - fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool { if len >= MAX_UNDERGROUND_LENGTH { return false; @@ -332,7 +297,7 @@ impl Bruteforce { return false; } - let end_pos = match self.pos_in_direction(pos, dir, len as usize) { + let end_pos = match pos.in_direction(dir, len as usize, &self.dimension) { Some(s) => s, None => { return false; @@ -430,7 +395,13 @@ impl Bruteforce { if second_last.dir().counter_clockwise() == dir && self.modify_underground(&pos, second_last.dir(), 2) { - let (p, d) = self.path_field_end(self.modify_path().last().unwrap()); + let (p, d) = self + .modify_path() + .last() + .unwrap() + .end_pos(&self.dimension) + .unwrap(); + if self.is_next_free(&p, &d) { return true; } else { @@ -440,7 +411,13 @@ impl Bruteforce { } PathField::Underground { pos, dir, len } => { if self.modify_underground(&pos, &dir, len + 1) { - let (p, d) = self.path_field_end(self.modify_path().last().unwrap()); + let (p, d) = self + .modify_path() + .last() + .unwrap() + .end_pos(&self.dimension) + .unwrap(); + if self.is_next_free(&p, &d) { return true; } else { @@ -472,16 +449,21 @@ impl Bruteforce { fn is_next_free(&self, pos: &Position, dir: &Direction) -> bool { let i = self.modify_pointer(); - self.pos_in_direction(pos, dir, 1) + { pos.in_direction(dir, 1, &self.dimension) } .filter(|p| !self.map.get(p.x, p.y).blocked || self.problems[i].end_pos == *p) .is_some() } // Add an Path elemeent fn add(&mut self) -> bool { - let (pos, dir) = self.path_field_end(self.add_path().last().unwrap()); + let (pos, dir) = self + .add_path() + .last() + .unwrap() + .end_pos(&self.dimension) + .unwrap(); - if let Some(p) = self.pos_in_direction(&pos, &dir, 1) { + if let Some(p) = pos.in_direction(&dir, 1, &self.dimension) { if !self.map.get(p.x, p.y).blocked { self.apply_path_field(PathField::Belt { pos: p, dir }); return self.is_next_free(&p, &dir); @@ -535,19 +517,6 @@ impl Bruteforce { .sum() } - fn pos_in_direction(&self, pos: &Position, dir: &Direction, len: usize) -> Option { - match dir { - Direction::Up => pos.y.checked_sub(len).map(|y| Position::new(pos.x, y)), - Direction::Right => Some(pos.x + len) - .filter(|&x| x < self.map.width) - .map(|x| Position::new(x, pos.y)), - Direction::Down => Some(pos.y + len) - .filter(|&y| y < self.map.height) - .map(|y| Position::new(pos.x, y)), - Direction::Left => pos.x.checked_sub(len).map(|x| Position::new(x, pos.y)), - } - } - pub fn count(&self) -> u128 { self.count } @@ -605,7 +574,9 @@ impl Display for Bruteforce { Direction::Down => m.set(pos.x, pos.y, Some((i, "↡"))), Direction::Left => m.set(pos.x, pos.y, Some((i, "↞"))), }; - let end_pos = self.pos_in_direction(pos, dir, *len as usize).unwrap(); + let end_pos = pos + .in_direction(dir, *len as usize, &self.dimension) + .unwrap(); match dir { Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, "↥"))), Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, "↦"))), diff --git a/src/belt_finding/common.rs b/src/belt_finding/common.rs new file mode 100644 index 0000000..e8b1bc9 --- /dev/null +++ b/src/belt_finding/common.rs @@ -0,0 +1,146 @@ +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Direction { + Up, + Right, + Down, + Left, +} + +impl Direction { + pub fn from_neghbors(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, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Position { + pub x: usize, + pub y: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct Dimension { + pub width: usize, + pub height: usize, +} + +impl Position { + pub fn new(x: usize, y: usize) -> Self { + Self { x, y } + } + + pub fn in_direction( + &self, + dir: &Direction, + len: usize, + dimension: &Dimension, + ) -> Option { + match dir { + Direction::Up => self.y.checked_sub(len).map(|y| Position::new(self.x, y)), + Direction::Right => Some(self.x + len) + .filter(|&x| x < dimension.width) + .map(|x| Position::new(x, self.y)), + Direction::Down => Some(self.y + len) + .filter(|&y| y < dimension.height) + .map(|y| Position::new(self.x, y)), + Direction::Left => self.x.checked_sub(len).map(|x| Position::new(x, self.y)), + } + } +} + +#[derive(Clone, Debug, Copy)] +pub enum PathField { + Belt { + pos: Position, + dir: Direction, + }, + Underground { + pos: Position, + dir: Direction, + len: u8, + }, +} + +impl PathField { + pub fn pos(&self) -> &Position { + match self { + PathField::Belt { pos, dir: _ } => pos, + PathField::Underground { + pos, + dir: _, + len: _, + } => pos, + } + } + + pub fn dir(&self) -> &Direction { + match self { + PathField::Belt { pos: _, dir } => dir, + PathField::Underground { + pos: _, + dir, + len: _, + } => dir, + } + } + + pub fn end_pos(&self, dimension: &Dimension) -> Option<(Position, Direction)> { + match self { + PathField::Belt { pos, dir } => Some((*pos, *dir)), + PathField::Underground { pos, dir, len } => pos + .in_direction(dir, *len as usize, dimension) + .map(|p| (p, *dir)), + } + } +} diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index 0880e2c..9cc61d9 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -1,4 +1,4 @@ -use crate::belt_finding::brute_force::BruteforceBuilder; +use crate::belt_finding::{brute_force::BruteforceBuilder, common::Direction}; use crate::graph::wheighted_graph::shortest_path::dijkstra; use crate::graph::wheighted_graph::WheightedGraph; use crate::misc::Map; @@ -6,83 +6,10 @@ use crate::priority_queue::BinaryHeap; use colored::{Color, Colorize}; use std::fmt::Display; +use self::common::Position; + pub mod brute_force; - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum Direction { - Up, - Right, - Down, - Left, -} - -impl Direction { - fn from_neghbors(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, - _ => { - unreachable!() - } - } - } - - fn vertical(&self) -> bool { - match self { - Direction::Up => true, - Direction::Right => false, - Direction::Down => true, - Direction::Left => false, - } - } - - // fn horizontal(&self) -> bool { - // !self.vertical() - // } - - fn reverse(&self) -> Self { - match self { - Direction::Up => Direction::Down, - Direction::Right => Direction::Left, - Direction::Down => Direction::Up, - Direction::Left => Direction::Right, - } - } - - fn clockwise(&self) -> Self { - match self { - Direction::Up => Direction::Right, - Direction::Right => Direction::Down, - Direction::Down => Direction::Left, - Direction::Left => Direction::Up, - } - } - - fn counter_clockwise(&self) -> Self { - match self { - Direction::Up => Direction::Left, - Direction::Right => Direction::Up, - Direction::Down => Direction::Right, - Direction::Left => Direction::Down, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct Position { - pub x: usize, - pub y: usize, -} -impl Position { - pub fn new(x: usize, y: usize) -> Self { - Self { x, y } - } -} +pub mod common; #[derive(Default, Clone, Copy)] pub struct Field {