Use PositionType for position
This commit is contained in:
parent
2e9c699600
commit
207a0436d8
4 changed files with 283 additions and 194 deletions
|
|
@ -5,7 +5,7 @@ use colored::Colorize;
|
||||||
use crate::misc::Map;
|
use crate::misc::Map;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
common::{Dimension, Direction, PathField},
|
common::{Dimension, Direction, PathField, PositionType},
|
||||||
Position, COLORS,
|
Position, COLORS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -64,8 +64,10 @@ impl BruteforceBuilder {
|
||||||
};
|
};
|
||||||
|
|
||||||
for [start, end] in self.path {
|
for [start, end] in self.path {
|
||||||
b.map.get_mut(start.0.x, start.0.y).blocked = true;
|
b.map
|
||||||
b.map.get_mut(end.0.x, end.0.y).blocked = true;
|
.get_mut(start.0.x as usize, start.0.y as usize)
|
||||||
|
.blocked = true;
|
||||||
|
b.map.get_mut(end.0.x as usize, end.0.y as usize).blocked = true;
|
||||||
b.problems.push(Problem {
|
b.problems.push(Problem {
|
||||||
path: vec![PathField::Belt {
|
path: vec![PathField::Belt {
|
||||||
pos: start.0,
|
pos: start.0,
|
||||||
|
|
@ -111,25 +113,32 @@ impl Bruteforce {
|
||||||
self.pointer_stack.last().copied().unwrap_or(0)
|
self.pointer_stack.last().copied().unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Path field must be valid and inside bounds.
|
||||||
fn internal_apply_path_field(&mut self, i: usize, path_field: PathField) {
|
fn internal_apply_path_field(&mut self, i: usize, path_field: PathField) {
|
||||||
match &path_field {
|
match &path_field {
|
||||||
PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = true,
|
PathField::Belt { pos, dir: _ } => {
|
||||||
|
self.map.get_mut(pos.x as usize, pos.y as usize).blocked = true
|
||||||
|
}
|
||||||
PathField::Underground { pos, dir, len } => {
|
PathField::Underground { pos, dir, len } => {
|
||||||
self.map.get_mut(pos.x, pos.y).blocked = true;
|
self.map.get_mut(pos.x as usize, pos.y as usize).blocked = true;
|
||||||
|
|
||||||
for i in 0..=*len {
|
for i in 0..=*len {
|
||||||
let mid_pos = pos.in_direction(dir, i.into(), &self.dimension).unwrap();
|
let mid_pos = pos.in_direction(dir, i as PositionType);
|
||||||
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 as usize, mid_pos.y as usize)
|
||||||
|
.underground_vertical = true;
|
||||||
} else {
|
} else {
|
||||||
self.map
|
self.map
|
||||||
.get_mut(mid_pos.x, mid_pos.y)
|
.get_mut(mid_pos.x as usize, mid_pos.y as usize)
|
||||||
.underground_horizontal = true;
|
.underground_horizontal = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let end_pos = { pos.in_direction(dir, *len as usize, &self.dimension) }.unwrap();
|
let end_pos = pos.in_direction(dir, *len as PositionType);
|
||||||
self.map.get_mut(end_pos.x, end_pos.y).blocked = true;
|
self.map
|
||||||
|
.get_mut(end_pos.x as usize, end_pos.y as usize)
|
||||||
|
.blocked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.problems[i].path.push(path_field);
|
self.problems[i].path.push(path_field);
|
||||||
|
|
@ -137,23 +146,29 @@ impl Bruteforce {
|
||||||
|
|
||||||
fn internal_remove_path_field(&mut self, i: usize) {
|
fn internal_remove_path_field(&mut self, i: usize) {
|
||||||
match self.problems[i].path.pop().unwrap() {
|
match self.problems[i].path.pop().unwrap() {
|
||||||
PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = false,
|
PathField::Belt { pos, dir: _ } => {
|
||||||
|
self.map.get_mut(pos.x as usize, pos.y as usize).blocked = false
|
||||||
|
}
|
||||||
PathField::Underground { pos, dir, len } => {
|
PathField::Underground { pos, dir, len } => {
|
||||||
self.map.get_mut(pos.x, pos.y).blocked = false;
|
self.map.get_mut(pos.x as usize, pos.y as usize).blocked = false;
|
||||||
|
|
||||||
for i in 0..=len {
|
for i in 0..=len {
|
||||||
let mid_pos = pos.in_direction(&dir, i.into(), &self.dimension).unwrap();
|
let mid_pos = pos.in_direction(&dir, i as PositionType);
|
||||||
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 as usize, mid_pos.y as usize)
|
||||||
|
.underground_vertical = false;
|
||||||
} else {
|
} else {
|
||||||
self.map
|
self.map
|
||||||
.get_mut(mid_pos.x, mid_pos.y)
|
.get_mut(mid_pos.x as usize, mid_pos.y as usize)
|
||||||
.underground_horizontal = false;
|
.underground_horizontal = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let end_pos = pos.in_direction(&dir, len.into(), &self.dimension).unwrap();
|
let end_pos = pos.in_direction(&dir, len.into());
|
||||||
self.map.get_mut(end_pos.x, end_pos.y).blocked = false;
|
self.map
|
||||||
|
.get_mut(end_pos.x as usize, end_pos.y as usize)
|
||||||
|
.blocked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -199,17 +214,25 @@ 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 = pos
|
let end_pos = pos.in_direction(dir, *len as PositionType);
|
||||||
.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 as usize, end_pos.y as usize)
|
||||||
|
.blocked = true;
|
||||||
|
|
||||||
for l in 0..=*len {
|
for l in 0..=*len {
|
||||||
let p = pos.in_direction(dir, l as usize, &self.dimension).unwrap();
|
let p = pos.in_direction(dir, l as PositionType);
|
||||||
match dir.vertical() {
|
match dir.vertical() {
|
||||||
true => self.map.get_mut(p.x, p.y).underground_vertical = true,
|
true => {
|
||||||
false => self.map.get_mut(p.x, p.y).underground_horizontal = true,
|
self.map
|
||||||
|
.get_mut(p.x as usize, p.y as usize)
|
||||||
|
.underground_vertical = true
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
self.map
|
||||||
|
.get_mut(p.x as usize, p.y as usize)
|
||||||
|
.underground_horizontal = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -235,23 +258,31 @@ impl Bruteforce {
|
||||||
len: new_len,
|
len: new_len,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
let last_end_pos = pos
|
let last_end_pos = pos.in_direction(&dir, last_len as PositionType);
|
||||||
.in_direction(&dir, last_len as usize, &self.dimension)
|
let new_end_pos = pos.in_direction(&dir, *new_len as PositionType);
|
||||||
.unwrap();
|
|
||||||
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;
|
self.map
|
||||||
self.map.get_mut(new_end_pos.x, new_end_pos.y).blocked = true;
|
.get_mut(last_end_pos.x as usize, last_end_pos.y as usize)
|
||||||
|
.blocked = false;
|
||||||
|
self.map
|
||||||
|
.get_mut(new_end_pos.x as usize, new_end_pos.y as usize)
|
||||||
|
.blocked = true;
|
||||||
|
|
||||||
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 = pos.in_direction(&dir, l as usize, &self.dimension).unwrap();
|
let p = pos.in_direction(&dir, l as PositionType);
|
||||||
match dir.vertical() {
|
match dir.vertical() {
|
||||||
true => self.map.get_mut(p.x, p.y).underground_vertical = true,
|
true => {
|
||||||
false => self.map.get_mut(p.x, p.y).underground_horizontal = true,
|
self.map
|
||||||
|
.get_mut(p.x as usize, p.y as usize)
|
||||||
|
.underground_vertical = true
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
self.map
|
||||||
|
.get_mut(p.x as usize, p.y as usize)
|
||||||
|
.underground_horizontal = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -268,18 +299,18 @@ 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 } => pos
|
PathField::Belt { pos, dir } => Some(pos.in_direction(dir, 1))
|
||||||
.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 } => pos
|
|
||||||
.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()
|
||||||
})
|
})
|
||||||
.is_some(),
|
.is_some(),
|
||||||
|
PathField::Underground { pos, dir, len } => {
|
||||||
|
Some(pos.in_direction(dir, *len as PositionType + 1))
|
||||||
|
.filter(|p| {
|
||||||
|
p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse()
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,28 +321,49 @@ impl Bruteforce {
|
||||||
|
|
||||||
if len == 2
|
if len == 2
|
||||||
&& match dir.vertical() {
|
&& match dir.vertical() {
|
||||||
true => self.map.get(pos.x, pos.y).underground_vertical,
|
true => {
|
||||||
false => self.map.get(pos.x, pos.y).underground_horizontal,
|
self.map
|
||||||
|
.get(pos.x as usize, pos.y as usize)
|
||||||
|
.underground_vertical
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
self.map
|
||||||
|
.get(pos.x as usize, pos.y as usize)
|
||||||
|
.underground_horizontal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let end_pos = match pos.in_direction(dir, len as usize, &self.dimension) {
|
let binding = pos.in_direction(dir, len as PositionType);
|
||||||
Some(s) => s,
|
let end_pos = match binding.in_range(
|
||||||
None => {
|
&Position::new(0, 0),
|
||||||
return false;
|
&Position::new(
|
||||||
}
|
self.map.width as PositionType,
|
||||||
|
self.map.height as PositionType,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if match dir.vertical() {
|
if match dir.vertical() {
|
||||||
true => self.map.get(end_pos.x, end_pos.y).underground_vertical,
|
true => {
|
||||||
false => self.map.get(end_pos.x, end_pos.y).underground_horizontal,
|
self.map
|
||||||
|
.get(end_pos.x as usize, end_pos.y as usize)
|
||||||
|
.underground_vertical
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
self.map
|
||||||
|
.get(end_pos.x as usize, end_pos.y as usize)
|
||||||
|
.underground_horizontal
|
||||||
|
}
|
||||||
} {
|
} {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.map.get(end_pos.x, end_pos.y).blocked {
|
if !self.map.get(end_pos.x as usize, end_pos.y as usize).blocked {
|
||||||
self.modify_path_field(PathField::Underground {
|
self.modify_path_field(PathField::Underground {
|
||||||
pos: *pos,
|
pos: *pos,
|
||||||
dir: *dir,
|
dir: *dir,
|
||||||
|
|
@ -395,12 +447,7 @@ 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
|
let (p, d) = self.modify_path().last().unwrap().end_pos();
|
||||||
.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;
|
||||||
|
|
@ -411,12 +458,7 @@ 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
|
let (p, d) = self.modify_path().last().unwrap().end_pos();
|
||||||
.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;
|
||||||
|
|
@ -449,22 +491,32 @@ 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();
|
||||||
{ pos.in_direction(dir, 1, &self.dimension) }
|
pos.in_direction(dir, 1)
|
||||||
.filter(|p| !self.map.get(p.x, p.y).blocked || self.problems[i].end_pos == *p)
|
.in_range(
|
||||||
|
&Position::new(0, 0),
|
||||||
|
&Position::new(
|
||||||
|
self.map.width as PositionType,
|
||||||
|
self.map.height as PositionType,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(|&p| {
|
||||||
|
!self.map.get(p.x as usize, p.y as usize).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
|
let (pos, dir) = self.add_path().last().unwrap().end_pos();
|
||||||
.add_path()
|
|
||||||
.last()
|
|
||||||
.unwrap()
|
|
||||||
.end_pos(&self.dimension)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(p) = pos.in_direction(&dir, 1, &self.dimension) {
|
if let Some(&p) = pos.in_direction(&dir, 1).in_range(
|
||||||
if !self.map.get(p.x, p.y).blocked {
|
&Position::new(0, 0),
|
||||||
|
&Position::new(
|
||||||
|
self.map.width as PositionType,
|
||||||
|
self.map.height as PositionType,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
if !self.map.get(p.x as usize, p.y as usize).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);
|
||||||
}
|
}
|
||||||
|
|
@ -555,33 +607,53 @@ impl Display for Bruteforce {
|
||||||
|
|
||||||
for (i, problem) in self.problems.iter().enumerate() {
|
for (i, problem) in self.problems.iter().enumerate() {
|
||||||
if problem.finished {
|
if problem.finished {
|
||||||
m.set(problem.end_pos.x, problem.end_pos.y, Some((i, "T")));
|
m.set(
|
||||||
|
problem.end_pos.x as usize,
|
||||||
|
problem.end_pos.y as usize,
|
||||||
|
Some((i, "T")),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
m.set(problem.end_pos.x, problem.end_pos.y, Some((i, "t")));
|
m.set(
|
||||||
|
problem.end_pos.x as usize,
|
||||||
|
problem.end_pos.y as usize,
|
||||||
|
Some((i, "t")),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for p in &problem.path {
|
for p in &problem.path {
|
||||||
match p {
|
match p {
|
||||||
PathField::Belt { pos, dir } => match dir {
|
PathField::Belt { pos, dir } => match dir {
|
||||||
Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))),
|
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))),
|
||||||
Direction::Right => m.set(pos.x, pos.y, Some((i, "→"))),
|
Direction::Right => m.set(pos.x as usize, pos.y as usize, Some((i, "→"))),
|
||||||
Direction::Down => m.set(pos.x, pos.y, Some((i, "↓"))),
|
Direction::Down => m.set(pos.x as usize, pos.y as usize, Some((i, "↓"))),
|
||||||
Direction::Left => m.set(pos.x, pos.y, Some((i, "←"))),
|
Direction::Left => m.set(pos.x as usize, pos.y as usize, Some((i, "←"))),
|
||||||
},
|
},
|
||||||
PathField::Underground { pos, dir, len } => {
|
PathField::Underground { pos, dir, len } => {
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up => m.set(pos.x, pos.y, Some((i, "↟"))),
|
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))),
|
||||||
Direction::Right => m.set(pos.x, pos.y, Some((i, "↠"))),
|
Direction::Right => {
|
||||||
Direction::Down => m.set(pos.x, pos.y, Some((i, "↡"))),
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↠")))
|
||||||
Direction::Left => m.set(pos.x, pos.y, Some((i, "↞"))),
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↡")))
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↞")))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let end_pos = pos
|
let end_pos = pos.in_direction(dir, *len as PositionType);
|
||||||
.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 => {
|
||||||
Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, "↦"))),
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↥")))
|
||||||
Direction::Down => m.set(end_pos.x, end_pos.y, Some((i, "↧"))),
|
}
|
||||||
Direction::Left => m.set(end_pos.x, end_pos.y, Some((i, "↤"))),
|
Direction::Right => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↦")))
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↧")))
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↤")))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub type PositionType = i32;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Up,
|
Up,
|
||||||
|
|
@ -65,8 +67,8 @@ impl Direction {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub x: usize,
|
pub x: PositionType,
|
||||||
pub y: usize,
|
pub y: PositionType,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -76,27 +78,34 @@ pub struct Dimension {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
pub fn new(x: usize, y: usize) -> Self {
|
pub fn new(x: PositionType, y: PositionType) -> Self {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_direction(
|
pub fn in_direction(&self, dir: &Direction, len: PositionType) -> Position {
|
||||||
&self,
|
|
||||||
dir: &Direction,
|
|
||||||
len: usize,
|
|
||||||
dimension: &Dimension,
|
|
||||||
) -> Option<Position> {
|
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up => self.y.checked_sub(len).map(|y| Position::new(self.x, y)),
|
Direction::Up => Position::new(self.x, self.y - len),
|
||||||
Direction::Right => Some(self.x + len)
|
Direction::Right => Position::new(self.x + len, self.y),
|
||||||
.filter(|&x| x < dimension.width)
|
Direction::Down => Position::new(self.x, self.y + len),
|
||||||
.map(|x| Position::new(x, self.y)),
|
Direction::Left => Position::new(self.x - len, 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)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Copy)]
|
#[derive(Clone, Debug, Copy)]
|
||||||
|
|
@ -135,29 +144,23 @@ impl PathField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end_pos(&self, dimension: &Dimension) -> Option<(Position, Direction)> {
|
pub fn end_pos(&self) -> (Position, Direction) {
|
||||||
match self {
|
match self {
|
||||||
PathField::Belt { pos, dir } => Some((*pos, *dir)),
|
PathField::Belt { pos, dir } => (*pos, *dir),
|
||||||
PathField::Underground { pos, dir, len } => pos
|
PathField::Underground { pos, dir, len } => {
|
||||||
.in_direction(dir, *len as usize, dimension)
|
(pos.in_direction(dir, *len as PositionType), *dir)
|
||||||
.map(|p| (p, *dir)),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset(&self, offset: (i32, i32)) -> Self {
|
pub fn offset(&self, offset: &Position) -> Self {
|
||||||
match self {
|
match self {
|
||||||
PathField::Belt { pos, dir } => PathField::Belt {
|
PathField::Belt { pos, dir } => PathField::Belt {
|
||||||
pos: Position::new(
|
pos: Position::new(pos.x + offset.x, pos.y + offset.y),
|
||||||
(pos.x as i32 + offset.0) as usize,
|
|
||||||
(pos.y as i32 + offset.1) as usize,
|
|
||||||
),
|
|
||||||
dir: *dir,
|
dir: *dir,
|
||||||
},
|
},
|
||||||
PathField::Underground { pos, dir, len } => PathField::Underground {
|
PathField::Underground { pos, dir, len } => PathField::Underground {
|
||||||
pos: Position::new(
|
pos: Position::new(pos.x + offset.x, pos.y + offset.y),
|
||||||
(pos.x as i32 + offset.0) as usize,
|
|
||||||
(pos.y as i32 + offset.1) as usize,
|
|
||||||
),
|
|
||||||
dir: *dir,
|
dir: *dir,
|
||||||
len: *len,
|
len: *len,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use std::{fmt::Display, ops::RangeInclusive};
|
use std::{fmt::Display, ops::RangeInclusive};
|
||||||
|
|
||||||
|
use clap::builder::PathBufValueParser;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
common::{Dimension, Direction, PathField, Position},
|
common::{Dimension, Direction, PathField, Position, PositionType},
|
||||||
Problem, COLORS,
|
Problem, COLORS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -90,20 +91,13 @@ impl ConflictAvoidance {
|
||||||
for path in &self.belts {
|
for path in &self.belts {
|
||||||
for p in path {
|
for p in path {
|
||||||
match p {
|
match p {
|
||||||
PathField::Belt { pos, dir: _ } => *conflicts.get_mut(pos.x, pos.y) += 1,
|
PathField::Belt { pos, dir: _ } => {
|
||||||
|
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1
|
||||||
|
}
|
||||||
PathField::Underground { pos, dir, len } => {
|
PathField::Underground { pos, dir, len } => {
|
||||||
*conflicts.get_mut(pos.x, pos.y) += 1;
|
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1;
|
||||||
let end = pos
|
let end = pos.in_direction(dir, *len as PositionType);
|
||||||
.in_direction(
|
*conflicts.get_mut(end.x as usize, end.y as usize) += 1;
|
||||||
dir,
|
|
||||||
*len as usize,
|
|
||||||
&Dimension {
|
|
||||||
width: self.map.width,
|
|
||||||
height: self.map.height,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
*conflicts.get_mut(end.x, end.y) += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -181,13 +175,17 @@ impl ConflictAvoidance {
|
||||||
let s = path
|
let s = path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.pos())
|
.map(|p| p.pos())
|
||||||
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
.position(|p| {
|
||||||
|
xrange.contains(&(p.x as usize)) && yrange.contains(&(p.y as usize))
|
||||||
|
})
|
||||||
.map(|i| i.saturating_sub(1));
|
.map(|i| i.saturating_sub(1));
|
||||||
let e = path
|
let e = path
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.pos())
|
.map(|p| p.pos())
|
||||||
.rev()
|
.rev()
|
||||||
.position(|p| xrange.contains(&p.x) && yrange.contains(&p.y))
|
.position(|p| {
|
||||||
|
xrange.contains(&(p.x as usize)) && yrange.contains(&(p.y as usize))
|
||||||
|
})
|
||||||
.map(|i| usize::min(path.len() - 1, path.len() - i));
|
.map(|i| usize::min(path.len() - 1, path.len() - i));
|
||||||
|
|
||||||
if let Some((start, mut end)) = s.zip(e) {
|
if let Some((start, mut end)) = s.zip(e) {
|
||||||
|
|
@ -198,12 +196,7 @@ impl ConflictAvoidance {
|
||||||
|
|
||||||
mapping.push((i, start, end));
|
mapping.push((i, start, end));
|
||||||
|
|
||||||
let (start_pos, start_dir) = path[start]
|
let (start_pos, start_dir) = path[start].end_pos();
|
||||||
.end_pos(&Dimension {
|
|
||||||
width: self.map.width,
|
|
||||||
height: self.map.height,
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
let end_pos = path[end].pos();
|
let end_pos = path[end].pos();
|
||||||
let end_dir = path[end].dir();
|
let end_dir = path[end].dir();
|
||||||
|
|
||||||
|
|
@ -213,15 +206,15 @@ impl ConflictAvoidance {
|
||||||
b.add_path(
|
b.add_path(
|
||||||
(
|
(
|
||||||
Position::new(
|
Position::new(
|
||||||
start_pos.x - (xrange.start() - 1),
|
start_pos.x - (*xrange.start() as i32 - 1),
|
||||||
start_pos.y - (yrange.start() - 1),
|
start_pos.y - (*yrange.start() as i32 - 1),
|
||||||
),
|
),
|
||||||
start_dir,
|
start_dir,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Position::new(
|
Position::new(
|
||||||
end_pos.x - (xrange.start() - 1),
|
end_pos.x - (*xrange.start() as i32 - 1),
|
||||||
end_pos.y - (yrange.start() - 1),
|
end_pos.y - (*yrange.start() as i32 - 1),
|
||||||
),
|
),
|
||||||
*end_dir,
|
*end_dir,
|
||||||
),
|
),
|
||||||
|
|
@ -255,7 +248,10 @@ impl ConflictAvoidance {
|
||||||
|
|
||||||
t.extend_from_slice(&self.belts[index][0..=start]);
|
t.extend_from_slice(&self.belts[index][0..=start]);
|
||||||
t.extend(p[1..].iter().map(|p| {
|
t.extend(p[1..].iter().map(|p| {
|
||||||
p.offset(((*xrange.start() as i32) - 1, (*yrange.start() as i32) - 1))
|
p.offset(&Position::new(
|
||||||
|
(*xrange.start() as i32) - 1,
|
||||||
|
(*yrange.start() as i32) - 1,
|
||||||
|
))
|
||||||
}));
|
}));
|
||||||
t.extend_from_slice(&self.belts[index][end..]);
|
t.extend_from_slice(&self.belts[index][end..]);
|
||||||
// println!("{:?}", &t);
|
// println!("{:?}", &t);
|
||||||
|
|
@ -305,39 +301,44 @@ impl Display for ConflictAvoidance {
|
||||||
for p in problem {
|
for p in problem {
|
||||||
match p {
|
match p {
|
||||||
PathField::Belt { pos, dir } => match dir {
|
PathField::Belt { pos, dir } => match dir {
|
||||||
Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))),
|
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))),
|
||||||
Direction::Right => m.set(pos.x, pos.y, Some((i, "→"))),
|
Direction::Right => m.set(pos.x as usize, pos.y as usize, Some((i, "→"))),
|
||||||
Direction::Down => m.set(pos.x, pos.y, Some((i, "↓"))),
|
Direction::Down => m.set(pos.x as usize, pos.y as usize, Some((i, "↓"))),
|
||||||
Direction::Left => m.set(pos.x, pos.y, Some((i, "←"))),
|
Direction::Left => m.set(pos.x as usize, pos.y as usize, Some((i, "←"))),
|
||||||
},
|
},
|
||||||
PathField::Underground { pos, dir, len } => {
|
PathField::Underground { pos, dir, len } => {
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up => m.set(pos.x, pos.y, Some((i, "↟"))),
|
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))),
|
||||||
Direction::Right => m.set(pos.x, pos.y, Some((i, "↠"))),
|
Direction::Right => {
|
||||||
Direction::Down => m.set(pos.x, pos.y, Some((i, "↡"))),
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↠")))
|
||||||
Direction::Left => m.set(pos.x, pos.y, Some((i, "↞"))),
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↡")))
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
m.set(pos.x as usize, pos.y as usize, Some((i, "↞")))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let end_pos = pos
|
let end_pos = pos.in_direction(dir, *len as PositionType);
|
||||||
.in_direction(
|
|
||||||
dir,
|
|
||||||
*len as usize,
|
|
||||||
&Dimension {
|
|
||||||
width: self.map.width,
|
|
||||||
height: self.map.height,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
match dir {
|
match dir {
|
||||||
Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, "↥"))),
|
Direction::Up => {
|
||||||
Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, "↦"))),
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↥")))
|
||||||
Direction::Down => m.set(end_pos.x, end_pos.y, Some((i, "↧"))),
|
}
|
||||||
Direction::Left => m.set(end_pos.x, end_pos.y, Some((i, "↤"))),
|
Direction::Right => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↦")))
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↧")))
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↤")))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let last_pos = problem.last().unwrap().pos();
|
let last_pos = problem.last().unwrap().pos();
|
||||||
m.set(last_pos.x, last_pos.y, Some((i, "T")));
|
m.set(last_pos.x as usize, last_pos.y as usize, Some((i, "T")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print body
|
// Print body
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ 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;
|
use self::common::{Position, PositionType};
|
||||||
|
|
||||||
pub mod brute_force;
|
pub mod brute_force;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
@ -69,17 +69,17 @@ impl Problem {
|
||||||
for (i, path) in self.path.iter().enumerate() {
|
for (i, path) in self.path.iter().enumerate() {
|
||||||
if i != without {
|
if i != without {
|
||||||
for p in path {
|
for p in path {
|
||||||
self.map.get_mut(p.x, p.y).wheight += 50.0;
|
self.map.get_mut(p.x as usize, p.y as usize).wheight += 50.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in &self.start {
|
for p in &self.start {
|
||||||
self.map.get_mut(p.x, p.y).wheight += 200.0;
|
self.map.get_mut(p.x as usize, p.y as usize).wheight += 200.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in &self.end {
|
for p in &self.end {
|
||||||
self.map.get_mut(p.x, p.y).wheight += 200.0;
|
self.map.get_mut(p.x as usize, p.y as usize).wheight += 200.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -124,13 +124,21 @@ impl Display for Problem {
|
||||||
write!(f, "{:1$}", y, height_digits as usize)?;
|
write!(f, "{:1$}", y, height_digits as usize)?;
|
||||||
|
|
||||||
for x in 0..self.map.width {
|
for x in 0..self.map.width {
|
||||||
if let Some(i) = self.start.iter().position(|p| p == &Position::new(x, y)) {
|
if let Some(i) = self
|
||||||
|
.start
|
||||||
|
.iter()
|
||||||
|
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||||
|
{
|
||||||
write!(f, "{}", "s".color(COLORS[i]))?;
|
write!(f, "{}", "s".color(COLORS[i]))?;
|
||||||
} else if let Some(i) = self.end.iter().position(|p| p == &Position::new(x, y)) {
|
} else if let Some(i) = self
|
||||||
|
.end
|
||||||
|
.iter()
|
||||||
|
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||||
|
{
|
||||||
write!(f, "{}", "t".color(COLORS[i]))?;
|
write!(f, "{}", "t".color(COLORS[i]))?;
|
||||||
} else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| {
|
} else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| {
|
||||||
v.iter()
|
v.iter()
|
||||||
.position(|p| p == &Position::new(x, y))
|
.position(|p| p == &Position::new(x as PositionType, y as PositionType))
|
||||||
.map(|j| (i, j))
|
.map(|j| (i, j))
|
||||||
}) {
|
}) {
|
||||||
if self.path[i][p].x < self.path[i][p + 1].x {
|
if self.path[i][p].x < self.path[i][p + 1].x {
|
||||||
|
|
@ -164,19 +172,24 @@ struct MapInternal<'a> {
|
||||||
|
|
||||||
impl<'a> MapInternal<'a> {
|
impl<'a> MapInternal<'a> {
|
||||||
fn get_direction(&self, pos: Position) -> [Option<Position>; 4] {
|
fn get_direction(&self, pos: Position) -> [Option<Position>; 4] {
|
||||||
|
let min = Position::new(0, 0);
|
||||||
|
let max = Position::new(
|
||||||
|
self.map.width as PositionType,
|
||||||
|
self.map.height as PositionType,
|
||||||
|
);
|
||||||
[
|
[
|
||||||
(pos.x > 0)
|
Position::new(pos.x - 1, pos.y)
|
||||||
.then_some((pos.x.saturating_sub(1), pos.y))
|
.in_range(&min, &max)
|
||||||
.map(|(x, y)| Position::new(x, y)),
|
.copied(),
|
||||||
(pos.x < self.map.width - 1)
|
Position::new(pos.x + 1, pos.y)
|
||||||
.then_some((pos.x + 1, pos.y))
|
.in_range(&min, &max)
|
||||||
.map(|(x, y)| Position::new(x, y)),
|
.copied(),
|
||||||
(pos.y > 0)
|
Position::new(pos.x, pos.y - 1)
|
||||||
.then_some((pos.x, pos.y.saturating_sub(1)))
|
.in_range(&min, &max)
|
||||||
.map(|(x, y)| Position::new(x, y)),
|
.copied(),
|
||||||
(pos.y < self.map.height - 1)
|
Position::new(pos.x, pos.y + 1)
|
||||||
.then_some((pos.x, pos.y + 1))
|
.in_range(&min, &max)
|
||||||
.map(|(x, y)| Position::new(x, y)),
|
.copied(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +198,7 @@ impl<'a> WheightedGraph for MapInternal<'a> {
|
||||||
type Node = Position;
|
type Node = Position;
|
||||||
|
|
||||||
fn num_edges(&self, node: &Self::Node) -> usize {
|
fn num_edges(&self, node: &Self::Node) -> usize {
|
||||||
if self.map.get(node.x, node.y).blocked {
|
if self.map.get(node.x as usize, node.y as usize).blocked {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
let t = self.get_direction(*node);
|
let t = self.get_direction(*node);
|
||||||
|
|
@ -202,7 +215,7 @@ impl<'a> WheightedGraph for MapInternal<'a> {
|
||||||
t.iter()
|
t.iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.nth(num)
|
.nth(num)
|
||||||
.map(|&p| (p, self.map.get(p.x, p.y).wheight))
|
.map(|&p| (p, self.map.get(p.x as usize, p.y as usize).wheight))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue