diff --git a/src/belt_finding/brute_force.rs b/src/belt_finding/brute_force.rs index c2a7ad6..b182fd4 100644 --- a/src/belt_finding/brute_force.rs +++ b/src/belt_finding/brute_force.rs @@ -5,7 +5,7 @@ use colored::Colorize; use crate::misc::Map; use super::{ - common::{Dimension, Direction, PathField}, + common::{Dimension, Direction, PathField, PositionType}, Position, COLORS, }; @@ -64,8 +64,10 @@ impl BruteforceBuilder { }; for [start, end] in self.path { - b.map.get_mut(start.0.x, start.0.y).blocked = true; - b.map.get_mut(end.0.x, end.0.y).blocked = true; + b.map + .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 { path: vec![PathField::Belt { pos: start.0, @@ -111,25 +113,32 @@ impl Bruteforce { 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) { 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 } => { - 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 { - 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() { - 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 { 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; } } - 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; + let end_pos = pos.in_direction(dir, *len as PositionType); + self.map + .get_mut(end_pos.x as usize, end_pos.y as usize) + .blocked = true; } } self.problems[i].path.push(path_field); @@ -137,23 +146,29 @@ impl Bruteforce { fn internal_remove_path_field(&mut self, i: usize) { 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 } => { - 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 { - 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() { - 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 { 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; } } - let end_pos = pos.in_direction(&dir, len.into(), &self.dimension).unwrap(); - self.map.get_mut(end_pos.x, end_pos.y).blocked = false; + let end_pos = pos.in_direction(&dir, len.into()); + 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) { (PathField::Belt { pos: _, dir: _ }, PathField::Belt { pos: _, dir: _ }) => {} (PathField::Belt { pos: _, dir: _ }, PathField::Underground { pos, dir, len }) => { - 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; 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() { - true => self.map.get_mut(p.x, p.y).underground_vertical = true, - false => self.map.get_mut(p.x, p.y).underground_horizontal = true, + 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, }, ) => { - let last_end_pos = pos - .in_direction(&dir, last_len as usize, &self.dimension) - .unwrap(); - let new_end_pos = pos - .in_direction(&dir, *new_len as usize, &self.dimension) - .unwrap(); + let last_end_pos = pos.in_direction(&dir, last_len as PositionType); + let new_end_pos = pos.in_direction(&dir, *new_len as PositionType); - self.map.get_mut(last_end_pos.x, last_end_pos.y).blocked = false; - self.map.get_mut(new_end_pos.x, new_end_pos.y).blocked = true; + self.map + .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 { true => { 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() { - true => self.map.get_mut(p.x, p.y).underground_vertical = true, - false => self.map.get_mut(p.x, p.y).underground_horizontal = true, + 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 { match self.problems[i].path.last().unwrap() { - 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 } => pos - .in_direction(dir, *len as usize + 1, &self.dimension) + PathField::Belt { pos, dir } => Some(pos.in_direction(dir, 1)) .filter(|p| { p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse() }) .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 && match dir.vertical() { - true => self.map.get(pos.x, pos.y).underground_vertical, - false => self.map.get(pos.x, pos.y).underground_horizontal, + true => { + 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; } - let end_pos = match pos.in_direction(dir, len as usize, &self.dimension) { - Some(s) => s, - None => { - return false; - } + let binding = pos.in_direction(dir, len as PositionType); + let end_pos = match binding.in_range( + &Position::new(0, 0), + &Position::new( + self.map.width as PositionType, + self.map.height as PositionType, + ), + ) { + Some(t) => t, + None => return false, }; if match dir.vertical() { - true => self.map.get(end_pos.x, end_pos.y).underground_vertical, - false => self.map.get(end_pos.x, end_pos.y).underground_horizontal, + true => { + 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; } - 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 { pos: *pos, dir: *dir, @@ -395,12 +447,7 @@ impl Bruteforce { if second_last.dir().counter_clockwise() == dir && self.modify_underground(&pos, second_last.dir(), 2) { - let (p, d) = self - .modify_path() - .last() - .unwrap() - .end_pos(&self.dimension) - .unwrap(); + let (p, d) = self.modify_path().last().unwrap().end_pos(); if self.is_next_free(&p, &d) { return true; @@ -411,12 +458,7 @@ impl Bruteforce { } PathField::Underground { pos, dir, len } => { if self.modify_underground(&pos, &dir, len + 1) { - let (p, d) = self - .modify_path() - .last() - .unwrap() - .end_pos(&self.dimension) - .unwrap(); + let (p, d) = self.modify_path().last().unwrap().end_pos(); if self.is_next_free(&p, &d) { return true; @@ -449,22 +491,32 @@ impl Bruteforce { fn is_next_free(&self, pos: &Position, dir: &Direction) -> bool { let i = self.modify_pointer(); - { pos.in_direction(dir, 1, &self.dimension) } - .filter(|p| !self.map.get(p.x, p.y).blocked || self.problems[i].end_pos == *p) + pos.in_direction(dir, 1) + .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() } // Add an Path elemeent fn add(&mut self) -> bool { - let (pos, dir) = self - .add_path() - .last() - .unwrap() - .end_pos(&self.dimension) - .unwrap(); + let (pos, dir) = self.add_path().last().unwrap().end_pos(); - if let Some(p) = pos.in_direction(&dir, 1, &self.dimension) { - if !self.map.get(p.x, p.y).blocked { + if let Some(&p) = pos.in_direction(&dir, 1).in_range( + &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 }); return self.is_next_free(&p, &dir); } @@ -555,33 +607,53 @@ impl Display for Bruteforce { for (i, problem) in self.problems.iter().enumerate() { 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 { - 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 { match p { PathField::Belt { pos, dir } => match dir { - Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))), - Direction::Right => 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::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))), + Direction::Right => m.set(pos.x as usize, pos.y as usize, 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, "←"))), }, PathField::Underground { pos, dir, len } => { match dir { - Direction::Up => m.set(pos.x, pos.y, Some((i, "↟"))), - Direction::Right => 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::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))), + Direction::Right => { + m.set(pos.x as usize, pos.y as usize, 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 - .in_direction(dir, *len as usize, &self.dimension) - .unwrap(); + let end_pos = pos.in_direction(dir, *len as PositionType); 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, "↦"))), - 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::Up => { + m.set(end_pos.x as usize, end_pos.y as usize, 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, "↤"))) + } }; } } diff --git a/src/belt_finding/common.rs b/src/belt_finding/common.rs index 782303d..87ef90f 100644 --- a/src/belt_finding/common.rs +++ b/src/belt_finding/common.rs @@ -1,3 +1,5 @@ +pub type PositionType = i32; + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Direction { Up, @@ -65,8 +67,8 @@ impl Direction { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Position { - pub x: usize, - pub y: usize, + pub x: PositionType, + pub y: PositionType, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -76,27 +78,34 @@ pub struct Dimension { } impl Position { - pub fn new(x: usize, y: usize) -> Self { + pub fn new(x: PositionType, y: PositionType) -> Self { Self { x, y } } - pub fn in_direction( - &self, - dir: &Direction, - len: usize, - dimension: &Dimension, - ) -> Option { + pub fn in_direction(&self, dir: &Direction, len: PositionType) -> 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)), + 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) + } } #[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 { - PathField::Belt { pos, dir } => Some((*pos, *dir)), - PathField::Underground { pos, dir, len } => pos - .in_direction(dir, *len as usize, dimension) - .map(|p| (p, *dir)), + PathField::Belt { pos, dir } => (*pos, *dir), + PathField::Underground { pos, dir, len } => { + (pos.in_direction(dir, *len as PositionType), *dir) + } } } - pub fn offset(&self, offset: (i32, i32)) -> Self { + pub fn offset(&self, offset: &Position) -> Self { match self { PathField::Belt { pos, dir } => PathField::Belt { - pos: Position::new( - (pos.x as i32 + offset.0) as usize, - (pos.y as i32 + offset.1) as usize, - ), + pos: Position::new(pos.x + offset.x, pos.y + offset.y), dir: *dir, }, PathField::Underground { pos, dir, len } => PathField::Underground { - pos: Position::new( - (pos.x as i32 + offset.0) as usize, - (pos.y as i32 + offset.1) as usize, - ), + pos: Position::new(pos.x + offset.x, pos.y + offset.y), dir: *dir, len: *len, }, diff --git a/src/belt_finding/conflict_avoidance.rs b/src/belt_finding/conflict_avoidance.rs index ce82942..ee6599f 100644 --- a/src/belt_finding/conflict_avoidance.rs +++ b/src/belt_finding/conflict_avoidance.rs @@ -1,11 +1,12 @@ use std::{fmt::Display, ops::RangeInclusive}; +use clap::builder::PathBufValueParser; use colored::Colorize; use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map}; use super::{ - common::{Dimension, Direction, PathField, Position}, + common::{Dimension, Direction, PathField, Position, PositionType}, Problem, COLORS, }; @@ -90,20 +91,13 @@ impl ConflictAvoidance { for path in &self.belts { for p in path { 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 } => { - *conflicts.get_mut(pos.x, pos.y) += 1; - let end = pos - .in_direction( - dir, - *len as usize, - &Dimension { - width: self.map.width, - height: self.map.height, - }, - ) - .unwrap(); - *conflicts.get_mut(end.x, end.y) += 1; + *conflicts.get_mut(pos.x as usize, pos.y as usize) += 1; + let end = pos.in_direction(dir, *len as PositionType); + *conflicts.get_mut(end.x as usize, end.y as usize) += 1; } } } @@ -181,13 +175,17 @@ impl ConflictAvoidance { let s = path .iter() .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)); let e = path .iter() .map(|p| p.pos()) .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)); if let Some((start, mut end)) = s.zip(e) { @@ -198,12 +196,7 @@ impl ConflictAvoidance { mapping.push((i, start, end)); - let (start_pos, start_dir) = path[start] - .end_pos(&Dimension { - width: self.map.width, - height: self.map.height, - }) - .unwrap(); + let (start_pos, start_dir) = path[start].end_pos(); let end_pos = path[end].pos(); let end_dir = path[end].dir(); @@ -213,15 +206,15 @@ impl ConflictAvoidance { b.add_path( ( Position::new( - start_pos.x - (xrange.start() - 1), - start_pos.y - (yrange.start() - 1), + start_pos.x - (*xrange.start() as i32 - 1), + start_pos.y - (*yrange.start() as i32 - 1), ), start_dir, ), ( Position::new( - end_pos.x - (xrange.start() - 1), - end_pos.y - (yrange.start() - 1), + end_pos.x - (*xrange.start() as i32 - 1), + end_pos.y - (*yrange.start() as i32 - 1), ), *end_dir, ), @@ -255,7 +248,10 @@ impl ConflictAvoidance { t.extend_from_slice(&self.belts[index][0..=start]); 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..]); // println!("{:?}", &t); @@ -305,39 +301,44 @@ impl Display for ConflictAvoidance { for p in problem { match p { PathField::Belt { pos, dir } => match dir { - Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))), - Direction::Right => 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::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))), + Direction::Right => m.set(pos.x as usize, pos.y as usize, 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, "←"))), }, PathField::Underground { pos, dir, len } => { match dir { - Direction::Up => m.set(pos.x, pos.y, Some((i, "↟"))), - Direction::Right => 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::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))), + Direction::Right => { + m.set(pos.x as usize, pos.y as usize, 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 - .in_direction( - dir, - *len as usize, - &Dimension { - width: self.map.width, - height: self.map.height, - }, - ) - .unwrap(); + let end_pos = pos.in_direction(dir, *len as PositionType); 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, "↦"))), - 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::Up => { + m.set(end_pos.x as usize, end_pos.y as usize, 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(); - 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 diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index d634e60..d0f0708 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -6,7 +6,7 @@ use crate::priority_queue::BinaryHeap; use colored::{Color, Colorize}; use std::fmt::Display; -use self::common::Position; +use self::common::{Position, PositionType}; pub mod brute_force; pub mod common; @@ -69,17 +69,17 @@ impl Problem { for (i, path) in self.path.iter().enumerate() { if i != without { 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 { - 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 { - 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)?; 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]))?; - } 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]))?; } else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| { v.iter() - .position(|p| p == &Position::new(x, y)) + .position(|p| p == &Position::new(x as PositionType, y as PositionType)) .map(|j| (i, j)) }) { if self.path[i][p].x < self.path[i][p + 1].x { @@ -164,19 +172,24 @@ struct MapInternal<'a> { impl<'a> MapInternal<'a> { fn get_direction(&self, pos: Position) -> [Option; 4] { + let min = Position::new(0, 0); + let max = Position::new( + self.map.width as PositionType, + self.map.height as PositionType, + ); [ - (pos.x > 0) - .then_some((pos.x.saturating_sub(1), pos.y)) - .map(|(x, y)| Position::new(x, y)), - (pos.x < self.map.width - 1) - .then_some((pos.x + 1, pos.y)) - .map(|(x, y)| Position::new(x, y)), - (pos.y > 0) - .then_some((pos.x, pos.y.saturating_sub(1))) - .map(|(x, y)| Position::new(x, y)), - (pos.y < self.map.height - 1) - .then_some((pos.x, pos.y + 1)) - .map(|(x, y)| Position::new(x, y)), + Position::new(pos.x - 1, pos.y) + .in_range(&min, &max) + .copied(), + Position::new(pos.x + 1, pos.y) + .in_range(&min, &max) + .copied(), + Position::new(pos.x, pos.y - 1) + .in_range(&min, &max) + .copied(), + Position::new(pos.x, pos.y + 1) + .in_range(&min, &max) + .copied(), ] } } @@ -185,7 +198,7 @@ impl<'a> WheightedGraph for MapInternal<'a> { type Node = Position; 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 } else { let t = self.get_direction(*node); @@ -202,7 +215,7 @@ impl<'a> WheightedGraph for MapInternal<'a> { t.iter() .flatten() .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)) } }