Solve day12

This commit is contained in:
Malte Tammena 2022-12-12 18:50:53 +01:00
parent afc1255c76
commit 0e87cb94d3
5 changed files with 264 additions and 2 deletions

4
Cargo.lock generated
View file

@ -156,6 +156,10 @@ dependencies = [
[[package]]
name = "day12"
version = "0.1.0"
dependencies = [
"colorous",
"termion",
]
[[package]]
name = "day13"

View file

@ -8,3 +8,5 @@ build = true
app = true
[dependencies]
colorous = "1.0.8"
termion = "2.0.1"

41
day12/input Normal file
View file

@ -0,0 +1,41 @@
abcccccccccccccccccaaccccccccccccaaaaaaaacccccccccccaaaaaccccaaaaaaccaaaaaaaaaaaaaaaaaccccccccccccccccaaacccccaaaaaaaacccaaaccccccccccccccccccccccccccccccccccccccccccccccccccaaaaa
abccccccccccccccccaaacaacccccccccccaaaacccccccccccccaaaaaacccaaaaaaccaaaaaaaaaaaaaaaaaaaacccccccccaaacaaacccccaaaaaaaaaccaaaaccccccccccccccccccccccccccccccccccccccccccccccccaaaaaa
abcccccccccccccccccaaaaacccccccccccaaaaaccccccccccccaaaaaaccccaaaacccaaaacccaaaaaaaaaaaaacccccccccaaaaaaaaaacccaaaaaaaaccaaaaccccccccccccccccccccccccccccccccccaaacccccccccccaaaaaa
abcccccccccccccccaaaaaacccccccccccaaacaaccaaccccccccaaaaaaccccaaaacccaaaccccaaaaaaaaaaaaaccccccccccaaaaaaaaaccaaaaaacccccaaacccccccccccccccccccccccccccccccccccaaaccccccccccccccaaa
abcccccccccccccccaaaaaaaacccccccccaacccacaaacaacccccccaaccccccaccaccccccccaaaaaaaaaaaaccccccccccccccaaaaaaacccaaaaaaacccccccccccccaacccccccccccccccccccccccccccaaaccccccccccccccaaa
abcccccccccccccccaacaaaaacccccccccccccccccaaaaacccccccccccccccccccccccccccaaaaaaaaaaaaccccccccccccccaaaaaaccccaaccaaacccccccccccaaaaaaccccccccccccccccccccccccccdccccccccccccccccaa
abccaacccccccaaacccaaacaccccccccccaaacccaaaaaaccccccccccccccccccccccccccccaaacccaaaaaacaaaaccccccccaaaaaaaccccccccaaacccccccccccaaaaaacccccccccccccccccllllllcccdddddcccccccccccccc
abaaaacccacccaaccccaacccccccccccccaaacccaaaaaaaacccccccccccccccccaaccccccccacccaaaaccccaaaaccccccccaaacaaaccccccccccccccccccccccaaaaaaccccccccccccccccllllllllldddddddddddccaaccccc
abaaaaccaaaaaaaacccccccccccccccaaaaaaaacaacaaaaacccccccccccccccccaaacccccccaaacaaccccccaaaacccccccccccccaaccccccccccccccccccccccaaaaaccccccccccccccccclllllllllldddddddddeeaaaccccc
abaaaccccaaaaaaaaccccccccaaacccaaaaaaaacccaaacccccccccccccccccaaaaaaaaccccccaaaaacccccccaacccccccccccccccccccccccccccccccccccccccaaaaccccaaaccccccccckllppppplllmmmmmmmdeeeeaaccccc
abaaaacccaaaaaaaaacccccaaaaaaccccaaaaaccccaaccccccccccccccccccaaaaaaaaccccccaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccaaaacccccccckklpppppppplmmmmmmmmmeeeeaccccc
abaaaacccaaaaaaaaacccccaaaaaacccaaaaaaccccccccaacccccccccccccccaaaaaaccccccaaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccaaaacccccccckkkppppppppqmmmmmmmmmmeeeaacccc
abaaaaaccaaaaaaaaccccccaaaaaacccaaaaaaccccccacaaaacccccccccccccaaaaaaccccccaaaaaaaaccccccccaaaaccccccccaaacccccccccccccccccccccccccccccccaaacccccccckkkpppuuuppqqqqqqqqmmmeeeeacccc
abacccccaaaaaaaccccccccaaaaaccccaccaaaccccccaaaaaacccccacccccccaaaaaaccccccaaaaaacaaaccccccaaaaccccccccaaaacccccccccccccccccccccccccccccccccccccccckkkpppuuuuuuqqqqqqqqqnnneeeccccc
abcccccccaccaaaccccccccaaaaacccccccccccccccccaaaacccaaaacccccccaacaaacccccccccaaacaaaaaccccaaaaccccccccaaaaccccccccccccccccccccccccccccccccccccccckkkkpppuuuuuuuqvvvvqqqnnneeeccccc
abcccccccccccaaacaaccccccccccccccccccccccccccaaaacccaaaaaacccccccccccccccccccccccaaaaaaccccaaacccccccccaaaccccccccccccccccccccccccccccccccccccccckkkkrrpuuuxxxuvvvvvvvqqnnneeeccccc
abcccccccccccccccaacaaaccccccccccccccccccccccaacaacccaaaaacccccccccccccccccccccccaaaaaaccccccccccccccccccccccccccccccccccccccccccccccccccccccccckkkkrrrruuxxxxuvvvvvvvqqnnneeeccccc
abcccccccccccccccaaaaacccccccccccccccccccccccccccaccaaaaacccccaaccccccccccccccccccaaaaaccccccccccccccccaaaccccccccccccccaaacccccccccccccccccccckkkkrrrruuuxxxxyyyyyvvvqqnnneecccccc
abcccccccccccccaaaaaacccccccccccaacaacccccccccccaaaaaaaaacccacaaaacaaccaaccccccccaaacaaccccccccccaaccccaaaaaacccaacaacccaaacacccccccccccccccccjjkkrrrruuuuuxxxyyyyyvvqrqnneffcccccc
abcccccccccccccaaaaaaaacccaaacccaaaaaccccccaacccaaaaaaaaacccaaaaaacaaaaaaccccccccaaacaaacccccccaaaaaacaaaaaaacccaaaaacaaaaaaaaccccccccccccccccjjjrrrtttuuxxxxxyyyyyvvrrnnnfffcccccc
SbccccccccccccccccaaaaacccaaaaccaaaaaaccccaaaaaacaaaaaaaaacccaaaacccaaaaaccccccccaaaaaaacccccccaaaaaaaaaaaaaaccaaaaaccaaaaaaaaccccccccccccccccjjjrrrtttxxxEzzzzyyyvvrrrnnnfffcccccc
abccccccccccaaaccaaccaacccaaaaccaaaaaacccccaaaaacaaaaaaaaacccaaaaccaaaaaacccccccccaaaaaaccccccccaaaacaaaaaaacccaaaaaaccaaaaaacccccccccccccccccjjjrrrtttxxxxxyyyyyyvvrrrnnnfffcccccc
abcccccccccaaaaccaacccccccaaacccaaaaaacccaaaaaaaaaaaaaaaaacccaacacaaaaaaaacccccaaaaaaaacccccccccaaaacccaaaaaaccccaaaacccaaaaacccccccccccccccccjjjrrrtttxxxxxyyyyyyywvrrnnnfffcccccc
abcccccccccaaaacccccccccccccccccccaaaccccaaaaaaaaaaaaaaaaaacccccccaaaaaaaacccccaaaaaaaaaccccccccaccacccaaaaaaccccacccccaaaaaacccccccccccccccccjjjrrrrttttxxxyyyyyyywwrrroooffcccccc
abccccccccccaaaccccccccccccccccccccccccccaaaaaaaaaccaaaaaaaccccccccccaaccccccccaaaaaaaaaaccccccccccccccaacccccccccccccccaaccccccccccccccccccccjjjjqqqqttttxxyywwwwwwwwrrooofffccccc
abcccccccccccccccccccccccccccccccccccccccccaaacacccccaaaaccccccccccccaacccccccccccaaacaaacccccccccccccccccccccccccccccaaacccccccccccccccccccaacjjjjqqqqqttwwwwwwwwwwwrrrooofffccccc
abcccccccccccccccccccccccccccccccccccccccccaaccccccccccaacccccccccccccccccccccccccaaacccccccccccccccccccccccccccccccccaaacccccccccccccccccaaaaaajjjjqqqqttwwwwwwsswwrrrrooofffccccc
abcccccaaaaccccccccccccccaacaaccccccccccccccccccccccccccccccccccccccccccccccccccccaacccccccccccccccccccccccccccccccaaaaaaaaccaaaacccccccccaaaaaacjjjiqqqtttwwwwsssssrrrrooofffccccc
abccccaaaaaccccccccccccccaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaaaaccaaaaacccccccccaaaaacciiiiqqttswwwssssssrrroooogffccccc
abccccaaaaaacccccccccccccaaaaaacccaaaccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaccaaaaaaccccccccaaaaacccciiiqqqssssssspppooooooogggaccccc
abccccaaaaaaccccccccaacccaaaaaaccccaacccccccccccccccccccccccccccccccccaaaaccccccccccccccccccccccccccccccccccccccccccaaaaaaccaaaaaaccccccccaaaaaccccciiiqqsssssspppppoooooggggaacccc
abccccaaaaaccccccaaaaacccaaaaaacaacaaaaaccccccccccccccccccccaacccccccaaaaacccccccccccaaaccccccccccccccccccccccccccccaaaaaacccaaaaacccccccccacccccccciiiqqqpssspppppgggggggggaaacccc
abccccccaaacccccccaaaaaccccaaaccaaaaaaaacccccccaacccccccaaccaacccccccaaaaaacccccccccaaaacccccccccccaaaaccccccccccccaaccaaacccaaacccccaaacaaaccccccccciiqqppppppphhhggggggggaaaacccc
abccccccccccccccccaaaaaccccccccccaaaaaccccccccaaacaaccccaaaaaacccccccaaaaaaaccccccccaaaacccccccccccaaaacccccccccaaaaaacccccccccccccccaaaaaaaccccccccciiippppppphhhhggggggcaaacccccc
abaacccccccccccccaaaaaccccccccccccaaaaaccccccccaaaaacccccaaaaaaacccccaaaaacaaacccccccaaacccccccccccaaaacccccccccaaaaacccccccccccccccccaaaaaacccccccccciiiippphhhhhhcccccccaaacccccc
abaacccccccccccccccaaacccccccccccaaacaaccccccaaaaaaccccccaaaaaaacccaaccaaacaaaaccaaaccccccccccccccccaaacccccccccaaaaaaacccccccccccccccaaaaaaaacccccccciiihhhhhhhhaaaccccccccccccccc
abaaccccccccccccccccccccccccccccccaacccccccccaaaaaaaacccaaaaaaccaaaaaacccccaaaacaaaaaccccccccccccccccccccccccccaaaaaaaaccccccccccccccaaaaaaaaaccccccccciihhhhhhcaaaacccccccccccccca
abaaccccccccccccccccccccccccccccccccaacccccccaacaaaaacccaaaaaaccaaaaacccccccaaaaaaaacccccccccccccccccccccccccccaaaaaaaacccccccccaaacaaaaaaaaaacccccccccccchhhaccccaacccccccccccccca
abaaccccccccccccccccccccccccccccccccaaaaaaccccccaaccccccccccaaccaaaaaaacccccaaaaaaaccccccccccccccccccccccccaaaccacaaacccccccccccaaaaaaacaaacaaaaaacccccccccaaacccccccccccccccaaaaaa
abccccccccccccccccccccccccccccccccccaaaaaccccccaaccccccccccccccaaaaaaaacaaaaaaaaaaccccccccccccccccccccccccaaaaaaccaaaccccccccccccaaaaaacaaacaaaaaacccccccccaaaccccccccccccccccaaaaa
abccccccccccccccccccccccccccccccccaaaaaaaacccccccccccccccccccccaaaaaaaacaaaaaaaaaaaaacccccccccccccccccccccaaaaaacccccccccccccccaaaaaaaaaaaaaaaaaacccccccccccccccccccccccccccccaaaaa

5
day12/input.test Normal file
View file

@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

View file

@ -1,3 +1,213 @@
fn main() {
println!("Hello, world!");
use std::{
cmp::Reverse,
fs::File,
io::{BufRead, BufReader, Read},
};
#[derive(Debug, Default, PartialEq, Eq)]
enum SolvePuzzle {
First,
#[default]
Second,
Print,
}
#[derive(Debug)]
struct HeightMap {
heights: Vec<u8>,
width: usize,
height: usize,
}
#[derive(Debug, Eq, Ord)]
struct ScoredPos {
height: u8,
score: u32,
index_on_map: usize,
}
impl HeightMap {
pub fn solve_a_star<const STARTING: u8>(&self) -> usize {
let mut entries: Vec<_> = self
.heights
.iter()
.enumerate()
.map(|(idx, &height)| ScoredPos {
height,
score: if height == STARTING { 0 } else { u32::MAX },
index_on_map: idx,
})
.collect();
let mut open: Vec<usize> = entries
.iter()
.enumerate()
.filter(|(_, entry)| entry.height == STARTING)
.map(|(idx, _)| idx)
.collect();
open.sort_by_cached_key(|&idx| Reverse(entries[idx].score));
let mut came_from: Vec<Option<usize>> =
::std::iter::repeat(None).take(self.heights.len()).collect();
while !open.is_empty() {
let current_idx = *open.last().unwrap();
if entries[current_idx].height == b'E' {
return self.count_path(&came_from, current_idx);
}
let current_idx = open.pop().unwrap();
for neighbor_idx in self.neighbors_of(current_idx) {
let tentative_score = &entries[current_idx].score + 1;
let neighbor = &mut entries[neighbor_idx];
if tentative_score < neighbor.score {
came_from[neighbor_idx] = Some(current_idx);
neighbor.score = tentative_score;
if !open.contains(&neighbor_idx) {
open.push(neighbor_idx);
}
}
}
open.sort_by_cached_key(|&idx| Reverse(entries[idx].score));
}
panic!()
}
fn neighbors_of(&self, current: usize) -> impl Iterator<Item = usize> + '_ {
let (x, y) = self.coords_of(current);
let curr_height = self.height_of(current);
[
(x.saturating_sub(1), y),
(x, y.saturating_sub(1)),
(x + 1, y),
(x, y + 1),
]
.into_iter()
.filter(move |&(x, _)| x < self.width)
.filter(|&(_, y)| y < self.height)
.filter(move |&(new_x, new_y)| new_x != x || new_y != y)
.map(|neigh| self.index_of(&neigh))
.filter(move |&idx| self.height_of(idx) <= curr_height + 1)
}
fn coords_of(&self, current: usize) -> (usize, usize) {
(current % self.width, current / self.width)
}
fn index_of(&self, (x, y): &(usize, usize)) -> usize {
x + y * self.width
}
fn height_of(&self, idx: usize) -> u8 {
match self.heights[idx] {
b'S' => b'a',
b'E' => b'z',
other => other,
}
}
fn count_path(&self, came_from: &[Option<usize>], mut current: usize) -> usize {
let mut count = 0;
while let Some(new) = came_from[current] {
count += 1;
current = new;
}
count
}
fn print_fancy(&self) {
let sup = (b'z' - b'a' + 1) as usize;
for y in 0..self.height {
for x in 0..self.width {
let idx = self.index_of(&(x, y));
let height = self.height_of(idx) - b'a';
let char = if self.heights[idx] == b'S' {
'S'
} else if self.heights[idx] == b'E' {
'E'
} else {
'█'
};
let color = colorous::RED_YELLOW_GREEN.eval_rational(26 - height as usize, sup);
print!(
"{}{}{char}",
termion::color::Fg(termion::color::Rgb(color.r, color.g, color.b)),
termion::color::Bg(termion::color::Rgb(0, 0, 0))
);
}
println!()
}
println!()
}
}
fn solve_puzzle<const STARTING: u8, R: BufRead>(reader: R) -> usize {
let map = HeightMap::from(reader);
map.solve_a_star::<STARTING>()
}
fn print_puzzle<R: BufRead>(reader: R) -> usize {
let map = HeightMap::from(reader);
map.print_fancy();
0
}
fn main() {
let mut args = ::std::env::args().skip(1);
let file = args.next().unwrap_or_else(|| String::from("./input"));
let solve = args
.next()
.map(|arg| match arg.as_str() {
"first" => SolvePuzzle::First,
"second" => SolvePuzzle::Second,
"print" => SolvePuzzle::Print,
_ => unreachable!(),
})
.unwrap_or_default();
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);
}
impl<R: Read> From<R> for HeightMap {
fn from(reader: R) -> Self {
let mut width = None;
let heights: Vec<_> = reader
.bytes()
.map(Result::unwrap)
.enumerate()
.inspect(|&(idx, byte)| {
if width.is_none() && byte == b'\n' {
width = Some(idx);
}
})
.map(|(_, byte)| byte)
.filter(|&byte| byte != b'\n')
.collect();
let width = width.unwrap_or(heights.len());
let height = heights.len() / width;
HeightMap {
heights,
width,
height,
}
}
}
impl PartialEq for ScoredPos {
fn eq(&self, other: &Self) -> bool {
self.height == other.height
}
}
impl PartialOrd for ScoredPos {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.height < other.height {
Some(::std::cmp::Ordering::Less)
} else if self.height < other.height {
Some(::std::cmp::Ordering::Greater)
} else {
Some(::std::cmp::Ordering::Equal)
}
}
}