Printing day12
This commit is contained in:
parent
105989cdb7
commit
e61dac6b9b
|
@ -38,6 +38,42 @@ impl HeightMap {
|
|||
panic!("Did not reach the target");
|
||||
}
|
||||
|
||||
pub fn find_shortest_path_to_end<const TARGET: u8>(&self) -> Vec<usize> {
|
||||
let mut visited: Vec<bool> = self.heights.iter().map(|_| false).collect();
|
||||
let mut came_from: Vec<Option<usize>> = self.heights.iter().map(|_| None).collect();
|
||||
let mut open: PriorityQueue<usize, Reverse<u32>, DefaultHashBuilder> =
|
||||
PriorityQueue::with_hasher(DefaultHashBuilder::default());
|
||||
let end_idx = self
|
||||
.heights
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, &height)| height == b'E')
|
||||
.unwrap()
|
||||
.0;
|
||||
open.push(end_idx, Reverse(0));
|
||||
while let Some((current_idx, Reverse(current_score))) = open.pop() {
|
||||
if self.heights[current_idx] == TARGET {
|
||||
let mut current = current_idx;
|
||||
let mut path = vec![current];
|
||||
while let Some(next) = came_from[current] {
|
||||
path.push(next);
|
||||
current = next;
|
||||
}
|
||||
path.reverse();
|
||||
return path;
|
||||
}
|
||||
visited[current_idx] = true;
|
||||
for neighbor_idx in self.neighbors_of(current_idx) {
|
||||
let tentative_score = current_score + 1;
|
||||
if !visited[neighbor_idx] {
|
||||
came_from[neighbor_idx] = Some(current_idx);
|
||||
open.push(neighbor_idx, Reverse(tentative_score));
|
||||
}
|
||||
}
|
||||
}
|
||||
panic!("Did not reach the target");
|
||||
}
|
||||
|
||||
fn neighbors_of(&self, current: usize) -> impl Iterator<Item = usize> + '_ {
|
||||
let (x, y) = self.coords_of(current);
|
||||
let curr_height = self.height_of(current);
|
||||
|
@ -71,8 +107,10 @@ impl HeightMap {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn print_fancy(&self) {
|
||||
pub fn print_fancy<const TARGET: u8>(&self) {
|
||||
let sup = (b'z' - b'a' + 1) as usize;
|
||||
let letters: Vec<char> = "..,,,-----+++++::::====mmM".chars().collect();
|
||||
let path = self.find_shortest_path_to_end::<TARGET>();
|
||||
for y in 0..self.height {
|
||||
for x in 0..self.width {
|
||||
let idx = self.index_of(&(x, y));
|
||||
|
@ -81,10 +119,36 @@ impl HeightMap {
|
|||
'S'
|
||||
} else if self.heights[idx] == b'E' {
|
||||
'E'
|
||||
} else if let Some((pos, _idx)) = path.iter().enumerate().find(|(_, &at)| at == idx)
|
||||
{
|
||||
let (prev_x, prev_y) =
|
||||
self.coords_of(path.get(pos - 1).copied().unwrap_or(path[pos]));
|
||||
let (next_x, next_y) =
|
||||
self.coords_of(path.get(pos + 1).copied().unwrap_or(path[pos]));
|
||||
match (
|
||||
prev_x.abs_diff(x),
|
||||
prev_y.abs_diff(y),
|
||||
next_x.abs_diff(x),
|
||||
next_y.abs_diff(y),
|
||||
) {
|
||||
(1, 0, 1, 0) => '─',
|
||||
(0, 1, 0, 1) => '│',
|
||||
(1, 0, 0, 1) if prev_x < x && next_y < y => '╯',
|
||||
(1, 0, 0, 1) if prev_x < x && next_y > y => '╮',
|
||||
(1, 0, 0, 1) if prev_x > x && next_y < y => '╰',
|
||||
(1, 0, 0, 1) if prev_x > x && next_y > y => '╭',
|
||||
(0, 1, 1, 0) if prev_y < y && next_x < x => '╯',
|
||||
(0, 1, 1, 0) if prev_y < y && next_x > x => '╰',
|
||||
(0, 1, 1, 0) if prev_y > y && next_x < x => '╮',
|
||||
(0, 1, 1, 0) if prev_y > y && next_x > x => '╭',
|
||||
(1, 0, 0, 0) if prev_x < x => '╴',
|
||||
(1, 0, 0, 0) if prev_x > x => '╶',
|
||||
x => unreachable!("Did not expect {x:?}"),
|
||||
}
|
||||
} else {
|
||||
'█'
|
||||
letters[height as usize]
|
||||
};
|
||||
let color = colorous::RED_YELLOW_GREEN.eval_rational(26 - height as usize, sup);
|
||||
let color = colorous::PURPLE_BLUE.eval_rational(26 - height as usize, sup);
|
||||
print!(
|
||||
"{}{}{char}",
|
||||
termion::color::Fg(termion::color::Rgb(color.r, color.g, color.b)),
|
||||
|
|
|
@ -12,17 +12,16 @@ enum SolvePuzzle {
|
|||
First,
|
||||
#[default]
|
||||
Second,
|
||||
Print,
|
||||
}
|
||||
|
||||
fn solve_puzzle<const STARTING: u8, R: BufRead>(reader: R) -> usize {
|
||||
fn solve_puzzle<const TARGET: u8, R: BufRead>(reader: R) -> usize {
|
||||
let map = HeightMap::from(reader);
|
||||
map.find_shortest_path_len_to_end::<STARTING>()
|
||||
map.find_shortest_path_len_to_end::<TARGET>()
|
||||
}
|
||||
|
||||
fn print_puzzle<R: BufRead>(reader: R) -> usize {
|
||||
fn print_puzzle<const TARGET: u8, R: BufRead>(reader: R) -> usize {
|
||||
let map = HeightMap::from(reader);
|
||||
map.print_fancy();
|
||||
map.print_fancy::<TARGET>();
|
||||
0
|
||||
}
|
||||
|
||||
|
@ -33,18 +32,23 @@ fn main() {
|
|||
.next()
|
||||
.map(|arg| match arg.as_str() {
|
||||
"first" => SolvePuzzle::First,
|
||||
"second" => SolvePuzzle::Second,
|
||||
"print" => SolvePuzzle::Print,
|
||||
_ => unreachable!(),
|
||||
_ => SolvePuzzle::Second,
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let should_print = args.next() == Some(String::from("print"));
|
||||
let file = BufReader::new(File::open(file).expect("Open file"));
|
||||
let solution = match solve {
|
||||
SolvePuzzle::First => solve_puzzle::<b'S', _>(file),
|
||||
SolvePuzzle::Second => solve_puzzle::<b'a', _>(file),
|
||||
SolvePuzzle::Print => print_puzzle(file),
|
||||
};
|
||||
println!("{}", solution);
|
||||
if should_print {
|
||||
match solve {
|
||||
SolvePuzzle::First => print_puzzle::<b'S', _>(file),
|
||||
SolvePuzzle::Second => print_puzzle::<b'a', _>(file),
|
||||
};
|
||||
} else {
|
||||
let solution = match solve {
|
||||
SolvePuzzle::First => solve_puzzle::<b'S', _>(file),
|
||||
SolvePuzzle::Second => solve_puzzle::<b'a', _>(file),
|
||||
};
|
||||
println!("{}", solution);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in a new issue