Refactor Direction and Position.

This commit is contained in:
hal8174 2024-01-14 14:28:45 +01:00
parent 2bdfd8cc6c
commit 9751764611
6 changed files with 206 additions and 220 deletions

View file

@ -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);
// }
}

View file

@ -1,4 +1,4 @@
use factorio_blueprint::belt_finding::{Position, Problem}; use factorio_blueprint::belt_finding::{common::Position, Problem};
fn main() { fn main() {
let mut p = Problem::new(17, 13); let mut p = Problem::new(17, 13);

View file

@ -1,4 +1,4 @@
use factorio_blueprint::belt_finding::{Position, Problem}; use factorio_blueprint::belt_finding::{common::Position, Problem};
fn main() { fn main() {
let mut p = Problem::new(33, 13); let mut p = Problem::new(33, 13);

View file

@ -4,7 +4,10 @@ use colored::Colorize;
use crate::misc::Map; use crate::misc::Map;
use super::{Direction, Position, COLORS}; use super::{
common::{Dimension, Direction, PathField},
Position, COLORS,
};
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct BruteforceField { pub struct BruteforceField {
@ -13,43 +16,6 @@ pub struct BruteforceField {
underground_horizontal: bool, 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; static MAX_UNDERGROUND_LENGTH: u8 = 6;
#[derive(Clone)] #[derive(Clone)]
@ -83,12 +49,18 @@ impl BruteforceBuilder {
} }
pub fn build(self) -> Bruteforce { pub fn build(self) -> Bruteforce {
let dimension = Dimension {
width: self.map.width,
height: self.map.height,
};
let mut b = Bruteforce { let mut b = Bruteforce {
map: self.map, map: self.map,
problems: Vec::new(), problems: Vec::new(),
pointer_stack: vec![0], pointer_stack: vec![0],
solution_count: 0, solution_count: 0,
count: 0, count: 0,
dimension,
}; };
for [start, end] in self.path { for [start, end] in self.path {
@ -120,6 +92,7 @@ struct Problem {
#[derive(Clone)] #[derive(Clone)]
pub struct Bruteforce { pub struct Bruteforce {
map: Map<BruteforceField>, map: Map<BruteforceField>,
dimension: Dimension,
problems: Vec<Problem>, problems: Vec<Problem>,
pointer_stack: Vec<usize>, pointer_stack: Vec<usize>,
solution_count: u128, solution_count: u128,
@ -145,7 +118,7 @@ impl Bruteforce {
self.map.get_mut(pos.x, pos.y).blocked = true; self.map.get_mut(pos.x, pos.y).blocked = true;
for i in 0..=*len { 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() { if dir.vertical() {
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = true; self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = true;
} else { } 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; 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; self.map.get_mut(pos.x, pos.y).blocked = false;
for i in 0..=len { 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() { if dir.vertical() {
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = false; self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = false;
} else { } 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; self.map.get_mut(end_pos.x, end_pos.y).blocked = false;
} }
} }
@ -226,12 +199,14 @@ impl Bruteforce {
match (last, &path_field) { match (last, &path_field) {
(PathField::Belt { pos: _, dir: _ }, PathField::Belt { pos: _, dir: _ }) => {} (PathField::Belt { pos: _, dir: _ }, PathField::Belt { pos: _, dir: _ }) => {}
(PathField::Belt { pos: _, dir: _ }, PathField::Underground { pos, dir, len }) => { (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; self.map.get_mut(end_pos.x, end_pos.y).blocked = true;
for l in 0..=*len { 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() { match dir.vertical() {
true => self.map.get_mut(p.x, p.y).underground_vertical = true, true => self.map.get_mut(p.x, p.y).underground_vertical = true,
false => self.map.get_mut(p.x, p.y).underground_horizontal = true, false => self.map.get_mut(p.x, p.y).underground_horizontal = true,
@ -260,11 +235,11 @@ impl Bruteforce {
len: new_len, len: new_len,
}, },
) => { ) => {
let last_end_pos = self let last_end_pos = pos
.pos_in_direction(&pos, &dir, last_len as usize) .in_direction(&dir, last_len as usize, &self.dimension)
.unwrap(); .unwrap();
let new_end_pos = self let new_end_pos = pos
.pos_in_direction(&pos, &dir, *new_len as usize) .in_direction(&dir, *new_len as usize, &self.dimension)
.unwrap(); .unwrap();
self.map.get_mut(last_end_pos.x, last_end_pos.y).blocked = false; 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 { match last_len < *new_len {
true => { true => {
for l in last_len + 1..=*new_len { 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() { match dir.vertical() {
true => self.map.get_mut(p.x, p.y).underground_vertical = true, true => self.map.get_mut(p.x, p.y).underground_vertical = true,
false => self.map.get_mut(p.x, p.y).underground_horizontal = 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 { fn check_finish(&self, i: usize) -> bool {
match self.problems[i].path.last().unwrap() { match self.problems[i].path.last().unwrap() {
PathField::Belt { pos, dir } => self PathField::Belt { pos, dir } => pos
.pos_in_direction(pos, dir, 1) .in_direction(dir, 1, &self.dimension)
.filter(|p| { .filter(|p| {
p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse() p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse()
}) })
.is_some(), .is_some(),
PathField::Underground { pos, dir, len } => self PathField::Underground { pos, dir, len } => pos
.pos_in_direction(pos, dir, *len as usize + 1) .in_direction(dir, *len as usize + 1, &self.dimension)
.filter(|p| { .filter(|p| {
p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse() 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 { fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool {
if len >= MAX_UNDERGROUND_LENGTH { if len >= MAX_UNDERGROUND_LENGTH {
return false; return false;
@ -332,7 +297,7 @@ impl Bruteforce {
return false; 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, Some(s) => s,
None => { None => {
return false; return false;
@ -430,7 +395,13 @@ impl Bruteforce {
if second_last.dir().counter_clockwise() == dir if second_last.dir().counter_clockwise() == dir
&& self.modify_underground(&pos, second_last.dir(), 2) && 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) { if self.is_next_free(&p, &d) {
return true; return true;
} else { } else {
@ -440,7 +411,13 @@ impl Bruteforce {
} }
PathField::Underground { pos, dir, len } => { PathField::Underground { pos, dir, len } => {
if self.modify_underground(&pos, &dir, len + 1) { 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) { if self.is_next_free(&p, &d) {
return true; return true;
} else { } else {
@ -472,16 +449,21 @@ impl Bruteforce {
fn is_next_free(&self, pos: &Position, dir: &Direction) -> bool { fn is_next_free(&self, pos: &Position, dir: &Direction) -> bool {
let i = self.modify_pointer(); 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) .filter(|p| !self.map.get(p.x, p.y).blocked || self.problems[i].end_pos == *p)
.is_some() .is_some()
} }
// Add an Path elemeent // Add an Path elemeent
fn add(&mut self) -> bool { 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 { if !self.map.get(p.x, p.y).blocked {
self.apply_path_field(PathField::Belt { pos: p, dir }); self.apply_path_field(PathField::Belt { pos: p, dir });
return self.is_next_free(&p, &dir); return self.is_next_free(&p, &dir);
@ -535,19 +517,6 @@ impl Bruteforce {
.sum() .sum()
} }
fn pos_in_direction(&self, pos: &Position, dir: &Direction, len: usize) -> Option<Position> {
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 { pub fn count(&self) -> u128 {
self.count self.count
} }
@ -605,7 +574,9 @@ impl Display for Bruteforce {
Direction::Down => m.set(pos.x, pos.y, Some((i, ""))), Direction::Down => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Left => 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 { match dir {
Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, ""))), Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, ""))),
Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, ""))), Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, ""))),

146
src/belt_finding/common.rs Normal file
View file

@ -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<Position> {
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)),
}
}
}

View file

@ -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::shortest_path::dijkstra;
use crate::graph::wheighted_graph::WheightedGraph; use crate::graph::wheighted_graph::WheightedGraph;
use crate::misc::Map; use crate::misc::Map;
@ -6,83 +6,10 @@ use crate::priority_queue::BinaryHeap;
use colored::{Color, Colorize}; use colored::{Color, Colorize};
use std::fmt::Display; use std::fmt::Display;
use self::common::Position;
pub mod brute_force; pub mod brute_force;
pub mod common;
#[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 }
}
}
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
pub struct Field { pub struct Field {