Printing day12

This commit is contained in:
Malte Tammena 2022-12-12 22:17:24 +01:00
parent 105989cdb7
commit e61dac6b9b
2 changed files with 85 additions and 17 deletions

View file

@ -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)),

View file

@ -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)]