Advent of Code solutions

Day 12

bwc9876.dev e953ece2 9ae06fd4

verified
+198 -5
+166 -5
years/2025/src/day_12.rs
··· 1 1 use advent_core::{day_stuff, ex_for_day, Day}; 2 + use rayon::iter::{IntoParallelIterator, ParallelIterator}; 3 + use utils::{grid::Grid, pos::Position, tiles, upos, yippee}; 2 4 3 5 pub struct Day12; 4 6 7 + tiles!(Tile, [ 8 + '#' => Filled, 9 + '.' => Empty, 10 + ]); 11 + 12 + type Present = utils::grid::Grid<Tile>; 13 + type Input = (Vec<[Vec<Position>; 4]>, Vec<((usize, usize), Vec<usize>)>); 14 + 15 + pub const KERNS: [Position; 9] = [ 16 + Position::new(0, 0), 17 + Position::new(0, -1), 18 + Position::new(0, 1), 19 + Position::new(1, 0), 20 + Position::new(-1, 0), 21 + Position::new(1, 1), 22 + Position::new(1, -1), 23 + Position::new(-1, 1), 24 + Position::new(-1, -1), 25 + ]; 26 + 27 + fn rot_pos(Position { x, y }: Position) -> Position { 28 + let (x, y) = match (x, y) { 29 + (0, 0) => (0, 0), 30 + (1, 0) => (0, -1), 31 + (0, -1) => (-1, 0), 32 + (-1, 0) => (0, 1), 33 + (0, 1) => (1, 0), 34 + (1, 1) => (1, -1), 35 + (1, -1) => (-1, -1), 36 + (-1, -1) => (-1, 1), 37 + (-1, 1) => (1, 1), 38 + _ => unreachable!(), 39 + }; 40 + Position::new(x, y) 41 + } 42 + 43 + fn try_place_at(pos: Position, shape: &[Position], grid: &mut Present) -> bool { 44 + let empties = grid 45 + .relatives(pos, shape) 46 + .take_while(|(_, _, t)| **t == Tile::Empty) 47 + .map(|(_, p, _)| p) 48 + .collect::<Vec<_>>(); 49 + 50 + if empties.len() == shape.len() { 51 + for pos in empties { 52 + *(grid.get_mut(pos).unwrap()) = Tile::Filled; 53 + } 54 + true 55 + } else { 56 + false 57 + } 58 + } 59 + 60 + fn undo_place(pos: Position, shape: &[Position], grid: &mut Present) { 61 + let positions = grid 62 + .relatives(pos, shape) 63 + .map(|(_, p, _)| p) 64 + .collect::<Vec<_>>(); 65 + 66 + for pos in positions { 67 + *(grid.get_mut(pos).unwrap()) = Tile::Empty; 68 + } 69 + } 70 + 71 + fn solve(shapes: &Vec<[Vec<Position>; 4]>, grid: &mut Present, targets: &mut Vec<usize>) -> bool { 72 + let next_shape = targets 73 + .iter() 74 + .enumerate() 75 + .find(|(_, amnt)| **amnt != 0) 76 + .map(|(f, _)| f); 77 + 78 + let (x, y) = grid.size(); 79 + 80 + if let Some(next_shape) = next_shape { 81 + let shape_all_rots = shapes.get(next_shape).unwrap(); 82 + for y in 1..(y - 1) { 83 + for x in 1..(x - 1) { 84 + for shape in shape_all_rots { 85 + if try_place_at(upos!(x, y), shape.as_slice(), grid) { 86 + targets[next_shape] -= 1; 87 + let inner_res = solve(shapes, grid, targets); 88 + if inner_res { 89 + return inner_res; 90 + } else { 91 + targets[next_shape] += 1; 92 + undo_place(upos!(x, y), shape.as_slice(), grid); 93 + } 94 + } 95 + } 96 + } 97 + } 98 + false 99 + } else { 100 + true 101 + } 102 + } 103 + 5 104 impl Day for Day12 { 6 - day_stuff!(12, "", ""); 105 + day_stuff!(12, "2", "🥳", Input); 106 + 107 + fn part_1((shapes, targets): Self::Input) -> Option<String> { 108 + let ans = targets 109 + .into_par_iter() 110 + .filter_map(|((x, y), mut avail)| { 111 + let area_needed = shapes 112 + .iter() 113 + .enumerate() 114 + .map(|(i, s)| s[0].len() * avail[i]) 115 + .sum::<usize>(); 116 + if area_needed > (x * y) { 117 + return None; 118 + } 119 + let mut grid = Grid::new(vec![vec![Tile::Empty; x]; y]); 120 + let can_fit = solve(&shapes, &mut grid, &mut avail); 121 + if can_fit { 122 + Some(0) 123 + } else { 124 + None 125 + } 126 + }) 127 + .count(); 7 128 8 - fn part_1(_input: Self::Input) -> Option<String> { 9 - None 129 + Some(ans.to_string()) 10 130 } 11 131 12 - fn part_2(_input: Self::Input) -> Option<String> { 13 - None 132 + yippee!(); 133 + 134 + fn parse_input(input: &str) -> Self::Input { 135 + let sections = input.split("\n\n").collect::<Vec<_>>(); 136 + let shapes = sections 137 + .iter() 138 + .take(sections.len() - 1) 139 + .map(|s| { 140 + let (_, grid) = s.split_once('\n').unwrap(); 141 + let grid = Present::parse(grid); 142 + let rels = grid 143 + .relatives(Position::new(1, 1), &KERNS) 144 + .filter(|(_, _, t)| **t == Tile::Filled) 145 + .map(|(kern, _, _)| kern) 146 + .collect::<Vec<_>>(); 147 + 148 + let rels90: Vec<_> = rels.iter().copied().map(rot_pos).collect(); 149 + 150 + let rels180: Vec<_> = rels90.iter().copied().map(rot_pos).collect(); 151 + 152 + let rels270: Vec<_> = rels180.iter().copied().map(rot_pos).collect(); 153 + 154 + [rels, rels90, rels180, rels270] 155 + }) 156 + .collect(); 157 + 158 + let targets = sections 159 + .last() 160 + .unwrap() 161 + .lines() 162 + .map(|l| { 163 + let (size, amnts) = l.split_once(':').unwrap(); 164 + let (x, y) = size.split_once('x').unwrap(); 165 + let amnts = amnts 166 + .trim() 167 + .split(' ') 168 + .map(|x| x.parse().unwrap()) 169 + .collect(); 170 + ((x.parse().unwrap(), y.parse().unwrap()), amnts) 171 + }) 172 + .collect(); 173 + 174 + (shapes, targets) 14 175 } 15 176 }
+32
years/2025/src/examples/day_12/1.txt
··· 1 + 0: 2 + ### 3 + ##. 4 + ##. 5 + 6 + 1: 7 + ### 8 + ##. 9 + .## 10 + 11 + 2: 12 + .## 13 + ### 14 + ##. 15 + 16 + 3: 17 + ##. 18 + ### 19 + ##. 20 + 21 + 4: 22 + ### 23 + #.. 24 + ### 25 + 26 + 5: 27 + ### 28 + .#. 29 + ### 30 + 31 + 4x4: 0 0 0 0 2 0 32 + 12x5: 1 0 1 0 2 2