Compare commits
	
		
			No commits in common. "0ecea977521602d7206fc3d64db5fa1a2a40b66b" and "4ce7184b1ec21d0311e9219a6d9b8b6bb0319e38" have entirely different histories.
		
	
	
		
			0ecea97752
			...
			4ce7184b1e
		
	
		
| @ -1,287 +0,0 @@ | |||||||
| 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);
 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,126 +0,0 @@ | |||||||
| 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" |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,205 +0,0 @@ | |||||||
| 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" |  | ||||||
|         ); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -1,120 +0,0 @@ | |||||||
| 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,6 +1,3 @@ | |||||||
| mod day19; |  | ||||||
| mod day18; |  | ||||||
| mod day17; |  | ||||||
| mod day1; | mod day1; | ||||||
| mod day10; | mod day10; | ||||||
| mod day11; | mod day11; | ||||||
| @ -8,7 +5,6 @@ mod day12; | |||||||
| mod day13; | mod day13; | ||||||
| mod day14; | mod day14; | ||||||
| mod day15; | mod day15; | ||||||
| mod day16; |  | ||||||
| mod day2; | mod day2; | ||||||
| mod day3; | mod day3; | ||||||
| mod day4; | mod day4; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user