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() {
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() {
let mut p = Problem::new(33, 13);

View file

@ -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<BruteforceField>,
dimension: Dimension,
problems: Vec<Problem>,
pointer_stack: Vec<usize>,
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<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 {
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, ""))),

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::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 {