day(14): add solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
0a4cc4c031
commit
fdbca4409c
2 changed files with 152 additions and 0 deletions
10
samples/day14.txt
Normal file
10
samples/day14.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
O....#....
|
||||
O.OO#....#
|
||||
.....##...
|
||||
OO.#O....O
|
||||
.O.....O#.
|
||||
O.#..O.#.#
|
||||
..O..#O..O
|
||||
.......O..
|
||||
#....###..
|
||||
#OO..#....
|
142
src/bin/day14.rs
Normal file
142
src/bin/day14.rs
Normal file
|
@ -0,0 +1,142 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use aoc_2023::*;
|
||||
use indicatif::ProgressIterator;
|
||||
use memoize::memoize;
|
||||
|
||||
type Output1 = usize;
|
||||
type Output2 = Output1;
|
||||
|
||||
#[memoize]
|
||||
fn slide_rocks(map: Vec<Vec<char>>) -> Vec<Vec<char>> {
|
||||
let mut tilted: Vec<Vec<char>> = map.to_vec();
|
||||
|
||||
for x in 0..tilted[0].len() {
|
||||
let mut next = 0;
|
||||
for y in 0..tilted.len() {
|
||||
match tilted[y][x] {
|
||||
'#' | 'O' => {
|
||||
next = y + 1;
|
||||
}
|
||||
'.' => {
|
||||
while next < tilted.len() && tilted[next][x] == '.' {
|
||||
next += 1;
|
||||
}
|
||||
|
||||
if next < tilted.len() && tilted[next][x] == 'O' {
|
||||
tilted[y][x] = 'O';
|
||||
tilted[next][x] = '.';
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tilted
|
||||
}
|
||||
|
||||
#[memoize]
|
||||
fn rotate_east(map: Vec<Vec<char>>) -> Vec<Vec<char>> {
|
||||
let mut r = map.clone();
|
||||
|
||||
for y in 0..map.len() {
|
||||
for (x, row) in r.iter_mut().enumerate().take(map[y].len()) {
|
||||
row[map.len() - y - 1] = map[y][x];
|
||||
}
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
#[memoize]
|
||||
fn run_cycle(map: Vec<Vec<char>>) -> Vec<Vec<char>> {
|
||||
let mut map = map;
|
||||
for _ in 0..4 {
|
||||
map = slide_rocks(map);
|
||||
map = rotate_east(map);
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
fn total_load(m: &[Vec<char>]) -> usize {
|
||||
let rows = m.len();
|
||||
|
||||
m.iter()
|
||||
.enumerate()
|
||||
.map(|(y, l)| (rows - y) * l.iter().filter(|&&c| c == 'O').count())
|
||||
.sum()
|
||||
}
|
||||
|
||||
struct Day14 {
|
||||
map: Vec<Vec<char>>,
|
||||
}
|
||||
|
||||
impl Solution<Output1, Output2> for Day14 {
|
||||
fn new<P: AsRef<Path>>(pathname: P) -> Self {
|
||||
let lines: Vec<String> = file_to_lines(pathname);
|
||||
|
||||
Self {
|
||||
map: lines.iter().map(|l| l.chars().collect()).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn part_1(&mut self) -> Output1 {
|
||||
let tilted = slide_rocks(self.map.clone());
|
||||
total_load(&tilted)
|
||||
}
|
||||
|
||||
fn part_2(&mut self) -> Output2 {
|
||||
let mut map = self.map.clone();
|
||||
|
||||
let iterations = 1000000000;
|
||||
let mut remaining = 0;
|
||||
|
||||
let mut seen: HashMap<Vec<Vec<char>>, usize> = HashMap::new();
|
||||
for i in (0..iterations).progress() {
|
||||
seen.insert(map.clone(), i);
|
||||
map = run_cycle(map);
|
||||
|
||||
if let Some(&old_i) = seen.get(&map) {
|
||||
remaining = (iterations - i - 1) % (i - old_i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..remaining {
|
||||
map = run_cycle(map);
|
||||
}
|
||||
|
||||
total_load(&map)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
Day14::main()
|
||||
}
|
||||
|
||||
test_sample!(day_14, Day14, 136, 64);
|
||||
|
||||
#[cfg(test)]
|
||||
mod day_14_extended {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_rotate_east() {
|
||||
let m = vec![
|
||||
vec!['#', 'O', 'O'],
|
||||
vec!['.', '#', 'O'],
|
||||
vec!['.', '.', 'O'],
|
||||
];
|
||||
|
||||
assert_eq!(
|
||||
rotate_east(m),
|
||||
vec![
|
||||
vec!['.', '.', '#'],
|
||||
vec!['.', '#', 'O'],
|
||||
vec!['O', 'O', 'O'],
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue