diff --git a/2023/src/day14.rs b/2023/src/day14.rs new file mode 100644 index 0000000..a81c536 --- /dev/null +++ b/2023/src/day14.rs @@ -0,0 +1,214 @@ +use aoc_runner_derive::{aoc, aoc_generator}; +use std::collections::HashSet; + +#[aoc_generator(day14)] +fn parse(input: &str) -> Vec { + input + .lines() + .filter_map(|line| { + if !line.is_empty() { + Some(String::from(line)) + } else { + None + } + }) + .collect::>() +} + +fn map_to_string(map: &[[char; 100]; 100]) -> String { + let mut s = String::with_capacity(100 * 100); + for row in map.iter() { + let mut has_char = false; + for &c in row.iter() { + if c == ' ' { + break; + } + has_char = true; + s.push(c); + } + if has_char { + s.push('\n'); + } + } + s +} + +fn score(input: &str) -> usize { + let lines = input + .split("\n") + .filter_map(|t| { + if t.is_empty() { + None + } else { + Some(String::from(t)) + } + }) + .collect::>(); + let mut score = 0; + let total_lines = lines.len(); + for (index, line) in lines.iter().enumerate() { + score += line.matches("O").collect::>().len() * (total_lines - index); + } + score +} + +#[aoc(day14, part1)] +fn part1(input: &[String]) -> usize { + let mut map: [[char; 100]; 100] = [[' '; 100]; 100]; + for (row, line) in input.iter().enumerate() { + for (col, c) in line.chars().enumerate() { + map[row][col] = c; + } + } + tilt_north(&mut map); + score(&map_to_string(&map)) +} + +fn tilt_north(map: &mut [[char; 100]; 100]) -> String { + for col in 0..(map[0]).len() { + let mut r = 0; + for row in (0..(map.len())).rev() { + if map[row][col] == ' ' { + continue; + } else if map[row][col] == '#' { + for rock in 1..=r { + map[row + rock][col] = 'O'; + } + r = 0; + } else if map[row][col] == 'O' { + r += 1; + map[row][col] = '.'; + } + } + for rock in 1..=r { + map[rock - 1][col] = 'O'; + } + } + map_to_string(&map) +} + +fn tilt_west(map: &mut [[char; 100]; 100]) -> String { + for row in 0..map.len() { + let mut r = 0; + for col in (0..map[0].len()).rev() { + if map[row][col] == ' ' { + continue; + } else if map[row][col] == '#' { + for rock in 1..=r { + map[row][col + rock] = 'O'; + } + r = 0; + } else if map[row][col] == 'O' { + r += 1; + map[row][col] = '.'; + } + } + for rock in 1..=r { + map[row][rock - 1] = 'O'; + } + } + map_to_string(&map) +} + +fn tilt_south(map: &mut [[char; 100]; 100]) -> String { + for col in 0..map[0].len() { + let mut r = 0; + let mut last_row = 100; + for row in 0..map.len() { + if map[row][col] == ' ' { + last_row = row; + break; + } else if map[row][col] == '#' { + for rock in 1..=r { + map[row - rock][col] = 'O'; + } + r = 0; + } else if map[row][col] == 'O' { + r += 1; + map[row][col] = '.'; + } + } + for rock in 1..=r { + map[last_row - rock][col] = 'O'; + } + } + map_to_string(&map) +} + +fn tilt_east(map: &mut [[char; 100]; 100]) -> String { + for row in 0..map.len() { + let mut r = 0; + let mut last_col = 100; + for col in 0..map[row].len() { + if map[row][col] == ' ' { + last_col = col; + break; + } else if map[row][col] == '#' { + for rock in 1..=r { + map[row][col - rock] = 'O'; + } + r = 0; + } else if map[row][col] == 'O' { + r += 1; + map[row][col] = '.'; + } + } + for rock in 1..=r { + map[row][last_col - rock] = 'O'; + } + } + map_to_string(&map) +} + +#[aoc(day14, part2)] +fn part2(input: &[String]) -> usize { + let mut map: [[char; 100]; 100] = [[' '; 100]; 100]; + for (row, line) in input.iter().enumerate() { + for (col, c) in line.chars().enumerate() { + map[row][col] = c; + } + } + let mut patterns: HashSet = HashSet::new(); + let mut seq: Vec = vec![]; + let mut iters = 0; + loop { + if iters == 1000 { + break; + } + tilt_north(&mut map); + tilt_west(&mut map); + tilt_south(&mut map); + tilt_east(&mut map); + let s = map_to_string(&map); + iters += 1; + seq.push(s.clone()); + patterns.insert(s); + } + + let score = score(&seq[999]); + score +} + +#[cfg(test)] +mod tests { + use super::*; + + const SAMPLE_DATA: &'static str = r#"O....#.... +O.OO#....# +.....##... +OO.#O....O +.O.....O#. +O.#..O.#.# +..O..#O..O +.......O.. +#....###.. +#OO..#.... +"#; + + #[test] + fn sample_data() { + let input = parse(&SAMPLE_DATA); + assert_eq!(part1(&input), 136); + assert_eq!(part2(&input), 64); + } +} diff --git a/2023/src/lib.rs b/2023/src/lib.rs index 8942eda..605e6fa 100644 --- a/2023/src/lib.rs +++ b/2023/src/lib.rs @@ -13,5 +13,6 @@ mod day10; mod day11; mod day12; mod day13; +mod day14; aoc_lib! { year = 2023 }