Compare commits
	
		
			2 Commits
		
	
	
		
			4ce7184b1e
			...
			0ecea97752
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 0ecea97752 | ||
|   | dc5f488212 | 
							
								
								
									
										287
									
								
								aoc_2024/src/day16.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								aoc_2024/src/day16.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,287 @@ | ||||
| use std::{ | ||||
|     cmp::{Ordering, Reverse}, | ||||
|     collections::BinaryHeap, | ||||
| }; | ||||
| 
 | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use hashbrown::HashSet; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| enum Cell { | ||||
|     Empty, | ||||
|     Wall, | ||||
| } | ||||
| 
 | ||||
| type Input = ((usize, usize), (usize, usize), Vec<Vec<Cell>>); | ||||
| 
 | ||||
| #[aoc_generator(day16)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     let mut pos = (0, 0); | ||||
|     let mut end = (0, 0); | ||||
|     let map = input | ||||
|         .lines() | ||||
|         .enumerate() | ||||
|         .map(|(y, line)| { | ||||
|             line.chars() | ||||
|                 .enumerate() | ||||
|                 .map(|(x, c)| match c { | ||||
|                     '#' => Cell::Wall, | ||||
|                     '.' => Cell::Empty, | ||||
|                     'E' => { | ||||
|                         end = (x, y); | ||||
|                         Cell::Empty | ||||
|                     } | ||||
|                     'S' => { | ||||
|                         pos = (x, y); | ||||
|                         Cell::Empty | ||||
|                     } | ||||
|                     _ => unreachable!(), | ||||
|                 }) | ||||
|                 .collect() | ||||
|         }) | ||||
|         .collect(); | ||||
|     (pos, end, map) | ||||
| } | ||||
| 
 | ||||
| #[aoc(day16, part1)] | ||||
| fn part1(input: &Input) -> i64 { | ||||
|     let start = (input.0 .0 as i64, input.0 .1 as i64); | ||||
|     let end = (input.1 .0 as i64, input.1 .1 as i64); | ||||
|     let map = input.2.clone(); | ||||
|     let w = map[0].len(); | ||||
|     let h = map.len(); | ||||
|     let mut d = vec![vec![[i64::MAX; 4]; w]; h]; | ||||
| 
 | ||||
|     #[allow(clippy::type_complexity)] | ||||
|     let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new(); | ||||
|     d[start.1 as usize][start.0 as usize][1] = 0; | ||||
|     queue.push(Reverse((0, start.0, start.1, 1, 0))); | ||||
| 
 | ||||
|     while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() { | ||||
|         let dir_num = match (dir_x, dir_y) { | ||||
|             (0, -1) => 0, | ||||
|             (1, 0) => 1, | ||||
|             (0, 1) => 2, | ||||
|             (-1, 0) => 3, | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
| 
 | ||||
|         if d[pos_y as usize][pos_x as usize][dir_num] < dist { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (pos_x, pos_y) == end { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty { | ||||
|             let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             if (dist + 1).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1; | ||||
|                 queue.push(Reverse(( | ||||
|                     *dist_next, | ||||
|                     pos_x + dir_x, | ||||
|                     pos_y + dir_y, | ||||
|                     dir_x, | ||||
|                     dir_y, | ||||
|                 ))); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x))); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x))); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     *d[end.1 as usize][end.0 as usize].iter().min().unwrap() | ||||
| } | ||||
| 
 | ||||
| #[aoc(day16, part2)] | ||||
| fn part2(input: &Input) -> i64 { | ||||
|     let start = (input.0 .0 as i64, input.0 .1 as i64); | ||||
|     let end = (input.1 .0 as i64, input.1 .1 as i64); | ||||
|     let map = input.2.clone(); | ||||
|     let w = map[0].len(); | ||||
|     let h = map.len(); | ||||
|     let mut d = vec![vec![[i64::MAX; 4]; w]; h]; | ||||
|     let mut b = vec![vec![[vec![], vec![], vec![], vec![]]; w]; h]; | ||||
| 
 | ||||
|     #[allow(clippy::type_complexity)] | ||||
|     let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new(); | ||||
|     d[start.1 as usize][start.0 as usize][1] = 0; | ||||
|     queue.push(Reverse((0, start.0, start.1, 1, 0))); | ||||
| 
 | ||||
|     while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() { | ||||
|         let dir_num = match (dir_x, dir_y) { | ||||
|             (0, -1) => 0, | ||||
|             (1, 0) => 1, | ||||
|             (0, 1) => 2, | ||||
|             (-1, 0) => 3, | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
| 
 | ||||
|         if d[pos_y as usize][pos_x as usize][dir_num] < dist { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (pos_x, pos_y) == end { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty { | ||||
|             let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             let back_next = &mut b[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num]; | ||||
|             if (dist + 1).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse(( | ||||
|                     *dist_next, | ||||
|                     pos_x + dir_x, | ||||
|                     pos_y + dir_y, | ||||
|                     dir_x, | ||||
|                     dir_y, | ||||
|                 ))); | ||||
|             } else if (dist + 1).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 3) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x))); | ||||
|             } else if (dist + 1000).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 1) % 4]; | ||||
|             if (dist + 1000).cmp(dist_next) == Ordering::Less { | ||||
|                 *dist_next = dist + 1000; | ||||
|                 back_next.clear(); | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|                 queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x))); | ||||
|             } else if (dist + 1000).cmp(dist_next) == Ordering::Equal { | ||||
|                 back_next.push((pos_x, pos_y, dir_num)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let mut visited = HashSet::new(); | ||||
|     let dist_min = *d[end.1 as usize][end.0 as usize].iter().min().unwrap(); | ||||
|     let mut stack = vec![]; | ||||
|     d[end.1 as usize][end.0 as usize] | ||||
|         .iter() | ||||
|         .enumerate() | ||||
|         .for_each(|(i, d)| { | ||||
|             if *d == dist_min { | ||||
|                 stack.push((end.0, end.1, i)); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|     while let Some((pos_x, pos_y, dir_num)) = stack.pop() { | ||||
|         visited.insert((pos_x, pos_y)); | ||||
|         stack.append(&mut b[pos_y as usize][pos_x as usize][dir_num]); | ||||
|     } | ||||
| 
 | ||||
|     visited.len() as i64 | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "###############
 | ||||
| #.......#....E# | ||||
| #.#.###.#.###.# | ||||
| #.....#.#...#.# | ||||
| #.###.#####.#.# | ||||
| #.#.#.......#.# | ||||
| #.#.#####.###.# | ||||
| #...........#.# | ||||
| ###.#.#####.#.# | ||||
| #...#.....#.#.# | ||||
| #.#.#.###.#.#.# | ||||
| #.....#...#.#.# | ||||
| #.###.#.#.#.#.# | ||||
| #S..#.....#...# | ||||
| ###############" | ||||
|             )), | ||||
|             7036 | ||||
|         ); | ||||
|         // assert_eq!(
 | ||||
|         //     part1(&parse(include_str!("../input/2024/day16.txt"))),
 | ||||
|         //     85420
 | ||||
|         // );
 | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part2_example() { | ||||
|         assert_eq!( | ||||
|             part2(&parse( | ||||
|                 "###############
 | ||||
| #.......#....E# | ||||
| #.#.###.#.###.# | ||||
| #.....#.#...#.# | ||||
| #.###.#####.#.# | ||||
| #.#.#.......#.# | ||||
| #.#.#####.###.# | ||||
| #...........#.# | ||||
| ###.#.#####.#.# | ||||
| #...#.....#.#.# | ||||
| #.#.#.###.#.#.# | ||||
| #.....#...#.#.# | ||||
| #.###.#.#.#.#.# | ||||
| #S..#.....#...# | ||||
| ###############" | ||||
|             )), | ||||
|             45 | ||||
|         ); | ||||
|         assert_eq!( | ||||
|             part2(&parse( | ||||
|                 "#################
 | ||||
| #...#...#...#..E# | ||||
| #.#.#.#.#.#.#.#.# | ||||
| #.#.#.#...#...#.# | ||||
| #.#.#.#.###.#.#.# | ||||
| #...#.#.#.....#.# | ||||
| #.#.#.#.#.#####.# | ||||
| #.#...#.#.#.....# | ||||
| #.#.#####.#.###.# | ||||
| #.#.#.......#...# | ||||
| #.#.###.#####.### | ||||
| #.#.#...#.....#.# | ||||
| #.#.#.#####.###.# | ||||
| #.#.#.........#.# | ||||
| #.#.#.#########.# | ||||
| #S#.............# | ||||
| #################" | ||||
|             )), | ||||
|             64 | ||||
|         ); | ||||
|         // assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492);
 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										126
									
								
								aoc_2024/src/day17.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								aoc_2024/src/day17.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use nom::bytes::complete::tag; | ||||
| use nom::character::complete::i64 as parse_i64; | ||||
| use nom::error::Error; | ||||
| use nom::multi::separated_list1; | ||||
| use nom::sequence::{preceded, separated_pair, tuple}; | ||||
| 
 | ||||
| type Input = ((i64, i64, i64), Vec<i64>); | ||||
| 
 | ||||
| #[aoc_generator(day17)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     separated_pair( | ||||
|         tuple(( | ||||
|             preceded(tag("Register A: "), parse_i64::<&str, Error<&str>>), | ||||
|             preceded(tag("\nRegister B: "), parse_i64), | ||||
|             preceded(tag("\nRegister C: "), parse_i64), | ||||
|         )), | ||||
|         tag("\n\n"), | ||||
|         preceded(tag("Program: "), separated_list1(tag(","), parse_i64)), | ||||
|     )(input) | ||||
|     .unwrap() | ||||
|     .1 | ||||
| } | ||||
| 
 | ||||
| #[aoc(day17, part1)] | ||||
| fn part1(input: &Input) -> String { | ||||
|     let mut registers = input.0; | ||||
|     let program = input.1.clone(); | ||||
| 
 | ||||
|     let mut pc = 0; | ||||
| 
 | ||||
|     let mut output = Vec::new(); | ||||
| 
 | ||||
|     loop { | ||||
|         if pc >= program.len() { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         let instruction = program[pc]; | ||||
|         let literal_value = program[pc + 1]; | ||||
|         let combo_value = match program[pc + 1] { | ||||
|             0 => 0, | ||||
|             1 => 1, | ||||
|             2 => 2, | ||||
|             3 => 3, | ||||
|             4 => registers.0, | ||||
|             5 => registers.1, | ||||
|             6 => registers.2, | ||||
|             _ => unreachable!(), | ||||
|         }; | ||||
| 
 | ||||
|         match instruction { | ||||
|             0 => registers.0 >>= combo_value, | ||||
|             1 => registers.1 ^= literal_value, | ||||
|             2 => registers.1 = combo_value % 8, | ||||
|             3 => { | ||||
|                 if registers.0 != 0 { | ||||
|                     pc = literal_value as usize; | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|             4 => registers.1 ^= registers.2, | ||||
|             5 => output.push(combo_value % 8), | ||||
|             6 => registers.1 = registers.0 >> combo_value, | ||||
|             7 => registers.2 = registers.0 >> combo_value, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
| 
 | ||||
|         pc += 2; | ||||
|     } | ||||
| 
 | ||||
|     output | ||||
|         .iter() | ||||
|         .map(|x| x.to_string()) | ||||
|         .collect::<Vec<String>>() | ||||
|         .join(",") | ||||
| } | ||||
| 
 | ||||
| #[aoc(day17, part2)] | ||||
| fn part2(input: &Input) -> i64 { | ||||
|     let program = input.1.clone(); | ||||
|     let mut candidates = vec![0]; | ||||
| 
 | ||||
|     for target in program.iter().rev() { | ||||
|         let mut new_candidates = vec![]; | ||||
|         for candidate in candidates { | ||||
|             let a = candidate; | ||||
|             new_candidates.extend( | ||||
|                 (0..8) | ||||
|                     .filter(|b| { | ||||
|                         let a = (a << 3) + b; | ||||
|                         let b = a % 8; | ||||
|                         let b = b ^ 5; | ||||
|                         let c = a >> b; | ||||
|                         let b = b ^ c; | ||||
|                         let b = b ^ 6; | ||||
| 
 | ||||
|                         b % 8 == *target | ||||
|                     }) | ||||
|                     .map(|b| (a << 3) + b), | ||||
|             ); | ||||
|         } | ||||
|         candidates = new_candidates; | ||||
|     } | ||||
| 
 | ||||
|     candidates[0] | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "Register A: 729
 | ||||
| Register B: 0 | ||||
| Register C: 0 | ||||
| 
 | ||||
| Program: 0,1,5,4,3,0" | ||||
|             )), | ||||
|             "4,6,3,5,6,3,5,2,1,0" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										205
									
								
								aoc_2024/src/day18.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								aoc_2024/src/day18.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,205 @@ | ||||
| use std::collections::VecDeque; | ||||
| 
 | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use nom::{ | ||||
|     bytes::complete::tag, | ||||
|     character::complete::{i64 as parse_i64, newline}, | ||||
|     error::Error, | ||||
|     multi::separated_list0, | ||||
|     sequence::separated_pair, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| enum Cell { | ||||
|     Empty, | ||||
|     Byte, | ||||
|     Visited, | ||||
| } | ||||
| 
 | ||||
| type Input = Vec<(i64, i64)>; | ||||
| 
 | ||||
| #[aoc_generator(day18)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     separated_list0( | ||||
|         newline::<&str, Error<&str>>, | ||||
|         separated_pair(parse_i64, tag(","), parse_i64), | ||||
|     )(input) | ||||
|     .unwrap() | ||||
|     .1 | ||||
| } | ||||
| 
 | ||||
| #[aoc(day18, part1)] | ||||
| fn part1(input: &Input) -> usize { | ||||
|     #[cfg(not(test))] | ||||
|     let (w, h, bytes) = (71, 71, &input[..1024]); | ||||
|     #[cfg(test)] | ||||
|     let (w, h, bytes) = (7, 7, &input[..12]); | ||||
| 
 | ||||
|     let mut map = vec![vec![Cell::Empty; w]; h]; | ||||
| 
 | ||||
|     bytes | ||||
|         .iter() | ||||
|         .for_each(|(x, y)| map[*y as usize][*x as usize] = Cell::Byte); | ||||
| 
 | ||||
|     let mut deque = VecDeque::new(); | ||||
|     deque.push_back((0, 0, 0)); | ||||
| 
 | ||||
|     while let Some((x, y, depth)) = deque.pop_front() { | ||||
|         if x == w - 1 && y == h - 1 { | ||||
|             return depth; | ||||
|         } | ||||
| 
 | ||||
|         if map[y][x] == Cell::Visited { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         map[y][x] = Cell::Visited; | ||||
| 
 | ||||
|         if x >= 1 && map[y][x - 1] == Cell::Empty { | ||||
|             deque.push_back((x - 1, y, depth + 1)); | ||||
|         } | ||||
|         if x < w - 1 && map[y][x + 1] == Cell::Empty { | ||||
|             deque.push_back((x + 1, y, depth + 1)); | ||||
|         } | ||||
|         if y >= 1 && map[y - 1][x] == Cell::Empty { | ||||
|             deque.push_back((x, y - 1, depth + 1)); | ||||
|         } | ||||
|         if y < h - 1 && map[y + 1][x] == Cell::Empty { | ||||
|             deque.push_back((x, y + 1, depth + 1)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     unreachable!() | ||||
| } | ||||
| 
 | ||||
| #[aoc(day18, part2)] | ||||
| fn part2(input: &Input) -> String { | ||||
|     #[cfg(not(test))] | ||||
|     let (w, h, min_idx) = (71, 71, 1024); | ||||
|     #[cfg(test)] | ||||
|     let (w, h, min_idx) = (7, 7, 12); | ||||
| 
 | ||||
|     let (mut l, mut r) = (min_idx - 1, input.len() - 1); | ||||
| 
 | ||||
|     while r - l > 1 { | ||||
|         let mut possible = false; | ||||
| 
 | ||||
|         let mut map = vec![vec![Cell::Empty; w]; h]; | ||||
| 
 | ||||
|         let bytes = (l + r) >> 1; | ||||
| 
 | ||||
|         input[0..bytes] | ||||
|             .iter() | ||||
|             .for_each(|(x, y)| map[*y as usize][*x as usize] = Cell::Byte); | ||||
| 
 | ||||
|         let mut deque = VecDeque::new(); | ||||
|         deque.push_back((0, 0, 0)); | ||||
| 
 | ||||
|         while let Some((x, y, depth)) = deque.pop_front() { | ||||
|             if x == w - 1 && y == h - 1 { | ||||
|                 possible = true; | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if map[y][x] == Cell::Visited { | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             map[y][x] = Cell::Visited; | ||||
| 
 | ||||
|             if x >= 1 && map[y][x - 1] == Cell::Empty { | ||||
|                 deque.push_back((x - 1, y, depth + 1)); | ||||
|             } | ||||
|             if x < w - 1 && map[y][x + 1] == Cell::Empty { | ||||
|                 deque.push_back((x + 1, y, depth + 1)); | ||||
|             } | ||||
|             if y >= 1 && map[y - 1][x] == Cell::Empty { | ||||
|                 deque.push_back((x, y - 1, depth + 1)); | ||||
|             } | ||||
|             if y < h - 1 && map[y + 1][x] == Cell::Empty { | ||||
|                 deque.push_back((x, y + 1, depth + 1)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if possible { | ||||
|             l = bytes; | ||||
|         } else { | ||||
|             r = bytes; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     format!("{},{}", input[l].0, input[l].1).to_string() | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "5,4
 | ||||
| 4,2 | ||||
| 4,5 | ||||
| 3,0 | ||||
| 2,1 | ||||
| 6,3 | ||||
| 2,4 | ||||
| 1,5 | ||||
| 0,6 | ||||
| 3,3 | ||||
| 2,6 | ||||
| 5,1 | ||||
| 1,2 | ||||
| 5,5 | ||||
| 2,5 | ||||
| 6,5 | ||||
| 1,4 | ||||
| 0,4 | ||||
| 6,4 | ||||
| 1,1 | ||||
| 6,1 | ||||
| 1,0 | ||||
| 0,5 | ||||
| 1,6 | ||||
| 2,0" | ||||
|             )), | ||||
|             22 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part2_example() { | ||||
|         assert_eq!( | ||||
|             part2(&parse( | ||||
|                 "5,4
 | ||||
| 4,2 | ||||
| 4,5 | ||||
| 3,0 | ||||
| 2,1 | ||||
| 6,3 | ||||
| 2,4 | ||||
| 1,5 | ||||
| 0,6 | ||||
| 3,3 | ||||
| 2,6 | ||||
| 5,1 | ||||
| 1,2 | ||||
| 5,5 | ||||
| 2,5 | ||||
| 6,5 | ||||
| 1,4 | ||||
| 0,4 | ||||
| 6,4 | ||||
| 1,1 | ||||
| 6,1 | ||||
| 1,0 | ||||
| 0,5 | ||||
| 1,6 | ||||
| 2,0" | ||||
|             )), | ||||
|             "6,1" | ||||
|         ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										120
									
								
								aoc_2024/src/day19.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								aoc_2024/src/day19.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,120 @@ | ||||
| use aoc_runner_derive::{aoc, aoc_generator}; | ||||
| use nom::{ | ||||
|     bytes::complete::tag, | ||||
|     character::complete::{newline, one_of}, | ||||
|     combinator::map, | ||||
|     multi::{many1, separated_list1}, | ||||
|     sequence::separated_pair, | ||||
|     IResult, | ||||
| }; | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||
| enum Color { | ||||
|     White, | ||||
|     Blue, | ||||
|     Black, | ||||
|     Red, | ||||
|     Green, | ||||
| } | ||||
| 
 | ||||
| type Input = (Vec<Vec<Color>>, Vec<Vec<Color>>); | ||||
| 
 | ||||
| #[aoc_generator(day19)] | ||||
| fn parse(input: &str) -> Input { | ||||
|     separated_pair( | ||||
|         separated_list1(tag(", "), many1(parse_color)), | ||||
|         tag("\n\n"), | ||||
|         separated_list1(newline, many1(parse_color)), | ||||
|     )(input) | ||||
|     .unwrap() | ||||
|     .1 | ||||
| } | ||||
| 
 | ||||
| fn parse_color(input: &str) -> IResult<&str, Color> { | ||||
|     map(one_of("wubrg"), |c| match c { | ||||
|         'w' => Color::White, | ||||
|         'u' => Color::Blue, | ||||
|         'b' => Color::Black, | ||||
|         'r' => Color::Red, | ||||
|         'g' => Color::Green, | ||||
|         _ => unreachable!(), | ||||
|     })(input) | ||||
| } | ||||
| 
 | ||||
| #[aoc(day19, part1)] | ||||
| fn part1(input: &Input) -> usize { | ||||
|     let towels = &input.0; | ||||
|     let patterns = &input.1; | ||||
| 
 | ||||
|     patterns | ||||
|         .iter() | ||||
|         .map(|pattern| { | ||||
|             let mut m = vec![0u64; pattern.len() + 1]; | ||||
|             m[0] = 1; | ||||
| 
 | ||||
|             for i in 1..=pattern.len() { | ||||
|                 for towel in towels { | ||||
|                     if towel.len() <= i && &pattern[i - towel.len()..i] == towel { | ||||
|                         m[i] += m[i - towel.len()]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             m[pattern.len()] | ||||
|         }) | ||||
|         .filter(|n| *n > 0) | ||||
|         .count() | ||||
| } | ||||
| 
 | ||||
| #[aoc(day19, part2)] | ||||
| fn part2(input: &Input) -> u64 { | ||||
|     let towels = &input.0; | ||||
|     let patterns = &input.1; | ||||
| 
 | ||||
|     patterns | ||||
|         .iter() | ||||
|         .map(|pattern| { | ||||
|             let mut m = vec![0u64; pattern.len() + 1]; | ||||
|             m[0] = 1; | ||||
| 
 | ||||
|             for i in 1..=pattern.len() { | ||||
|                 for towel in towels { | ||||
|                     if towel.len() <= i && &pattern[i - towel.len()..i] == towel { | ||||
|                         m[i] += m[i - towel.len()]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             m[pattern.len()] | ||||
|         }) | ||||
|         .sum() | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn part1_example() { | ||||
|         assert_eq!( | ||||
|             part1(&parse( | ||||
|                 "r, wr, b, g, bwu, rb, gb, br
 | ||||
| 
 | ||||
| brwrr | ||||
| bggr | ||||
| gbbr | ||||
| rrbgbr | ||||
| ubwu | ||||
| bwurrg | ||||
| brgr | ||||
| bbrgwb" | ||||
|             )), | ||||
|             6 | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     // #[test]
 | ||||
|     // fn part2_example() {
 | ||||
|     //     assert_eq!(part2(&parse("<EXAMPLE>")), 0);
 | ||||
|     // }
 | ||||
| } | ||||
| @ -1,3 +1,6 @@ | ||||
| mod day19; | ||||
| mod day18; | ||||
| mod day17; | ||||
| mod day1; | ||||
| mod day10; | ||||
| mod day11; | ||||
| @ -5,6 +8,7 @@ mod day12; | ||||
| mod day13; | ||||
| mod day14; | ||||
| mod day15; | ||||
| mod day16; | ||||
| mod day2; | ||||
| mod day3; | ||||
| mod day4; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user