├── .cargo └── config ├── .direnv └── bin │ ├── aoc-bench │ ├── aoc-run │ └── aoc-test ├── .envrc ├── .gitignore ├── Cargo.toml ├── README.md ├── rust-toolchain.toml ├── rustfmt.toml └── src ├── day01 ├── input.txt └── mod.rs ├── day02 ├── input.txt └── mod.rs ├── day03 ├── input.txt └── mod.rs ├── day04 ├── input.txt └── mod.rs ├── day05 ├── input.txt ├── mod.rs ├── part1.rs ├── part2.rs └── projection.rs ├── day06 ├── input.txt └── mod.rs ├── day07 ├── input.txt └── mod.rs ├── day08 ├── input.txt └── mod.rs ├── day09 ├── input.txt └── mod.rs ├── day10 ├── input.txt └── mod.rs ├── day11 ├── input.txt └── mod.rs ├── day12 ├── input.txt └── mod.rs ├── day13 ├── input.txt └── mod.rs ├── day14 ├── input.txt └── mod.rs ├── day15 ├── input.txt └── mod.rs ├── day16 ├── input.txt └── mod.rs ├── day17 ├── input.txt └── mod.rs ├── day18 ├── input.txt └── mod.rs ├── day19 ├── input.txt └── mod.rs ├── day20 ├── input.txt └── mod.rs ├── day21 ├── input.txt └── mod.rs ├── day22 ├── input.txt └── mod.rs ├── day23 ├── input.txt ├── input_alt.txt ├── input_hardest.txt ├── mod.rs └── tests.txt ├── day24 ├── input.txt ├── mod.rs └── pattern.txt ├── day25 ├── input.txt └── mod.rs ├── lib.rs ├── runner.rs └── utils.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | rustflags = ["-C", "target-cpu=native"] 3 | -------------------------------------------------------------------------------- /.direnv/bin/aoc-bench: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" 3 | PROJ_DIR=$SCRIPT_DIR/../.. 4 | export RUSTFLAGS="-Awarnings" 5 | cargo run --manifest-path $PROJ_DIR/Cargo.toml --target-dir $PROJ_DIR/target/direnv \ 6 | --release --bin runner -- --bench "$@" 7 | -------------------------------------------------------------------------------- /.direnv/bin/aoc-run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" 3 | PROJ_DIR=$SCRIPT_DIR/../.. 4 | export RUSTFLAGS="-Awarnings" 5 | cargo run --manifest-path $PROJ_DIR/Cargo.toml --target-dir $PROJ_DIR/target/direnv \ 6 | --release --bin runner -- "$@" 7 | -------------------------------------------------------------------------------- /.direnv/bin/aoc-test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)" 3 | PROJ_DIR=$SCRIPT_DIR/../.. 4 | export RUSTFLAGS="-Awarnings" 5 | cargo test --manifest-path $PROJ_DIR/Cargo.toml --target-dir $PROJ_DIR/target/direnv \ 6 | -- --test-threads 1 "$@" 7 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | PATH_add $(direnv_layout_dir)/bin 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | .idea/ 4 | flamegraph.* 5 | .ipynb-checkpoints/ 6 | *.ipynb 7 | /tmp/ 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aoc2021" 3 | version = "0.1.0" 4 | authors = ["Ivan Smirnov "] 5 | edition = "2021" 6 | default-run = "runner" 7 | 8 | [dependencies] 9 | arrayvec = "0.7" 10 | memchr = "2.4" 11 | core_simd = { git = "https://github.com/rust-lang/portable-simd.git" } 12 | structopt = "0.3" 13 | eyre = "0.6" 14 | ahash = "0.7" 15 | num-integer = "0.1" 16 | rayon = "1.5" 17 | petgraph = "0.6" 18 | 19 | [profile.release] 20 | #codegen-units = 1 21 | lto = "fat" 22 | panic = "abort" 23 | 24 | [lib] 25 | name = "aoc2021" 26 | path = "src/lib.rs" 27 | doctest = false 28 | 29 | [[bin]] 30 | name = "runner" 31 | path = "src/runner.rs" 32 | test = false 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aoc-2021 2 | 3 | Advent of Code 2021 -- highly optimized Rust solutions. 4 | 5 | There's a lot of unsafe code, all kinds of bit hackery, and SIMD (since it uses portable-simd crate, 6 | it can currently only compile on nightly). The main goal was to try and squeeze out as much performance 7 | as possible, both via using smart non-bruteforce algorithms when applicable, and by making full use 8 | of the hardware (be it SIMD or parallelisation). Most problems except a few run a single thread though. 9 | 10 | These are the benchmark results taken on Apple M1 laptop (these include the time to parse input for 11 | each part of each problem - there are no input 'generators' and so each input is parsed twice): 12 | 13 | ``` 14 | day part 1 part 2 15 | ------------------------------ 16 | day 01 3.67 μs 3.66 μs 17 | day 02 0.83 μs 0.83 μs 18 | day 03 0.32 μs 3.32 μs 19 | day 04 6.78 μs 6.79 μs 20 | day 05 38.9 μs 171 μs 21 | day 06 0.47 μs 1.21 μs 22 | day 07 3.33 μs 2.01 μs 23 | day 08 5.02 μs 14.4 μs 24 | day 09 0.35 μs 26.4 μs 25 | day 10 5.81 μs 6.17 μs 26 | day 11 12.2 μs 35.0 μs 27 | day 12 3.38 μs 10.9 μs 28 | day 13 10.5 μs 13.8 μs 29 | day 14 1.48 μs 5.14 μs 30 | day 15 92.4 μs 2859 μs 31 | day 16 1.84 μs 1.98 μs 32 | day 17 0.00 μs 0.71 μs 33 | day 18 59.5 μs 600 μs 34 | day 19 1082 μs 1026 μs 35 | day 20 69.3 μs 1689 μs 36 | day 21 0.73 μs 284 μs 37 | day 22 102 μs 378 μs 38 | day 23 28.2 μs 2587 μs 39 | day 24 0.54 μs 0.55 μs 40 | day 25 1079 μs 0.00 μs 41 | ------------------------------ 42 | total time = 12337 μs 43 | ``` 44 | 45 | Quick notes on solutions to some of the problems that were less trivial (the problems that 46 | are not mentioned were straightforward): 47 | 48 | - Day 5: part 1 is a simple orthogonal line sweep. Part 2 uses a modified version of line 49 | sweep algorithm where the scanline is vertical and there are separate active sets for 50 | all three types of lines (horizontal and both diagonal types). 51 | - Day 9: uses SIMD to speed up part 1. Part 2 is a known problem (4-CCL for binary images), 52 | so a union-find algorithm can be employed. 53 | - Day 12: uses a cache when traversing the graph; also, in part 1 simplifies the graph by 54 | removing some irrelevant nodes that have a single edge leading to a small cave. 55 | - Day 18: exploits the fact that there can be no split operations until there's at least 56 | one explode, so everything is unrolled in two passes; the first pass is explodes-only 57 | and in the second pass we process the splits inline. 58 | - Day 19: uses the fact that an unambiguous solution for a pair of scanners is guaranteed 59 | if there's a 12-point overlap; only L2 pairwise distances between beacons are used to 60 | find matching sets - then we build a connectivity graph between scanners. 61 | - Day 20: naive solution; planned to optimize it via SIMD but haven't had time to finish. 62 | - Day 21: classic bottom-up 5-D dynamic programming. 63 | - Day 22: one of the most non-trivial solutions - used the fact that overlaps of different 64 | cardinality can be found by enumerating cliques of the overlap graph; ported and modified 65 | networkx clique finding algorithm to make it work (surprisingly, it ended up being fast). 66 | - Day 23: track minimum possible remaining cost for all moves, use compact data structures 67 | and run DFS with some heuristics (try to select worst moves for A) and cost tracking. 68 | - Day 24: relies on the specific structure of the input (stack machine). 69 | - Day 25: used SIMD, ghost cells and lookup tables to speed it up (this is the BML traffic model). 70 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly-2021-12-01" 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | use_small_heuristics = "Max" 2 | use_field_init_shorthand = true 3 | use_try_shorthand = true 4 | empty_item_single_line = true 5 | edition = "2021" 6 | unstable_features = true 7 | fn_args_layout = "Compressed" 8 | -------------------------------------------------------------------------------- /src/day01/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | #[inline] 4 | fn count_increasing(mut s: &[u8]) -> u16 { 5 | let mut count = 0; 6 | let mut buf = [T::default(); N]; 7 | for i in 0..N - 1 { 8 | buf[i] = parse_int_fast::(&mut s); 9 | } 10 | while s.len() > 1 { 11 | let num = parse_int_fast::(&mut s); 12 | count += u16::from(num > buf[0]); 13 | buf[N - 1] = num; 14 | for i in 1..N { 15 | buf[i - 1] = buf[i]; 16 | } 17 | } 18 | count 19 | } 20 | 21 | pub fn input() -> &'static [u8] { 22 | include_bytes!("input.txt") 23 | } 24 | 25 | pub fn part1(s: &[u8]) -> u16 { 26 | count_increasing::(s) as _ 27 | } 28 | 29 | pub fn part2(s: &[u8]) -> u16 { 30 | count_increasing::(s) as _ 31 | } 32 | 33 | #[test] 34 | fn test_day01_part1() { 35 | assert_eq!(part1(input()), 1475); 36 | } 37 | 38 | #[test] 39 | fn test_day01_part2() { 40 | assert_eq!(part2(input()), 1516); 41 | } 42 | -------------------------------------------------------------------------------- /src/day02/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 4 | enum Dir { 5 | Forward(i32), 6 | Down(i32), 7 | Up(i32), 8 | } 9 | 10 | impl Dir { 11 | #[inline] 12 | pub fn parse_next(s: &mut &[u8]) -> Option { 13 | if s.len() <= 1 { 14 | return None; 15 | } 16 | let dir = match s.get_first() { 17 | b'f' => { 18 | *s = s.advance(8); 19 | Self::Forward(s.get_digit() as _) 20 | } 21 | b'd' => { 22 | *s = s.advance(5); 23 | Self::Down(s.get_digit() as _) 24 | } 25 | _ /* up */ => { 26 | *s = s.advance(3); 27 | Self::Up(s.get_digit() as _) 28 | } 29 | }; 30 | *s = s.advance(2); 31 | Some(dir) 32 | } 33 | } 34 | 35 | pub fn input() -> &'static [u8] { 36 | include_bytes!("input.txt") 37 | } 38 | 39 | pub fn part1(mut s: &[u8]) -> i32 { 40 | let (mut horizontal, mut depth) = (0, 0); 41 | while let Some(dir) = Dir::parse_next(&mut s) { 42 | match dir { 43 | Dir::Forward(x) => horizontal += x, 44 | Dir::Down(x) => depth += x, 45 | Dir::Up(x) => depth -= x, 46 | } 47 | } 48 | horizontal * depth 49 | } 50 | 51 | pub fn part2(mut s: &[u8]) -> i32 { 52 | let (mut horizontal, mut depth, mut aim) = (0, 0, 0); 53 | while let Some(dir) = Dir::parse_next(&mut s) { 54 | match dir { 55 | Dir::Forward(x) => { 56 | horizontal += x; 57 | depth += aim * x; 58 | } 59 | Dir::Down(x) => aim += x, 60 | Dir::Up(x) => aim -= x, 61 | } 62 | } 63 | horizontal * depth 64 | } 65 | 66 | #[test] 67 | fn test_day02_part1() { 68 | assert_eq!(part1(input()), 1427868); 69 | } 70 | 71 | #[test] 72 | fn test_day02_part2() { 73 | assert_eq!(part2(input()), 1568138742); 74 | } 75 | -------------------------------------------------------------------------------- /src/day03/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | pub fn input() -> &'static [u8] { 4 | include_bytes!("input.txt") 5 | } 6 | 7 | pub fn part1(mut s: &[u8]) -> u32 { 8 | use core_simd::{u16x16, u16x32}; 9 | const N: usize = 12; 10 | let mut count = 0_u16; 11 | let mut total = u16x32::splat(0); 12 | while s.len() >= 32 { 13 | let input: [u8; 32] = unsafe { *s.as_ptr().cast() }; 14 | let mut buf = [0; 32]; 15 | for i in 0..32 { 16 | buf[i] = input[i] as u16; 17 | } 18 | total += u16x32::from(buf); 19 | s = s.advance(26); 20 | count += 2; 21 | } 22 | let mut bits = [0_u16; 16]; 23 | let total = total.to_array(); 24 | for i in 0..N { 25 | bits[i] += total[i] + total[N + 1 + i]; 26 | } 27 | while s.len() > 1 { 28 | for i in 0..N { 29 | bits[i] += s.get_at(i) as u16; 30 | } 31 | count += 1; 32 | s = s.advance(13); 33 | } 34 | let bits = u16x16::from(bits); 35 | let threshold = u16x16::splat(((b'0' as u16) * count) + (count >> 1)); 36 | let most_bits = bits.lanes_ge(threshold).to_array(); 37 | let least_bits = bits.lanes_lt(threshold).to_array(); 38 | let (mut most, mut least) = (0_u16, 0_u16); 39 | for i in 0..N { 40 | most = most << 1 | most_bits[i] as u16; 41 | least = least << 1 | least_bits[i] as u16; 42 | } 43 | most as u32 * least as u32 44 | } 45 | 46 | pub fn part2(mut s: &[u8]) -> u32 { 47 | const N: usize = 12; 48 | let n = s.len() / (N + 1); 49 | let mut counts = [0_u8; 1 << N]; 50 | for _ in 0..n { 51 | let mut value = 0; 52 | for i in 0..N { 53 | let bit = s.get_at(i) == b'1'; 54 | value = (value << 1) | (bit as usize); 55 | } 56 | counts[value] += 1; 57 | s = s.advance(N + 1); 58 | } 59 | 60 | let mut offset_most = 0; 61 | let mut offset_least = 0; 62 | let mut total_most = n as u16; 63 | let mut total_least = n as u16; 64 | let mut size = 1 << N; 65 | for _ in 0..N { 66 | size >>= 1; 67 | let (mut most0, mut least0) = (0, 0); 68 | for j in 0..size { 69 | most0 += counts[offset_most + j] as u16; 70 | least0 += counts[offset_least + j] as u16; 71 | } 72 | let most1 = total_most - most0; 73 | let least1 = total_least - least0; 74 | total_most = if most0 == 0 || (most1 != 0 && most1 >= most0) { 75 | offset_most += size; 76 | most1 77 | } else { 78 | most0 79 | }; 80 | total_least = if least0 == 0 || (least1 != 0 && least1 < least0) { 81 | offset_least += size; 82 | least1 83 | } else { 84 | least0 85 | }; 86 | } 87 | offset_most as u32 * offset_least as u32 88 | } 89 | 90 | #[test] 91 | fn test_day03_part1() { 92 | assert_eq!(part1(input()), 3959450); 93 | } 94 | 95 | #[test] 96 | fn test_day03_part2() { 97 | assert_eq!(part2(input()), 7440311); 98 | } 99 | -------------------------------------------------------------------------------- /src/day04/input.txt: -------------------------------------------------------------------------------- 1 | 67,3,19,4,64,39,85,14,84,93,79,26,61,24,65,63,15,69,48,8,82,75,36,96,16,49,28,40,97,38,76,91,83,7,62,94,21,95,6,10,43,17,31,34,81,23,52,60,54,29,70,12,35,0,57,45,20,71,78,44,90,2,33,68,53,92,50,73,88,47,58,5,9,87,22,13,18,30,59,56,99,11,77,55,72,32,37,89,42,27,66,41,86,51,74,1,46,25,98,80 2 | 3 | 24 75 59 41 17 4 | 58 74 64 92 39 5 | 68 8 78 85 72 6 | 18 3 22 4 34 7 | 11 76 6 28 50 8 | 9 | 21 31 36 13 87 10 | 80 91 63 62 77 11 | 46 93 40 16 25 12 | 47 66 30 54 74 13 | 56 59 86 72 37 14 | 15 | 92 43 68 60 81 16 | 3 78 75 73 12 17 | 90 50 31 67 76 18 | 28 63 52 95 61 19 | 6 38 79 19 17 20 | 21 | 81 20 61 60 86 22 | 43 27 50 21 85 23 | 77 84 68 76 24 24 | 33 13 89 1 48 25 | 6 57 30 11 5 26 | 27 | 66 24 22 86 2 28 | 67 77 72 88 87 29 | 21 60 89 36 32 30 | 39 37 29 17 31 31 | 78 97 63 94 91 32 | 33 | 85 71 86 16 54 34 | 98 11 82 89 17 35 | 38 23 99 59 69 36 | 58 12 74 15 93 37 | 41 5 52 48 26 38 | 39 | 3 32 61 29 27 40 | 98 74 34 58 23 41 | 24 54 76 79 88 42 | 71 90 97 96 68 43 | 21 33 72 47 82 44 | 45 | 13 70 59 7 91 46 | 74 88 85 50 15 47 | 35 8 40 93 6 48 | 95 29 52 18 99 49 | 57 64 0 9 39 50 | 51 | 72 6 74 64 0 52 | 73 9 46 52 98 53 | 81 68 14 69 48 54 | 25 17 5 54 19 55 | 11 47 33 23 62 56 | 57 | 45 14 90 59 97 58 | 43 46 58 55 29 59 | 80 53 2 37 78 60 | 40 79 57 52 72 61 | 92 13 54 25 19 62 | 63 | 39 78 99 84 2 64 | 80 53 24 51 5 65 | 33 20 48 43 66 66 | 82 13 52 30 98 67 | 14 16 26 44 74 68 | 69 | 38 35 45 83 94 70 | 18 28 41 22 13 71 | 44 9 10 98 58 72 | 64 73 24 31 34 73 | 39 85 50 77 63 74 | 75 | 71 18 68 47 65 76 | 25 40 82 69 44 77 | 30 6 72 73 7 78 | 80 24 41 79 2 79 | 11 20 96 84 54 80 | 81 | 16 6 38 75 25 82 | 56 2 51 69 81 83 | 15 54 91 85 90 84 | 94 0 7 71 30 85 | 28 17 76 67 31 86 | 87 | 13 12 23 7 71 88 | 91 89 84 40 78 89 | 44 83 90 21 31 90 | 77 17 3 95 42 91 | 87 82 38 30 67 92 | 93 | 44 64 60 76 36 94 | 21 39 86 89 34 95 | 5 54 24 14 58 96 | 78 55 98 74 69 97 | 2 97 42 59 51 98 | 99 | 51 35 78 54 40 100 | 9 52 5 66 19 101 | 92 74 68 90 73 102 | 76 11 60 67 22 103 | 44 7 1 89 15 104 | 105 | 93 72 3 95 13 106 | 77 1 32 35 5 107 | 68 91 98 23 51 108 | 59 19 31 57 56 109 | 54 46 92 88 26 110 | 111 | 84 91 40 9 73 112 | 90 41 51 12 10 113 | 0 61 89 13 8 114 | 62 74 5 45 92 115 | 65 27 78 26 31 116 | 117 | 54 21 32 84 42 118 | 68 25 76 3 40 119 | 24 15 59 12 2 120 | 72 49 73 31 93 121 | 35 67 70 60 91 122 | 123 | 55 34 51 76 54 124 | 73 28 5 87 52 125 | 24 36 65 49 27 126 | 99 10 12 44 50 127 | 23 77 53 80 4 128 | 129 | 30 42 92 11 40 130 | 83 49 41 72 54 131 | 73 97 18 4 37 132 | 0 15 70 55 33 133 | 71 26 46 25 81 134 | 135 | 22 35 41 71 58 136 | 55 39 18 85 45 137 | 79 44 9 38 2 138 | 47 4 23 34 82 139 | 49 63 88 81 29 140 | 141 | 49 82 40 37 77 142 | 17 45 92 7 65 143 | 51 38 91 68 32 144 | 73 57 69 85 50 145 | 87 10 95 59 1 146 | 147 | 57 27 95 59 87 148 | 78 96 82 63 52 149 | 39 17 14 74 21 150 | 47 64 28 94 65 151 | 40 3 49 25 61 152 | 153 | 97 9 24 80 27 154 | 5 36 83 15 29 155 | 86 33 32 61 2 156 | 87 48 82 91 4 157 | 35 10 16 85 65 158 | 159 | 17 12 43 96 5 160 | 36 76 29 51 73 161 | 98 66 27 97 91 162 | 78 28 2 61 30 163 | 95 70 19 47 54 164 | 165 | 98 88 51 32 7 166 | 89 61 16 91 95 167 | 94 23 19 77 70 168 | 42 90 36 26 44 169 | 99 71 5 57 13 170 | 171 | 14 43 97 72 83 172 | 39 73 58 16 59 173 | 51 2 28 24 18 174 | 40 70 65 27 91 175 | 4 44 68 74 56 176 | 177 | 90 9 71 23 73 178 | 11 95 62 36 38 179 | 77 34 60 67 41 180 | 28 48 98 40 42 181 | 47 51 82 87 63 182 | 183 | 19 41 57 61 50 184 | 64 84 8 81 11 185 | 83 68 31 66 90 186 | 2 72 71 96 79 187 | 78 89 77 60 4 188 | 189 | 73 88 72 23 68 190 | 98 52 21 89 43 191 | 48 29 10 8 6 192 | 49 3 54 37 12 193 | 83 34 51 77 66 194 | 195 | 52 16 94 84 81 196 | 3 87 99 72 98 197 | 48 10 44 32 22 198 | 9 69 36 74 62 199 | 51 42 91 68 60 200 | 201 | 39 54 16 97 14 202 | 58 84 89 15 20 203 | 67 49 19 55 86 204 | 10 44 76 12 96 205 | 74 36 51 41 2 206 | 207 | 27 22 90 79 86 208 | 47 73 2 53 58 209 | 31 89 37 19 12 210 | 20 83 87 23 30 211 | 32 8 92 55 68 212 | 213 | 19 39 64 53 12 214 | 32 7 80 72 79 215 | 82 96 21 13 40 216 | 18 25 61 9 70 217 | 84 95 42 36 52 218 | 219 | 48 12 29 61 7 220 | 34 13 99 98 6 221 | 74 36 66 91 88 222 | 75 85 93 80 83 223 | 96 11 44 47 39 224 | 225 | 79 43 28 16 75 226 | 66 64 17 71 72 227 | 36 30 19 60 38 228 | 1 13 77 69 94 229 | 78 6 97 93 63 230 | 231 | 86 45 14 38 37 232 | 35 20 15 68 55 233 | 92 3 0 90 8 234 | 88 32 87 17 22 235 | 33 34 78 13 43 236 | 237 | 87 92 58 95 6 238 | 35 23 54 40 97 239 | 82 64 88 10 94 240 | 63 8 26 98 18 241 | 42 76 39 50 51 242 | 243 | 75 13 4 72 95 244 | 11 50 15 47 52 245 | 12 73 80 74 70 246 | 68 30 21 37 58 247 | 91 2 24 32 82 248 | 249 | 76 66 4 68 79 250 | 19 73 24 51 96 251 | 16 52 26 78 7 252 | 48 30 17 82 92 253 | 28 88 90 71 59 254 | 255 | 95 18 69 85 63 256 | 16 78 97 10 41 257 | 53 98 73 87 19 258 | 15 35 94 57 82 259 | 48 40 14 3 38 260 | 261 | 39 40 78 64 87 262 | 90 69 83 18 16 263 | 58 91 36 23 74 264 | 25 51 99 4 76 265 | 62 10 88 2 1 266 | 267 | 72 95 34 2 84 268 | 38 12 97 92 47 269 | 24 23 41 10 75 270 | 56 87 68 45 89 271 | 14 85 52 98 79 272 | 273 | 96 97 15 98 17 274 | 76 13 6 38 81 275 | 66 90 51 36 85 276 | 95 48 40 99 94 277 | 69 88 19 4 1 278 | 279 | 20 36 93 50 35 280 | 13 15 6 49 92 281 | 0 70 38 29 22 282 | 68 34 73 89 71 283 | 5 10 12 79 31 284 | 285 | 16 63 34 29 2 286 | 43 57 18 51 67 287 | 83 47 49 17 96 288 | 84 33 40 7 50 289 | 60 30 41 81 76 290 | 291 | 86 85 4 48 61 292 | 34 46 89 78 23 293 | 83 8 43 57 30 294 | 21 36 7 75 37 295 | 29 40 62 60 54 296 | 297 | 47 28 42 39 57 298 | 16 46 54 52 55 299 | 78 84 32 95 23 300 | 27 26 9 75 62 301 | 90 85 0 65 37 302 | 303 | 89 46 4 81 55 304 | 68 13 79 18 90 305 | 57 73 21 15 32 306 | 59 56 62 58 36 307 | 45 98 64 33 12 308 | 309 | 89 92 3 69 78 310 | 45 50 12 71 72 311 | 18 87 64 48 88 312 | 84 77 53 17 62 313 | 68 6 83 91 2 314 | 315 | 5 80 25 90 19 316 | 21 86 66 69 61 317 | 22 59 39 54 91 318 | 9 27 14 24 40 319 | 95 74 18 63 11 320 | 321 | 84 63 42 80 61 322 | 23 39 49 92 25 323 | 56 64 70 2 88 324 | 99 29 15 26 9 325 | 82 91 35 7 40 326 | 327 | 4 93 44 42 16 328 | 78 72 32 73 81 329 | 84 91 85 82 69 330 | 88 49 59 92 96 331 | 61 99 19 33 38 332 | 333 | 87 2 46 16 83 334 | 29 31 45 37 51 335 | 25 65 26 89 19 336 | 80 17 27 8 73 337 | 54 4 76 0 12 338 | 339 | 50 65 47 43 31 340 | 58 94 90 71 12 341 | 27 3 81 45 9 342 | 1 33 37 15 83 343 | 96 26 41 77 57 344 | 345 | 22 54 71 73 5 346 | 64 77 15 98 38 347 | 61 90 20 57 40 348 | 60 18 83 72 12 349 | 34 91 87 41 21 350 | 351 | 82 29 51 16 61 352 | 37 41 86 20 19 353 | 59 30 43 15 53 354 | 17 83 5 14 89 355 | 78 70 1 12 62 356 | 357 | 19 95 68 67 92 358 | 14 70 73 62 29 359 | 40 9 97 82 66 360 | 11 50 77 47 53 361 | 20 75 88 94 93 362 | 363 | 48 39 62 56 44 364 | 95 43 10 89 60 365 | 40 0 73 17 59 366 | 50 2 8 4 5 367 | 24 79 20 13 96 368 | 369 | 25 40 36 54 13 370 | 46 48 37 71 26 371 | 29 42 27 44 23 372 | 24 61 79 3 90 373 | 97 21 43 86 18 374 | 375 | 95 4 14 12 71 376 | 11 55 50 83 85 377 | 9 43 29 32 28 378 | 78 20 63 87 40 379 | 61 84 37 75 77 380 | 381 | 4 96 87 22 2 382 | 95 70 39 35 49 383 | 23 27 19 43 0 384 | 42 75 36 52 11 385 | 13 8 57 88 46 386 | 387 | 37 5 87 58 86 388 | 65 78 89 57 79 389 | 70 40 14 80 97 390 | 88 55 68 28 13 391 | 53 59 24 26 1 392 | 393 | 5 95 59 71 23 394 | 44 57 34 65 83 395 | 49 93 9 77 28 396 | 37 69 79 99 73 397 | 17 27 33 66 85 398 | 399 | 75 61 32 0 16 400 | 65 59 47 25 81 401 | 87 97 8 50 70 402 | 78 34 38 42 51 403 | 22 63 6 66 1 404 | 405 | 65 68 77 1 19 406 | 53 14 7 88 9 407 | 11 22 40 25 39 408 | 69 93 37 72 5 409 | 90 80 38 10 16 410 | 411 | 15 81 62 68 44 412 | 26 70 43 55 89 413 | 22 69 8 94 51 414 | 52 19 79 96 10 415 | 24 48 63 74 84 416 | 417 | 36 9 57 4 40 418 | 95 98 58 70 87 419 | 45 97 92 23 86 420 | 6 31 15 78 12 421 | 90 75 48 41 3 422 | 423 | 34 97 31 92 20 424 | 59 6 89 79 70 425 | 39 90 16 72 91 426 | 76 75 85 47 68 427 | 86 62 32 19 64 428 | 429 | 44 5 72 25 32 430 | 87 18 93 33 0 431 | 22 96 46 4 28 432 | 61 81 77 52 80 433 | 66 24 63 23 45 434 | 435 | 53 33 99 31 75 436 | 60 39 56 89 57 437 | 76 81 14 95 23 438 | 8 19 98 13 5 439 | 49 91 54 47 7 440 | 441 | 11 58 44 6 94 442 | 31 87 50 77 22 443 | 49 9 40 24 60 444 | 86 36 12 3 71 445 | 59 99 68 20 66 446 | 447 | 83 11 93 36 6 448 | 73 55 97 48 18 449 | 3 43 51 90 57 450 | 38 65 39 95 68 451 | 94 24 59 20 34 452 | 453 | 53 57 69 3 16 454 | 2 91 22 24 26 455 | 44 84 31 28 82 456 | 46 94 65 78 99 457 | 55 49 11 66 21 458 | 459 | 10 53 20 69 41 460 | 70 12 56 2 94 461 | 87 23 74 60 55 462 | 59 67 18 38 22 463 | 71 4 51 81 39 464 | 465 | 59 32 64 66 53 466 | 20 11 27 10 81 467 | 41 93 12 45 99 468 | 70 94 77 16 76 469 | 30 79 57 0 90 470 | 471 | 84 8 76 13 98 472 | 96 1 9 65 38 473 | 23 30 64 3 95 474 | 70 26 34 86 79 475 | 2 22 77 41 68 476 | 477 | 77 11 55 80 21 478 | 45 70 28 0 57 479 | 38 74 33 86 22 480 | 42 13 66 61 83 481 | 46 94 7 82 40 482 | 483 | 53 68 94 71 64 484 | 44 99 86 66 97 485 | 80 33 48 74 45 486 | 29 13 11 15 62 487 | 36 89 9 47 56 488 | 489 | 49 90 16 55 14 490 | 68 13 27 47 46 491 | 54 93 97 10 31 492 | 33 58 6 83 48 493 | 63 28 95 8 62 494 | 495 | 72 60 12 24 20 496 | 1 22 90 58 65 497 | 84 5 96 80 33 498 | 64 15 47 23 46 499 | 63 36 6 31 91 500 | 501 | 19 27 96 54 36 502 | 33 32 65 11 26 503 | 0 47 25 59 56 504 | 41 45 76 14 98 505 | 52 22 31 66 38 506 | 507 | 7 91 5 18 14 508 | 4 19 54 42 71 509 | 31 82 81 61 39 510 | 58 51 70 10 55 511 | 43 60 15 89 21 512 | 513 | 85 31 75 55 76 514 | 92 93 54 98 44 515 | 21 22 6 79 20 516 | 34 64 7 82 78 517 | 53 36 96 37 19 518 | 519 | 84 58 35 68 76 520 | 79 91 92 25 29 521 | 93 83 23 22 80 522 | 51 28 53 60 40 523 | 0 62 77 49 39 524 | 525 | 35 38 24 88 53 526 | 61 30 52 49 83 527 | 20 97 6 16 55 528 | 60 43 14 67 4 529 | 66 9 85 28 77 530 | 531 | 73 57 65 36 50 532 | 18 94 14 59 67 533 | 7 78 40 6 13 534 | 86 49 5 22 66 535 | 63 32 68 44 80 536 | 537 | 52 95 93 25 16 538 | 0 83 41 77 49 539 | 13 63 65 84 69 540 | 51 9 39 47 24 541 | 92 4 14 8 66 542 | 543 | 70 31 33 69 50 544 | 36 29 76 56 64 545 | 97 11 40 19 81 546 | 18 57 10 24 15 547 | 30 44 42 89 60 548 | 549 | 42 97 9 38 60 550 | 48 62 53 70 27 551 | 49 72 90 86 18 552 | 69 50 8 78 84 553 | 28 13 17 10 35 554 | 555 | 84 7 60 17 36 556 | 30 1 3 89 49 557 | 45 10 85 97 76 558 | 31 38 16 2 12 559 | 43 58 11 77 78 560 | 561 | 53 20 98 94 82 562 | 54 62 27 92 83 563 | 60 41 66 5 30 564 | 58 15 90 88 3 565 | 38 45 7 26 37 566 | 567 | 62 94 17 55 28 568 | 27 86 26 42 87 569 | 90 18 84 20 85 570 | 92 97 59 83 0 571 | 89 21 25 36 11 572 | 573 | 89 60 41 91 54 574 | 16 9 57 40 53 575 | 87 56 64 23 27 576 | 13 42 84 2 52 577 | 66 77 80 0 38 578 | 579 | 58 23 55 96 75 580 | 56 8 19 52 10 581 | 98 13 70 62 73 582 | 6 64 86 4 12 583 | 51 91 93 29 34 584 | 585 | 55 8 99 51 70 586 | 33 30 52 58 10 587 | 38 31 87 9 61 588 | 63 46 15 48 24 589 | 32 94 40 74 21 590 | 591 | 5 70 26 48 28 592 | 41 35 93 34 44 593 | 46 86 19 0 27 594 | 7 81 51 95 15 595 | 36 84 76 75 92 596 | 597 | 34 0 31 21 3 598 | 23 96 49 51 11 599 | 42 27 47 66 91 600 | 93 89 16 62 54 601 | 22 71 26 32 99 602 | -------------------------------------------------------------------------------- /src/day04/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Debug}; 2 | 3 | use crate::utils::*; 4 | 5 | const N: usize = 5; 6 | 7 | type Number = u8; 8 | type Score = u32; 9 | 10 | #[inline] 11 | fn parse_numbers(s: &mut &[u8]) -> Vec { 12 | let mut numbers = Vec::with_capacity(1 << 7); 13 | while s.get_at(0) != b'\n' { 14 | numbers.push(parse_int_fast::<_, 1, 2>(s)); 15 | } 16 | *s = s.advance(2); 17 | numbers 18 | } 19 | 20 | type Board = [[Number; N]; N]; 21 | 22 | fn parse_board(s: &mut &[u8]) -> Board { 23 | let mut board = Board::default(); 24 | for i in 0..N { 25 | for j in 0..N { 26 | if s.get_at(0) == b' ' { 27 | *s = s.advance(1); 28 | } 29 | let num = parse_int_fast::(s); 30 | board[i][j] = num; 31 | } 32 | } 33 | *s = s.advance(1); 34 | board 35 | } 36 | 37 | fn time_to_win(board: &Board, draw_times: &[usize]) -> usize { 38 | let (mut max_cols, mut max_rows) = ([0; N], [0; N]); 39 | for i in 0..N { 40 | for j in 0..N { 41 | let draw_time = unsafe { 42 | *draw_times.get_unchecked(*board.get_unchecked(i).get_unchecked(j) as usize) 43 | }; 44 | max_cols[j] = max_cols[j].max(draw_time); 45 | max_rows[i] = max_rows[i].max(draw_time); 46 | } 47 | } 48 | max_cols.into_iter().min().unwrap_or(0).min(max_rows.into_iter().min().unwrap_or(0)) 49 | } 50 | 51 | fn solve(mut s: &[u8], ttw_is_better: impl Fn(usize, usize) -> bool, ttw_init: usize) -> Score { 52 | // Credits for the algorithm idea: @orlp 53 | 54 | let numbers = parse_numbers(&mut s); 55 | let mut draw_times = [0; 1 << 8]; 56 | for (t, &num) in numbers.iter().enumerate() { 57 | draw_times[num as usize] = t; 58 | } 59 | let mut boards = Vec::with_capacity(100); 60 | let (mut ttw_best, mut idx_best) = (ttw_init, usize::MAX); 61 | while s.len() > 1 { 62 | let board = parse_board(&mut s); 63 | let ttw = time_to_win(&board, &draw_times); 64 | if ttw_is_better(ttw, ttw_best) { 65 | ttw_best = ttw; 66 | idx_best = boards.len(); 67 | } 68 | boards.push(board); 69 | } 70 | 71 | let board = boards[idx_best]; 72 | let mut sum_unmasked = 0; 73 | for i in 0..N { 74 | for j in 0..N { 75 | let num = board[i][j]; 76 | if draw_times.get_at(num as usize) > ttw_best { 77 | sum_unmasked += num as Score; 78 | } 79 | } 80 | } 81 | sum_unmasked * numbers.get_at(ttw_best) as Score 82 | } 83 | 84 | pub fn input() -> &'static [u8] { 85 | include_bytes!("input.txt") 86 | } 87 | 88 | pub fn part1(s: &[u8]) -> Score { 89 | solve(s, |ttw, ttw_best| ttw < ttw_best, usize::MAX) 90 | } 91 | 92 | pub fn part2(s: &[u8]) -> Score { 93 | solve(s, |ttw, ttw_best| ttw > ttw_best, 0) 94 | } 95 | 96 | // Below is the original mask-based solution (12us / 24us). 97 | 98 | type Mask = u128; 99 | 100 | #[derive(Clone, Copy, Default)] 101 | pub struct BoardMasks { 102 | masks: [Mask; N * 2], // N horizontal, N vertical 103 | } 104 | 105 | impl BoardMasks { 106 | pub fn parse(s: &mut &[u8]) -> Self { 107 | let mut board = Self::default(); 108 | for i in 0..N { 109 | for j in 0..N { 110 | if s.get_at(0) == b' ' { 111 | *s = s.advance(1); 112 | } 113 | let num = parse_int_fast::(s); 114 | let mask = 1_u128 << (1 + num); // we add 1 to all values so 0 is free 115 | board.masks[i] |= mask; 116 | board.masks[N + j] |= mask; 117 | } 118 | } 119 | *s = s.advance(1); 120 | board 121 | } 122 | 123 | pub fn score(&self, number: Number) -> Score { 124 | let mut sum = 0; 125 | for i in 0..N { 126 | let mut mask = self.masks[i]; 127 | let mut pos = 0; 128 | for _ in 0..mask.count_ones() { 129 | let num = mask.trailing_zeros(); 130 | pos += num + 1; 131 | sum += pos - 2; // because we added 1 to all numbers 132 | mask >>= num + 1; 133 | } 134 | } 135 | sum * (number as Score) 136 | } 137 | } 138 | 139 | impl Debug for BoardMasks { 140 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 141 | for i in 0..N { 142 | let row_mask = self.masks[i]; 143 | for j in 0..N { 144 | let col_mask = self.masks[N + j]; 145 | let num = (row_mask & col_mask).trailing_zeros() - 1; // make sure to subtract 1 146 | write!(f, "{:>w$}", num, w = 2 + (j != 0) as usize)?; 147 | } 148 | if i != N - 1 { 149 | writeln!(f)?; 150 | } 151 | } 152 | Ok(()) 153 | } 154 | } 155 | 156 | fn parse_numbers_and_masks(mut s: &[u8]) -> (Vec, Vec) { 157 | let numbers = parse_numbers(&mut s); 158 | let mut boards = Vec::with_capacity(1 << 7); 159 | while s.len() > 1 { 160 | boards.push(BoardMasks::parse(&mut s)); 161 | } 162 | (numbers, boards) 163 | } 164 | 165 | #[inline] 166 | pub fn part1_u128(s: &[u8]) -> Score { 167 | let (numbers, mut boards) = parse_numbers_and_masks(s); 168 | for (k, &num) in numbers.iter().enumerate() { 169 | let m = !(1_u128 << (num + 1)); 170 | for board in &mut boards { 171 | for mask in &mut board.masks { 172 | *mask &= m; 173 | if k >= N && *mask == 0 { 174 | return board.score(num); 175 | } 176 | } 177 | } 178 | } 179 | 0 180 | } 181 | 182 | #[inline] 183 | pub fn part2_u128(s: &[u8]) -> Score { 184 | let (numbers, mut boards) = parse_numbers_and_masks(s); 185 | let n_boards = boards.len(); 186 | let (mut n_winners, mut is_win) = (0, vec![false; n_boards]); 187 | for (k, &num) in numbers.iter().enumerate() { 188 | let m = !(1_u128 << (num + 1)); 189 | 'board: for (j, board) in boards.iter_mut().enumerate() { 190 | if is_win[j] { 191 | continue; 192 | } 193 | for mask in &mut board.masks { 194 | *mask &= m; 195 | if k >= N && *mask == 0 { 196 | n_winners += 1; 197 | is_win[j] = true; 198 | if n_winners == n_boards { 199 | return board.score(num); 200 | } 201 | continue 'board; 202 | } 203 | } 204 | } 205 | } 206 | 0 207 | } 208 | 209 | #[test] 210 | fn test_day04_part1() { 211 | assert_eq!(part1(input()), 28082); 212 | } 213 | 214 | #[test] 215 | fn test_day04_part2() { 216 | assert_eq!(part2(input()), 8224); 217 | } 218 | -------------------------------------------------------------------------------- /src/day05/input.txt: -------------------------------------------------------------------------------- 1 | 456,846 -> 221,846 2 | 980,926 -> 73,19 3 | 682,930 -> 562,930 4 | 766,592 -> 274,100 5 | 247,685 -> 247,21 6 | 106,800 -> 635,800 7 | 953,340 -> 135,340 8 | 293,223 -> 293,12 9 | 454,196 -> 454,463 10 | 886,766 -> 164,766 11 | 592,590 -> 192,590 12 | 436,982 -> 436,545 13 | 731,571 -> 420,260 14 | 741,11 -> 466,11 15 | 727,541 -> 579,541 16 | 341,553 -> 25,553 17 | 942,470 -> 942,196 18 | 203,600 -> 203,647 19 | 965,595 -> 949,611 20 | 554,306 -> 554,401 21 | 902,438 -> 902,728 22 | 864,609 -> 525,270 23 | 187,790 -> 187,323 24 | 956,950 -> 427,950 25 | 847,554 -> 422,554 26 | 935,900 -> 701,900 27 | 192,854 -> 866,180 28 | 512,946 -> 543,915 29 | 978,979 -> 491,979 30 | 708,61 -> 708,878 31 | 738,508 -> 282,52 32 | 23,25 -> 841,843 33 | 204,750 -> 204,797 34 | 703,500 -> 703,419 35 | 14,311 -> 694,311 36 | 646,301 -> 785,301 37 | 397,168 -> 439,168 38 | 680,931 -> 561,812 39 | 540,448 -> 90,448 40 | 706,668 -> 91,53 41 | 848,319 -> 318,319 42 | 198,948 -> 198,307 43 | 686,58 -> 686,541 44 | 867,234 -> 867,498 45 | 134,125 -> 134,688 46 | 824,566 -> 53,566 47 | 437,167 -> 276,167 48 | 94,65 -> 638,609 49 | 36,971 -> 971,36 50 | 494,330 -> 494,197 51 | 920,438 -> 920,364 52 | 698,84 -> 49,733 53 | 59,842 -> 59,876 54 | 328,577 -> 328,677 55 | 757,701 -> 134,78 56 | 466,274 -> 135,605 57 | 81,925 -> 988,18 58 | 40,142 -> 882,984 59 | 50,96 -> 882,928 60 | 782,47 -> 782,427 61 | 247,599 -> 24,599 62 | 112,812 -> 191,733 63 | 487,198 -> 144,198 64 | 327,663 -> 327,756 65 | 117,76 -> 688,76 66 | 530,71 -> 530,958 67 | 558,602 -> 671,489 68 | 677,830 -> 677,556 69 | 529,669 -> 349,669 70 | 336,966 -> 341,971 71 | 20,31 -> 851,862 72 | 423,880 -> 423,573 73 | 521,657 -> 552,657 74 | 412,822 -> 18,428 75 | 423,311 -> 423,105 76 | 381,614 -> 705,614 77 | 521,248 -> 394,121 78 | 286,47 -> 286,403 79 | 286,27 -> 711,452 80 | 347,61 -> 489,61 81 | 760,454 -> 760,954 82 | 746,573 -> 911,573 83 | 839,933 -> 839,776 84 | 124,815 -> 290,649 85 | 577,848 -> 419,848 86 | 393,206 -> 410,206 87 | 364,755 -> 881,755 88 | 788,68 -> 788,215 89 | 94,798 -> 192,798 90 | 292,250 -> 453,250 91 | 601,545 -> 293,237 92 | 438,923 -> 438,655 93 | 70,757 -> 887,757 94 | 184,402 -> 818,402 95 | 586,49 -> 103,49 96 | 202,315 -> 735,315 97 | 534,504 -> 534,523 98 | 367,236 -> 367,736 99 | 24,163 -> 24,240 100 | 185,426 -> 634,875 101 | 485,189 -> 39,189 102 | 556,30 -> 374,30 103 | 969,821 -> 676,528 104 | 254,435 -> 254,43 105 | 290,615 -> 741,164 106 | 345,601 -> 120,826 107 | 224,641 -> 887,641 108 | 190,716 -> 581,325 109 | 552,646 -> 552,393 110 | 413,177 -> 413,103 111 | 397,900 -> 360,900 112 | 138,980 -> 138,55 113 | 909,891 -> 909,593 114 | 926,986 -> 79,139 115 | 954,67 -> 53,968 116 | 180,30 -> 595,30 117 | 823,165 -> 823,660 118 | 285,176 -> 375,176 119 | 915,826 -> 184,95 120 | 735,230 -> 667,230 121 | 934,865 -> 917,865 122 | 48,602 -> 737,602 123 | 477,319 -> 385,411 124 | 981,17 -> 11,987 125 | 458,401 -> 24,401 126 | 118,415 -> 849,415 127 | 176,678 -> 176,852 128 | 567,753 -> 567,37 129 | 285,868 -> 830,323 130 | 555,623 -> 822,623 131 | 522,546 -> 674,546 132 | 880,21 -> 23,878 133 | 591,103 -> 591,407 134 | 434,64 -> 434,401 135 | 245,968 -> 275,968 136 | 726,510 -> 450,786 137 | 768,366 -> 768,738 138 | 488,745 -> 488,94 139 | 675,674 -> 675,705 140 | 618,237 -> 265,237 141 | 802,709 -> 802,59 142 | 144,696 -> 144,542 143 | 547,381 -> 547,799 144 | 78,667 -> 78,916 145 | 409,271 -> 302,271 146 | 294,694 -> 938,50 147 | 140,571 -> 97,571 148 | 682,875 -> 682,534 149 | 748,816 -> 748,183 150 | 84,622 -> 84,258 151 | 485,696 -> 582,599 152 | 909,233 -> 954,233 153 | 203,711 -> 203,350 154 | 335,904 -> 455,904 155 | 578,778 -> 578,21 156 | 830,954 -> 902,954 157 | 78,252 -> 78,682 158 | 920,220 -> 684,220 159 | 309,301 -> 104,301 160 | 270,795 -> 270,919 161 | 906,479 -> 304,479 162 | 627,164 -> 627,986 163 | 122,960 -> 915,167 164 | 664,916 -> 770,810 165 | 692,810 -> 826,810 166 | 981,951 -> 192,162 167 | 183,423 -> 809,423 168 | 632,464 -> 567,464 169 | 94,266 -> 94,587 170 | 261,770 -> 569,770 171 | 51,403 -> 466,818 172 | 631,645 -> 187,645 173 | 141,238 -> 141,145 174 | 357,21 -> 173,21 175 | 138,248 -> 839,949 176 | 889,957 -> 807,957 177 | 399,431 -> 105,725 178 | 548,331 -> 548,821 179 | 790,844 -> 43,97 180 | 675,671 -> 221,671 181 | 874,143 -> 620,397 182 | 205,435 -> 205,546 183 | 521,434 -> 822,133 184 | 141,86 -> 257,86 185 | 427,28 -> 290,165 186 | 49,694 -> 567,694 187 | 846,344 -> 266,924 188 | 425,910 -> 433,918 189 | 956,498 -> 485,27 190 | 798,498 -> 798,634 191 | 879,13 -> 766,126 192 | 737,475 -> 737,425 193 | 338,473 -> 425,386 194 | 510,615 -> 214,319 195 | 758,415 -> 758,490 196 | 969,208 -> 239,938 197 | 917,188 -> 917,528 198 | 34,820 -> 806,820 199 | 85,633 -> 857,633 200 | 262,355 -> 262,748 201 | 373,784 -> 971,186 202 | 146,577 -> 60,663 203 | 613,570 -> 613,199 204 | 300,319 -> 300,108 205 | 764,171 -> 764,17 206 | 555,921 -> 555,825 207 | 241,197 -> 770,197 208 | 600,832 -> 600,807 209 | 934,987 -> 20,73 210 | 960,730 -> 837,730 211 | 976,50 -> 46,980 212 | 829,834 -> 153,158 213 | 785,835 -> 785,58 214 | 586,633 -> 689,736 215 | 804,250 -> 348,706 216 | 226,539 -> 16,539 217 | 411,940 -> 98,940 218 | 289,589 -> 893,589 219 | 738,616 -> 738,55 220 | 225,54 -> 542,54 221 | 793,246 -> 303,736 222 | 332,752 -> 984,100 223 | 413,18 -> 839,444 224 | 840,122 -> 840,233 225 | 989,970 -> 215,196 226 | 329,361 -> 573,605 227 | 242,537 -> 242,619 228 | 943,898 -> 943,535 229 | 469,865 -> 501,833 230 | 226,717 -> 196,687 231 | 819,803 -> 712,803 232 | 532,663 -> 532,672 233 | 61,931 -> 940,52 234 | 623,218 -> 274,567 235 | 281,326 -> 281,790 236 | 815,176 -> 679,176 237 | 790,862 -> 942,710 238 | 18,771 -> 18,514 239 | 479,377 -> 309,377 240 | 704,402 -> 704,150 241 | 961,335 -> 492,335 242 | 745,829 -> 745,477 243 | 556,543 -> 771,543 244 | 832,336 -> 917,251 245 | 742,755 -> 742,174 246 | 206,735 -> 493,735 247 | 151,216 -> 312,55 248 | 445,157 -> 615,157 249 | 781,143 -> 781,76 250 | 833,717 -> 514,398 251 | 357,14 -> 357,36 252 | 771,405 -> 771,422 253 | 662,886 -> 169,886 254 | 689,990 -> 22,990 255 | 680,445 -> 379,445 256 | 92,369 -> 502,779 257 | 64,948 -> 64,363 258 | 295,957 -> 976,276 259 | 113,920 -> 634,399 260 | 542,662 -> 305,899 261 | 566,514 -> 566,645 262 | 528,106 -> 549,106 263 | 205,367 -> 821,367 264 | 313,105 -> 313,928 265 | 532,177 -> 532,664 266 | 862,773 -> 905,816 267 | 800,796 -> 911,796 268 | 870,80 -> 11,939 269 | 188,900 -> 154,900 270 | 420,509 -> 520,609 271 | 540,863 -> 28,863 272 | 31,72 -> 78,72 273 | 823,648 -> 503,648 274 | 879,252 -> 606,252 275 | 677,117 -> 677,507 276 | 743,303 -> 196,850 277 | 220,491 -> 220,891 278 | 216,815 -> 577,815 279 | 540,819 -> 745,819 280 | 152,721 -> 382,721 281 | 280,745 -> 985,745 282 | 479,367 -> 358,488 283 | 913,413 -> 649,413 284 | 40,678 -> 817,678 285 | 467,533 -> 467,214 286 | 132,68 -> 843,779 287 | 519,109 -> 669,259 288 | 619,791 -> 221,791 289 | 114,622 -> 628,622 290 | 951,636 -> 866,636 291 | 172,569 -> 775,569 292 | 244,972 -> 173,972 293 | 283,64 -> 739,520 294 | 68,604 -> 68,156 295 | 529,30 -> 529,925 296 | 813,883 -> 137,883 297 | 893,231 -> 629,231 298 | 673,658 -> 673,389 299 | 725,899 -> 218,899 300 | 317,318 -> 105,318 301 | 82,706 -> 100,688 302 | 222,227 -> 440,227 303 | 810,371 -> 810,985 304 | 414,321 -> 289,446 305 | 901,158 -> 260,799 306 | 198,967 -> 717,448 307 | 928,454 -> 875,454 308 | 974,437 -> 974,764 309 | 657,13 -> 760,13 310 | 498,966 -> 976,966 311 | 66,104 -> 66,15 312 | 773,569 -> 980,362 313 | 420,496 -> 403,513 314 | 57,920 -> 85,920 315 | 879,551 -> 879,662 316 | 98,395 -> 98,398 317 | 483,685 -> 483,55 318 | 222,935 -> 586,935 319 | 89,926 -> 807,208 320 | 744,160 -> 744,462 321 | 588,973 -> 588,548 322 | 312,572 -> 38,298 323 | 27,131 -> 552,656 324 | 591,935 -> 591,86 325 | 907,478 -> 907,279 326 | 981,75 -> 981,972 327 | 316,947 -> 935,947 328 | 906,38 -> 906,216 329 | 374,521 -> 345,550 330 | 579,29 -> 579,107 331 | 444,636 -> 444,557 332 | 458,608 -> 830,980 333 | 479,839 -> 155,515 334 | 766,600 -> 766,71 335 | 976,965 -> 31,20 336 | 928,49 -> 269,708 337 | 787,238 -> 787,983 338 | 583,742 -> 112,742 339 | 966,268 -> 554,680 340 | 671,354 -> 671,966 341 | 274,340 -> 274,894 342 | 673,185 -> 607,185 343 | 73,171 -> 874,171 344 | 861,526 -> 861,410 345 | 739,591 -> 739,138 346 | 209,355 -> 209,146 347 | 286,501 -> 887,501 348 | 495,902 -> 700,902 349 | 192,889 -> 821,260 350 | 400,21 -> 154,21 351 | 861,301 -> 325,301 352 | 552,990 -> 511,990 353 | 908,21 -> 11,918 354 | 127,724 -> 821,30 355 | 935,46 -> 170,811 356 | 947,91 -> 374,91 357 | 625,420 -> 265,60 358 | 214,228 -> 546,228 359 | 375,547 -> 715,887 360 | 516,350 -> 870,350 361 | 610,138 -> 665,193 362 | 214,621 -> 678,621 363 | 497,248 -> 600,145 364 | 549,558 -> 576,558 365 | 364,537 -> 364,312 366 | 840,324 -> 310,854 367 | 441,945 -> 441,458 368 | 459,531 -> 459,100 369 | 937,113 -> 150,900 370 | 277,405 -> 259,405 371 | 409,527 -> 409,359 372 | 534,766 -> 534,740 373 | 534,934 -> 681,934 374 | 456,419 -> 83,419 375 | 871,986 -> 873,986 376 | 14,59 -> 916,961 377 | 911,963 -> 971,963 378 | 25,325 -> 139,211 379 | 937,184 -> 354,767 380 | 460,416 -> 289,245 381 | 193,171 -> 861,839 382 | 840,299 -> 840,911 383 | 531,45 -> 531,619 384 | 599,315 -> 455,315 385 | 455,97 -> 455,811 386 | 38,748 -> 392,748 387 | 841,79 -> 841,88 388 | 105,571 -> 105,545 389 | 801,458 -> 344,458 390 | 491,535 -> 558,535 391 | 835,814 -> 223,202 392 | 563,85 -> 405,85 393 | 410,396 -> 600,396 394 | 273,670 -> 818,125 395 | 671,647 -> 817,647 396 | 46,892 -> 678,260 397 | 456,736 -> 110,736 398 | 962,941 -> 619,598 399 | 388,406 -> 53,71 400 | 558,895 -> 227,564 401 | 944,182 -> 807,319 402 | 484,898 -> 59,473 403 | 808,214 -> 488,534 404 | 451,679 -> 155,383 405 | 858,931 -> 381,931 406 | 723,377 -> 723,281 407 | 694,283 -> 182,795 408 | 385,191 -> 320,256 409 | 33,380 -> 584,931 410 | 480,91 -> 817,91 411 | 677,91 -> 677,126 412 | 291,651 -> 760,182 413 | 832,962 -> 153,283 414 | 38,60 -> 479,501 415 | 249,350 -> 789,350 416 | 603,341 -> 266,678 417 | 52,303 -> 52,102 418 | 911,201 -> 559,201 419 | 46,210 -> 46,275 420 | 960,212 -> 554,212 421 | 375,374 -> 169,580 422 | 10,10 -> 989,989 423 | 844,140 -> 40,944 424 | 916,408 -> 916,815 425 | 834,401 -> 834,169 426 | 553,479 -> 784,248 427 | 543,452 -> 543,848 428 | 854,910 -> 334,390 429 | 685,491 -> 793,491 430 | 552,943 -> 709,943 431 | 723,367 -> 124,367 432 | 95,55 -> 881,841 433 | 155,267 -> 573,267 434 | 59,357 -> 84,357 435 | 218,435 -> 218,344 436 | 491,584 -> 491,649 437 | 676,445 -> 676,333 438 | 361,618 -> 783,618 439 | 220,295 -> 220,267 440 | 668,758 -> 299,389 441 | 965,845 -> 674,845 442 | 285,603 -> 47,603 443 | 853,417 -> 853,757 444 | 859,906 -> 856,906 445 | 55,364 -> 753,364 446 | 893,474 -> 978,474 447 | 602,32 -> 58,576 448 | 171,445 -> 96,370 449 | 214,592 -> 214,286 450 | 400,946 -> 745,946 451 | 559,37 -> 112,484 452 | 624,510 -> 90,510 453 | 329,714 -> 329,850 454 | 458,287 -> 657,287 455 | 99,385 -> 99,949 456 | 50,736 -> 719,67 457 | 273,195 -> 273,306 458 | 490,902 -> 490,798 459 | 619,131 -> 921,131 460 | 266,652 -> 266,730 461 | 745,661 -> 745,555 462 | 311,878 -> 311,679 463 | 491,982 -> 643,830 464 | 735,875 -> 816,875 465 | 936,353 -> 936,529 466 | 792,467 -> 565,467 467 | 141,140 -> 141,988 468 | 98,171 -> 414,487 469 | 257,259 -> 257,484 470 | 24,41 -> 969,986 471 | 302,453 -> 223,453 472 | 807,363 -> 492,678 473 | 823,22 -> 835,10 474 | 301,94 -> 399,94 475 | 946,110 -> 248,808 476 | 983,985 -> 21,23 477 | 510,145 -> 510,58 478 | 13,661 -> 13,639 479 | 218,260 -> 218,54 480 | 475,846 -> 475,770 481 | 458,644 -> 458,529 482 | 912,934 -> 912,136 483 | 152,823 -> 550,823 484 | 136,470 -> 443,470 485 | 253,871 -> 905,219 486 | 765,212 -> 793,240 487 | 11,402 -> 11,42 488 | 348,813 -> 348,768 489 | 368,321 -> 823,776 490 | 343,495 -> 343,809 491 | 117,616 -> 117,273 492 | 92,92 -> 732,92 493 | 914,31 -> 28,917 494 | 259,944 -> 214,944 495 | 630,759 -> 462,759 496 | 134,653 -> 134,610 497 | 14,989 -> 988,15 498 | 139,181 -> 139,451 499 | 598,636 -> 598,442 500 | 263,42 -> 686,465 501 | -------------------------------------------------------------------------------- /src/day05/mod.rs: -------------------------------------------------------------------------------- 1 | mod part1; 2 | mod part2; 3 | mod projection; // used in part2 4 | 5 | use crate::utils::*; 6 | 7 | pub type Coord = i16; 8 | 9 | #[inline] 10 | pub fn minmax(a: T, b: T) -> (T, T) { 11 | if a <= b { 12 | (a, b) 13 | } else { 14 | (b, a) 15 | } 16 | } 17 | 18 | #[inline] 19 | pub fn parse_num(s: &mut &[u8]) -> Coord { 20 | parse_int_fast_skip_custom::(s) 21 | } 22 | 23 | pub fn input() -> &'static [u8] { 24 | include_bytes!("input.txt") 25 | } 26 | 27 | pub fn part1(s: &[u8]) -> usize { 28 | self::part1::solve(s) 29 | } 30 | 31 | pub fn part2(s: &[u8]) -> usize { 32 | self::part2::solve(s) 33 | } 34 | 35 | #[test] 36 | fn test_day05_part1() { 37 | assert_eq!(part1(input()), 5280); 38 | } 39 | 40 | #[test] 41 | fn test_day05_part2() { 42 | assert_eq!(part2(input()), 16716); 43 | } 44 | -------------------------------------------------------------------------------- /src/day05/part1.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeSet; 2 | 3 | use arrayvec::ArrayVec; 4 | 5 | use super::{minmax, parse_num, Coord}; 6 | 7 | type Interval = (Coord, Coord); // a 1-D interval, both ends are included 8 | type Intervals = ArrayVec; // a variable-size array of 1-D intervals 9 | type IntervalSet = [Intervals; N]; // interval array for each coordinate (=index) 10 | 11 | const N: usize = 1 << 10; // max coord 12 | const K: usize = 8; // max number of intervals per coord 13 | 14 | fn parse_horizontal_vertical(mut s: &[u8]) -> (IntervalSet, IntervalSet) { 15 | let mut horizontal = [0; N].map(|_| ArrayVec::new()); 16 | let mut vertical = [0; N].map(|_| ArrayVec::new()); 17 | 18 | while s.len() > 1 { 19 | let (x0, y0) = (parse_num::<1>(&mut s), parse_num::<4>(&mut s)); 20 | let (x1, y1) = (parse_num::<1>(&mut s), parse_num::<1>(&mut s)); 21 | if y0 == y1 { 22 | let (y, (x0, x1)) = (y0 as usize, minmax(x0, x1)); 23 | horizontal[y].push((x0, x1)); 24 | } else if x0 == x1 { 25 | let (x, (y0, y1)) = (x0 as usize, minmax(y0, y1)); 26 | vertical[x].push((y0, y1)); 27 | } 28 | } 29 | 30 | (horizontal, vertical) 31 | } 32 | 33 | fn process_overlaps_1d(intervals: &mut Intervals, overlaps: &mut Intervals) -> usize { 34 | // Fix intervals so there's no trivial horizontal/vertical overlap. 35 | // Pushes a non-overlapping set of overlaps into a separate output array. 36 | // We'll just use a naive algorithm here since there's not many of these 37 | // (otherwise we could have used a 1-D sweep line but it's an overkill). 38 | let mut n_overlaps = 0; 39 | 'outer: loop { 40 | for i in 0..intervals.len() - 1 { 41 | for j in i + 1..intervals.len() { 42 | let (a, b) = (intervals[i], intervals[j]); 43 | if a.0 <= b.1 && b.0 <= a.1 { 44 | let (left, c) = minmax(a.0, b.0); 45 | let (d, right) = minmax(a.1, b.1); 46 | let overlap = minmax(c, d); 47 | n_overlaps += (overlap.1 - overlap.0 + 1) as usize; 48 | intervals.remove(j); 49 | intervals.remove(i); 50 | overlaps.push(overlap); 51 | if left < overlap.0 { 52 | intervals.push((left, overlap.0 - 1)); 53 | } 54 | if right > overlap.1 { 55 | intervals.push((overlap.1 + 1, right)); 56 | } 57 | continue 'outer; 58 | } 59 | } 60 | } 61 | break; 62 | } 63 | // we're almost done, BUT: overlaps themselves may overlap, we need to fix that too 64 | loop { 65 | let mut overlap_overlaps = Intervals::new_const(); 66 | if overlap_overlaps.is_empty() { 67 | break; 68 | } 69 | n_overlaps -= process_overlaps_1d(overlaps, &mut overlap_overlaps); 70 | overlaps.extend(overlap_overlaps.drain(..)); 71 | } 72 | n_overlaps 73 | } 74 | 75 | #[inline] 76 | fn process_overlaps(interval_set: &mut [Intervals], n_overlaps: &mut usize) -> IntervalSet { 77 | let mut overlaps = [0; N].map(|_| ArrayVec::new()); 78 | for (coord, intervals) in interval_set.iter_mut().enumerate() { 79 | if intervals.len() > 1 { 80 | *n_overlaps += process_overlaps_1d(intervals, &mut overlaps[coord]); 81 | } 82 | } 83 | overlaps 84 | } 85 | 86 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 87 | enum Event { 88 | Start(Coord), 89 | Vertical(Interval), 90 | Finish(Coord), 91 | } 92 | 93 | fn line_sweep_hv(horizontal: &[Intervals], vertical: &[Intervals]) -> usize { 94 | let mut event_queue = [0; N].map(|_| ArrayVec::::new()); 95 | 96 | for (x, intervals) in vertical.iter().take(N).enumerate() { 97 | for &interval in intervals { 98 | event_queue[x].push(Event::Vertical(interval)); 99 | } 100 | } 101 | for (y, intervals) in horizontal.iter().take(N).enumerate() { 102 | for &(x0, x1) in intervals { 103 | event_queue[x0 as usize].push(Event::Start(y as _)); 104 | event_queue[x1 as usize].push(Event::Finish(y as _)); 105 | } 106 | } 107 | 108 | let mut active = BTreeSet::::new(); 109 | let mut count = 0; 110 | for events in &mut event_queue { 111 | if events.len() > 1 { 112 | events.sort_unstable(); 113 | } 114 | for &event in events as &_ { 115 | match event { 116 | Event::Start(y) => { 117 | active.insert(y); 118 | } 119 | Event::Vertical((y0, y1)) => { 120 | count += active.range(y0..=y1).count(); 121 | } 122 | Event::Finish(y) => { 123 | active.remove(&y); 124 | } 125 | } 126 | } 127 | } 128 | count 129 | } 130 | 131 | pub fn solve(s: &[u8]) -> usize { 132 | let (mut horizontal, mut vertical) = parse_horizontal_vertical(s); 133 | 134 | let mut n_parallel_overlaps = 0; 135 | let horizontal_overlaps = process_overlaps(&mut horizontal[..N], &mut n_parallel_overlaps); 136 | let vertical_overlaps = process_overlaps(&mut vertical[..N], &mut n_parallel_overlaps); 137 | let n_non_overlap_overlaps = line_sweep_hv(&horizontal, &vertical); 138 | let n_overlap_overlaps = line_sweep_hv(&horizontal_overlaps, &vertical_overlaps); 139 | 140 | n_parallel_overlaps + n_non_overlap_overlaps - n_overlap_overlaps 141 | } 142 | -------------------------------------------------------------------------------- /src/day05/part2.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{BTreeMap, BTreeSet}; 2 | use std::iter; 3 | use std::marker::PhantomData; 4 | use std::ops::{Range, RangeBounds, RangeInclusive}; 5 | 6 | use arrayvec::ArrayVec; 7 | 8 | use super::{minmax, parse_num, Coord}; 9 | 10 | use super::projection::{DiagNeg, DiagPos, Horizontal, Vertical}; 11 | use super::projection::{ 12 | IntersectWith, IntersectableWith, LineDirection, ProjectFrom, ProjectableOnto, 13 | }; 14 | 15 | type X = Coord; 16 | type Y = Coord; 17 | type Interval = (X, Y); 18 | type Point = (X, Y); 19 | type Line = (Point, Point); 20 | 21 | const N: usize = 1 << 10; 22 | const K: usize = 8; 23 | 24 | fn parse_lines(mut s: &[u8]) -> impl Iterator + '_ { 25 | iter::from_fn(move || { 26 | if s.len() > 1 { 27 | let p0 = (parse_num::<1>(&mut s), parse_num::<4>(&mut s)); 28 | let p1 = (parse_num::<1>(&mut s), parse_num::<1>(&mut s)); 29 | Some((p0, p1)) 30 | } else { 31 | None 32 | } 33 | }) 34 | } 35 | 36 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 37 | enum LineType { 38 | Horizontal, 39 | DiagPos, 40 | DiagNeg, 41 | } 42 | 43 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 44 | struct Segment { 45 | x_start: X, 46 | x_end: X, 47 | y: Y, 48 | } 49 | 50 | impl Segment { 51 | pub fn new((x_start, x_end): Interval, y: Y) -> Self { 52 | Self { x_start, x_end, y } 53 | } 54 | 55 | pub fn x_range(&self) -> RangeInclusive { 56 | self.x_start..=self.x_end 57 | } 58 | } 59 | 60 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] 61 | enum Event { 62 | Start(LineType, Segment), 63 | Vertical(Interval), 64 | Finish(LineType, Segment), 65 | } 66 | 67 | #[derive(Clone, Copy, Debug, Default)] 68 | struct IntervalTrackerElement { 69 | len: usize, 70 | overlap_start: X, 71 | } 72 | 73 | impl IntervalTrackerElement { 74 | pub fn start(&mut self, x: X) -> bool { 75 | // return true if a new element is inserted 76 | self.len += 1; 77 | if self.len == 2 { 78 | self.overlap_start = x; 79 | } 80 | self.len == 1 81 | } 82 | 83 | pub fn finish(&mut self, x: X) -> (bool, Range) { 84 | // returns (is_removed, range_of_overlaps) 85 | self.len -= 1; 86 | let range = if self.len == 1 { self.overlap_start..(x + 1) } else { 0..0 }; 87 | (self.len == 0, range) 88 | } 89 | } 90 | 91 | #[derive(Clone, Debug)] 92 | struct IntervalTracker { 93 | active: [IntervalTrackerElement; N * 2], // can also use BTreeMap... 94 | } 95 | 96 | impl IntervalTracker { 97 | pub fn new() -> Self { 98 | Self::default() 99 | } 100 | 101 | pub fn start(&mut self, (x, y): Point) -> bool { 102 | self.active[((N as Y) + y) as usize].start(x) // TODO: bounds checks 103 | } 104 | 105 | pub fn finish(&mut self, (x, y): Point) -> (bool, Range) { 106 | self.active[((N as Y) + y) as usize].finish(x) // TODO: bounds checks 107 | } 108 | } 109 | 110 | impl Default for IntervalTracker { 111 | fn default() -> Self { 112 | unsafe { std::mem::transmute([0_u8; std::mem::size_of::()]) } 113 | } 114 | } 115 | 116 | #[derive(Clone, Copy, Default, Debug)] 117 | struct ActiveSetElement { 118 | x_overlap_start: X, 119 | x_ends: [X; K], 120 | len: usize, 121 | } 122 | 123 | impl ActiveSetElement { 124 | pub fn new(x_end: X) -> Self { 125 | let mut out = Self::default(); 126 | out.x_ends[0] = x_end; 127 | out.len = 1; 128 | out 129 | } 130 | 131 | pub fn insert(&mut self, x_start: X, x_end: X) { 132 | debug_assert!(x_start > self.x_overlap_start); 133 | self.x_ends[self.len] = x_end; 134 | self.len += 1; 135 | if self.len == 2 { 136 | self.x_overlap_start = x_start; 137 | } 138 | (&mut self.x_ends[..self.len]).sort_unstable_by(|a, b| b.cmp(a)); 139 | } 140 | 141 | pub fn remove(&mut self, x_end: X) -> Range { 142 | debug_assert!(x_end >= self.x_overlap_start); 143 | debug_assert_ne!(self.len, 0); 144 | if self.len == 1 { 145 | debug_assert_eq!(self.x_ends[0], x_end); 146 | self.len = 0; 147 | 0..0 148 | } else { 149 | debug_assert!(self.x_ends.contains(&x_end)); 150 | for i in 0..self.len { 151 | if self.x_ends[i] == x_end { 152 | (&mut self.x_ends[i..]).rotate_left(1); 153 | break; 154 | } 155 | } 156 | self.len -= 1; 157 | if self.len == 1 { 158 | self.x_overlap_start..(x_end + 1) 159 | } else { 160 | 0..0 161 | } 162 | } 163 | } 164 | 165 | pub fn is_empty(&self) -> bool { 166 | self.len == 0 167 | } 168 | 169 | pub fn x_end(&self) -> X { 170 | self.x_ends[0] 171 | } 172 | } 173 | 174 | #[derive(Debug, Clone, Default)] 175 | struct ActiveSet { 176 | active: BTreeMap, 177 | } 178 | 179 | impl ActiveSet { 180 | pub fn insert(&mut self, segment: &Segment) { 181 | self.active 182 | .entry(segment.y) 183 | .and_modify(|element| element.insert(segment.x_start, segment.x_end)) 184 | .or_insert_with(|| ActiveSetElement::new(segment.x_end)); 185 | } 186 | 187 | pub fn remove(&mut self, segment: &Segment) -> Range { 188 | match self.active.get_mut(&segment.y) { 189 | Some(element) => { 190 | let range = element.remove(segment.x_end); 191 | if element.is_empty() { 192 | self.active.remove(&segment.y); 193 | } 194 | range 195 | } 196 | _ => 0..0, 197 | } 198 | } 199 | 200 | pub fn range(&self, range: impl RangeBounds) -> impl Iterator + '_ { 201 | self.active.range(range).map(|(&k, _)| k) 202 | } 203 | 204 | pub fn range_with_endpoints( 205 | &self, range: impl RangeBounds, 206 | ) -> impl Iterator + '_ { 207 | self.active.range(range).map(|(&k, element)| (k, element.x_end())) 208 | } 209 | } 210 | 211 | #[derive(Clone, Debug)] 212 | struct Intersections { 213 | intersections: [[u64; N >> 6]; N], 214 | } 215 | 216 | impl Default for Intersections { 217 | fn default() -> Self { 218 | const S: usize = std::mem::size_of::(); 219 | unsafe { std::mem::transmute([0_u8; S]) } 220 | } 221 | } 222 | 223 | impl Intersections { 224 | pub fn new() -> Self { 225 | Self::default() 226 | } 227 | 228 | #[inline] 229 | pub fn record(&mut self, x: X, y: Y) { 230 | let (x, y) = (x as usize, y as usize); 231 | unsafe { 232 | *self.intersections.get_unchecked_mut(y).get_unchecked_mut(x >> 6) |= 1 << (x & 0x3f); 233 | } 234 | } 235 | 236 | pub fn len(&self) -> usize { 237 | self.intersections 238 | .iter() 239 | .map(|i| i.iter().map(|n| n.count_ones()).sum::() as usize) 240 | .sum() 241 | } 242 | } 243 | 244 | #[derive(Debug, Clone, Default)] 245 | struct ProjectedActiveSet { 246 | active: ActiveSet, 247 | _marker: PhantomData, 248 | } 249 | 250 | impl ProjectedActiveSet { 251 | pub fn new() -> Self { 252 | Self::default() 253 | } 254 | 255 | pub fn find_intersections + IntersectWith>( 256 | &mut self, other: &ProjectedActiveSet, segment: &Segment, 257 | intersections: &mut Intersections, 258 | ) { 259 | let (x_range_this, y_this) = (segment.x_range(), segment.y); 260 | let y_range_other = x_range_this.project_onto::(y_this); 261 | 262 | for (y_other, x_right_endpoint) in other.active.range_with_endpoints(y_range_other) { 263 | if let Some(x) = y_other.intersect_with::(y_this) { 264 | if x <= x_right_endpoint { 265 | let y = x.project_onto::(y_other); 266 | intersections.record(x, y); 267 | } 268 | } 269 | } 270 | } 271 | 272 | pub fn on_start( 273 | &mut self, a: &ProjectedActiveSet, b: &ProjectedActiveSet, segment: &Segment, 274 | intersections: &mut Intersections, 275 | ) { 276 | self.active.insert(segment); 277 | self.find_intersections(a, segment, intersections); 278 | self.find_intersections(b, segment, intersections); 279 | } 280 | 281 | pub fn on_vertical(&self, x: X, (y0, y1): Interval, intersections: &mut Intersections) { 282 | for y_d in self.active.range((y0..=y1).project_onto::(x)) { 283 | let y = x.project_onto::(y_d); 284 | intersections.record(x, y); 285 | } 286 | } 287 | 288 | pub fn on_finish(&mut self, segment: &Segment, intersections: &mut Intersections) { 289 | let y_this = segment.y; 290 | for x in self.active.remove(segment) { 291 | let y = x.project_onto::(y_this); 292 | intersections.record(x, y); 293 | } 294 | } 295 | } 296 | 297 | fn triple_line_sweep(events: &EventQueue) -> usize { 298 | let mut horizontal = ProjectedActiveSet::::new(); 299 | let mut diag_pos = ProjectedActiveSet::::new(); 300 | let mut diag_neg = ProjectedActiveSet::::new(); 301 | 302 | let mut vertical_intervals = BTreeSet::new(); 303 | let mut ix = Intersections::new(); 304 | 305 | events.iter_events(|x, event| match event { 306 | Event::Start(line_type, s) => match line_type { 307 | LineType::Horizontal => horizontal.on_start(&diag_pos, &diag_neg, &s, &mut ix), 308 | LineType::DiagPos => diag_pos.on_start(&horizontal, &diag_neg, &s, &mut ix), 309 | LineType::DiagNeg => diag_neg.on_start(&horizontal, &diag_pos, &s, &mut ix), 310 | }, 311 | Event::Vertical(interval) => { 312 | horizontal.on_vertical(x, interval, &mut ix); 313 | diag_pos.on_vertical(x, interval, &mut ix); 314 | diag_neg.on_vertical(x, interval, &mut ix); 315 | vertical_intervals.insert((interval.0, false, x)); 316 | vertical_intervals.insert((interval.1, true, x)); 317 | } 318 | Event::Finish(line_type, s) => match line_type { 319 | LineType::Horizontal => horizontal.on_finish(&s, &mut ix), 320 | LineType::DiagPos => diag_pos.on_finish(&s, &mut ix), 321 | LineType::DiagNeg => diag_neg.on_finish(&s, &mut ix), 322 | }, 323 | }); 324 | 325 | let mut tracker = IntervalTracker::new(); 326 | for &(y_sweep, is_finish, x) in &vertical_intervals { 327 | if is_finish { 328 | for y in tracker.finish((y_sweep, x)).1 { 329 | ix.record(x, y); 330 | } 331 | } else { 332 | tracker.start((y_sweep, x)); 333 | } 334 | } 335 | 336 | ix.len() 337 | } 338 | 339 | #[derive(Debug, Clone)] 340 | struct EventQueue { 341 | events: Vec<[ArrayVec; 3]>, // [start, vertical, finish] 342 | } 343 | 344 | impl EventQueue { 345 | pub fn parse(s: &[u8]) -> Self { 346 | Self::from_lines(parse_lines(s)) 347 | } 348 | 349 | pub fn from_lines(lines: impl Iterator) -> Self { 350 | const START: usize = 0; 351 | const VERTICAL: usize = 1; 352 | const FINISH: usize = 2; 353 | let mut events = Vec::<[ArrayVec; 3]>::with_capacity(N); 354 | unsafe { 355 | events.set_len(N); 356 | std::slice::from_raw_parts_mut( 357 | events.as_mut_ptr() as *mut u8, 358 | N * std::mem::size_of::<[ArrayVec; 3]>(), 359 | ) 360 | .fill(0); 361 | } 362 | for ((x0, y0), (x1, y1)) in lines { 363 | let (dx, dy) = (x1 - x0, y1 - y0); 364 | if dx == 0 { 365 | let (y0, y1) = minmax(y0, y1); 366 | events[x0 as usize][VERTICAL].push(Event::Vertical((y0, y1))); 367 | } else { 368 | let (line_type, y) = match (dy == 0, dx == dy) { 369 | (true, _) => (LineType::Horizontal, y0), 370 | (_, true) => (LineType::DiagPos, x0.project_onto::(y0)), 371 | _ => (LineType::DiagNeg, x0.project_onto::(y0)), 372 | }; 373 | let (x0, x1) = minmax(x0, x1); 374 | let segment = Segment::new((x0, x1), y); 375 | events[x0 as usize][START].push(Event::Start(line_type, segment)); 376 | events[x1 as usize][FINISH].push(Event::Finish(line_type, segment)); 377 | } 378 | } 379 | Self { events } 380 | } 381 | 382 | pub fn iter_events(&self, mut func: impl FnMut(X, Event)) { 383 | for x in 0..N { 384 | for i in 0..3 { 385 | for &event in &self.events[x][i] { 386 | func(x as _, event); 387 | } 388 | } 389 | } 390 | } 391 | } 392 | 393 | pub fn solve(s: &[u8]) -> usize { 394 | let events = EventQueue::parse(s); 395 | triple_line_sweep(&events) 396 | } 397 | -------------------------------------------------------------------------------- /src/day05/projection.rs: -------------------------------------------------------------------------------- 1 | use std::ops::RangeInclusive; 2 | 3 | pub type Coord = i16; 4 | pub type X = Coord; 5 | pub type Y = Coord; 6 | 7 | /// Horizontal x and y are normal x and y. 8 | #[derive(Default)] 9 | pub struct Horizontal; 10 | 11 | /// Vertical x and y are normal y and x (swapped). 12 | #[derive(Default)] 13 | pub struct Vertical; 14 | 15 | /// Diag-pos x is normal x, but y is projected along y=x onto x=0. 16 | #[derive(Default)] 17 | pub struct DiagPos; 18 | 19 | /// Diag-neg x is normal x, but y is projected along y=-x onto x=0. 20 | #[derive(Default)] 21 | pub struct DiagNeg; 22 | 23 | pub trait ProjectOnto { 24 | /// Given local (x, y) coordinates in `Self`, return y-coordinate in `T`. 25 | fn project_onto(x: X, y: Y) -> Y; 26 | } 27 | 28 | macro_rules! impl_proj_onto { 29 | ($from:ty, $to:ty, $func:expr) => { 30 | impl ProjectFrom<$from> for $to { 31 | fn project_from(x: X, y: Y) -> Y { 32 | ($func)(x, y) 33 | } 34 | } 35 | }; 36 | } 37 | 38 | impl_proj_onto!(Horizontal, DiagPos, |x, y| y - x); 39 | impl_proj_onto!(Horizontal, DiagNeg, |x, y| y + x); 40 | impl_proj_onto!(Horizontal, Vertical, |x, _y| x); 41 | 42 | impl_proj_onto!(Vertical, DiagPos, |x, y| x - y); 43 | impl_proj_onto!(Vertical, DiagNeg, |x, y| x + y); 44 | impl_proj_onto!(Vertical, Horizontal, |x, _y| x); 45 | 46 | impl_proj_onto!(DiagPos, Horizontal, |x, y| y + x); 47 | impl_proj_onto!(DiagPos, Vertical, |x, _y| x); 48 | impl_proj_onto!(DiagPos, DiagNeg, |x, y| y + 2 * x); 49 | 50 | impl_proj_onto!(DiagNeg, Horizontal, |x, y| y - x); 51 | impl_proj_onto!(DiagNeg, Vertical, |x, _y| x); 52 | impl_proj_onto!(DiagNeg, DiagPos, |x, y| y - 2 * x); 53 | 54 | pub trait ProjectFrom { 55 | /// The reverse of project_onto(). 56 | fn project_from(x: X, y: Y) -> Y; 57 | } 58 | 59 | impl> ProjectOnto for F { 60 | fn project_onto(x: X, y: Y) -> Y { 61 | T::project_from(x, y) 62 | } 63 | } 64 | 65 | impl ProjectFrom for T { 66 | fn project_from(_x: X, y: Y) -> Y { 67 | y 68 | } 69 | } 70 | 71 | pub trait ProjectableOnto { 72 | fn project_onto, T>(self, y: Y) -> Self; 73 | } 74 | 75 | impl ProjectableOnto for X { 76 | fn project_onto, T>(self, y: Y) -> Self { 77 | F::project_onto(self, y) 78 | } 79 | } 80 | 81 | impl ProjectableOnto for (X, X) { 82 | fn project_onto, T>(self, y: Y) -> Self { 83 | (F::project_onto(self.0, y), F::project_onto(self.1, y)) 84 | } 85 | } 86 | 87 | impl ProjectableOnto for RangeInclusive { 88 | fn project_onto, T>(self, y: Y) -> Self { 89 | let (start, end) = (F::project_onto(*self.start(), y), F::project_onto(*self.end(), y)); 90 | if start <= end { 91 | start..=end 92 | } else { 93 | end..=start 94 | } 95 | } 96 | } 97 | 98 | pub trait IntersectWith { 99 | /// Given two local y-coordinates in `Self` and `T`, find the resulting 100 | /// x-coordinate of the intersection point (note that x-axis is shared for 101 | /// all non-vertical line directions). This intersection almost always exists 102 | /// except for diag-pos vs diag-neg case where the difference between the two 103 | /// y-coordinates is not divisible by 2. 104 | fn intersect_with(y1: Y, y2: Y) -> Option; 105 | } 106 | 107 | macro_rules! impl_intersect_with { 108 | ($ty1:ty, $ty2:ty, $func:expr) => { 109 | impl IntersectWith<$ty2> for $ty1 { 110 | fn intersect_with(y1: Y, y2: Y) -> Option { 111 | ($func)(y1, y2) 112 | } 113 | } 114 | impl IntersectWith<$ty1> for $ty2 { 115 | fn intersect_with(y1: Y, y2: Y) -> Option { 116 | ($func)(y2, y1) 117 | } 118 | } 119 | }; 120 | ($ty:ty) => { 121 | impl IntersectWith<$ty> for $ty { 122 | fn intersect_with(_y1: Y, _y2: Y) -> Option { 123 | None 124 | } 125 | } 126 | }; 127 | } 128 | 129 | impl_intersect_with!(Horizontal, DiagPos, |y1, y2| Some(y1 - y2)); 130 | impl_intersect_with!(Horizontal, DiagNeg, |y1, y2| Some(y2 - y1)); 131 | impl_intersect_with!(DiagPos, DiagNeg, |y1, y2| ((y2 - y1) % 2 == 0).then(|| (y2 - y1) / 2)); 132 | impl_intersect_with!(Horizontal); 133 | impl_intersect_with!(DiagPos); 134 | impl_intersect_with!(DiagNeg); 135 | 136 | pub trait IntersectableWith { 137 | fn intersect_with, T>(self, y: Y) -> Option; 138 | } 139 | 140 | impl IntersectableWith for Y { 141 | fn intersect_with, T>(self, y: Y) -> Option { 142 | F::intersect_with(self, y) 143 | } 144 | } 145 | 146 | pub trait LineDirection: 147 | Default 148 | + ProjectFrom 149 | + ProjectFrom 150 | + ProjectOnto 151 | + ProjectOnto 152 | + ProjectOnto 153 | + ProjectOnto 154 | + IntersectWith 155 | + IntersectWith 156 | { 157 | type A: LineDirection + ProjectFrom + IntersectWith; 158 | type B: LineDirection + ProjectFrom + IntersectWith; 159 | } 160 | 161 | impl LineDirection for Horizontal { 162 | type A = DiagPos; 163 | type B = DiagNeg; 164 | } 165 | 166 | impl LineDirection for DiagPos { 167 | type A = Horizontal; 168 | type B = DiagNeg; 169 | } 170 | 171 | impl LineDirection for DiagNeg { 172 | type A = Horizontal; 173 | type B = DiagPos; 174 | } 175 | -------------------------------------------------------------------------------- /src/day06/input.txt: -------------------------------------------------------------------------------- 1 | 2,5,3,4,4,5,3,2,3,3,2,2,4,2,5,4,1,1,4,4,5,1,2,1,5,2,1,5,1,1,1,2,4,3,3,1,4,2,3,4,5,1,2,5,1,2,2,5,2,4,4,1,4,5,4,2,1,5,5,3,2,1,3,2,1,4,2,5,5,5,2,3,3,5,1,1,5,3,4,2,1,4,4,5,4,5,3,1,4,5,1,5,3,5,4,4,4,1,4,2,2,2,5,4,3,1,4,4,3,4,2,1,1,5,3,3,2,5,3,1,2,2,4,1,4,1,5,1,1,2,5,2,2,5,2,4,4,3,4,1,3,3,5,4,5,4,5,5,5,5,5,4,4,5,3,4,3,3,1,1,5,2,4,5,5,1,5,2,4,5,4,2,4,4,4,2,2,2,2,2,3,5,3,1,1,2,1,1,5,1,4,3,4,2,5,3,4,4,3,5,5,5,4,1,3,4,4,2,2,1,4,1,2,1,2,1,5,5,3,4,1,3,2,1,4,5,1,5,5,1,2,3,4,2,1,4,1,4,2,3,3,2,4,1,4,1,4,4,1,5,3,1,5,2,1,1,2,3,3,2,4,1,2,1,5,1,1,2,1,2,1,2,4,5,3,5,5,1,3,4,1,1,3,3,2,2,4,3,1,1,2,4,1,1,1,5,4,2,4,3 2 | -------------------------------------------------------------------------------- /src/day06/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | type T = usize; 4 | 5 | #[inline(always)] 6 | const fn row_dot(x: &[T; N], y: &[T; N]) -> T { 7 | let (mut i, mut v) = (0, 0); 8 | while i < N { 9 | v += x[i] * y[i]; 10 | i += 1; 11 | } 12 | v 13 | } 14 | 15 | #[inline(always)] 16 | const fn dot(m: &[[T; N]; N], x: &[T; N]) -> [T; N] { 17 | let (mut i, mut v) = (0, [0; N]); 18 | while i < N { 19 | v[i] = row_dot(&m[i], x); 20 | i += 1; 21 | } 22 | v 23 | } 24 | 25 | #[inline] 26 | pub fn solve16(mut s: &[u8]) -> usize { 27 | let mut v = [0_usize; 9]; 28 | while s.len() > 1 { 29 | v[(s.get_first() - b'0') as usize] += 1; 30 | s = s.advance(2); 31 | } 32 | 33 | const M: [[usize; 9]; 9] = [ 34 | [2, 0, 1, 0, 0, 0, 0, 1, 0], 35 | [0, 2, 0, 1, 0, 0, 0, 0, 1], 36 | [1, 0, 2, 0, 1, 0, 0, 0, 0], 37 | [0, 1, 0, 2, 0, 1, 0, 0, 0], 38 | [0, 0, 1, 0, 2, 0, 1, 0, 0], 39 | [1, 0, 0, 1, 0, 2, 0, 1, 0], 40 | [0, 1, 0, 0, 1, 0, 2, 0, 1], 41 | [1, 0, 0, 0, 0, 1, 0, 1, 0], 42 | [0, 1, 0, 0, 0, 0, 1, 0, 1], 43 | ]; 44 | 45 | for _ in 0..N16 { 46 | v = dot(&M, &v); 47 | } 48 | v.into_iter().sum() 49 | } 50 | 51 | #[inline] 52 | pub fn solve(mut s: &[u8]) -> usize { 53 | let mut counts = [0_usize; 9]; 54 | while s.len() > 1 { 55 | counts[(s.get_first() - b'0') as usize] += 1; 56 | s = s.advance(2); 57 | } 58 | for _ in 0..N { 59 | let new = counts[0]; 60 | counts.rotate_left(1); 61 | counts[6] += new; 62 | } 63 | counts.into_iter().sum() 64 | } 65 | 66 | pub fn input() -> &'static [u8] { 67 | include_bytes!("input.txt") 68 | } 69 | 70 | pub fn part1(s: &[u8]) -> usize { 71 | solve16::<{ 80 >> 4 }>(s) 72 | } 73 | 74 | pub fn part2(s: &[u8]) -> usize { 75 | solve::<256>(s) 76 | } 77 | 78 | #[test] 79 | fn test_day06_part1() { 80 | assert_eq!(part1(input()), 345387); 81 | } 82 | 83 | #[test] 84 | fn test_day06_part2() { 85 | assert_eq!(part2(input()), 1574445493136); 86 | } 87 | -------------------------------------------------------------------------------- /src/day07/input.txt: -------------------------------------------------------------------------------- 1 | 1101,1,29,67,1102,0,1,65,1008,65,35,66,1005,66,28,1,67,65,20,4,0,1001,65,1,65,1106,0,8,99,35,67,101,99,105,32,110,39,101,115,116,32,112,97,115,32,117,110,101,32,105,110,116,99,111,100,101,32,112,114,111,103,114,97,109,10,104,709,235,932,796,119,731,120,462,837,152,100,214,411,71,28,91,1231,401,417,900,1733,683,107,101,582,159,72,11,514,566,1054,638,774,413,222,568,526,53,303,635,664,21,67,133,913,292,95,963,7,440,78,1455,283,104,106,431,749,468,325,319,922,433,2,108,10,95,89,1074,190,91,52,1313,242,475,964,395,437,604,277,525,162,191,923,124,219,35,707,18,1123,30,1163,41,467,290,420,393,279,159,59,206,160,592,52,267,696,218,151,807,301,262,424,102,1871,406,443,149,1035,1286,141,403,37,872,1031,788,1138,962,89,357,885,367,499,175,556,157,1571,759,989,2,1305,38,132,579,335,1452,171,627,175,557,1108,274,263,1036,482,432,21,1769,63,17,731,83,1329,131,101,6,1135,317,110,41,706,142,292,473,783,566,230,34,243,405,32,55,987,646,62,92,52,597,48,319,1159,827,769,125,420,308,60,345,461,159,229,1064,298,1200,861,364,1051,26,584,702,1717,19,61,35,581,297,63,945,1469,3,1168,588,339,1182,1357,823,293,85,77,40,847,235,326,364,474,619,732,105,517,153,32,198,65,1026,278,1170,1092,941,1747,147,124,86,975,856,1173,350,51,206,17,319,111,89,49,94,97,319,887,307,991,372,175,409,359,129,1242,1409,644,205,424,1644,1515,1134,299,571,78,695,101,365,385,1188,1162,17,106,972,198,381,656,9,291,1415,95,1048,541,162,1408,776,308,308,278,495,1679,302,1,138,7,382,981,455,719,607,541,136,449,1059,227,453,1614,315,283,583,143,1806,499,1062,1115,219,22,160,650,326,70,316,4,200,1542,1554,266,377,123,1302,1814,139,383,304,324,167,850,63,306,365,83,490,201,41,352,593,118,45,554,75,1352,49,92,1399,231,104,289,134,1307,9,247,883,999,1069,301,307,743,729,365,3,1251,415,304,40,330,293,72,393,562,12,183,41,229,306,209,281,1557,126,1119,286,12,18,1010,729,741,738,44,615,748,193,598,423,68,174,36,70,1455,325,0,229,409,211,423,183,271,233,952,601,320,109,1051,502,684,546,239,1279,215,1497,125,427,489,500,10,415,189,630,261,63,102,1459,79,1113,199,684,251,801,573,16,99,1805,716,45,18,631,290,508,67,0,2,461,63,325,607,697,812,58,262,316,754,37,848,60,101,202,1000,128,20,355,313,140,279,833,168,1197,1668,1062,255,626,205,326,321,591,243,1093,38,26,986,508,424,229,143,163,1173,608,349,468,571,95,140,10,279,112,12,552,0,326,258,195,113,470,651,1298,439,53,134,151,447,299,905,40,19,23,719,10,557,1339,474,119,329,1487,55,602,255,284,162,783,524,452,899,327,236,1826,295,265,598,1825,220,517,592,862,57,762,465,313,499,694,1328,5,81,137,936,46,852,448,1301,1101,35,77,1283,11,193,937,757,9,208,160,736,54,1574,87,546,51,373,29,25,79,1091,1432,125,158,728,835,1,614,172,389,173,808,1788,223,125,135,25,318,6,691,724,104,467,269,66,39,362,155,100,165,425,1844,41,284,602,226,294,172,942,223,1,14,199,1292,235,434,612,980,139,61,735,276,62,864,56,460,652,713,98,408,1314,320,116,171,114,93,804,260,339,451,392,31,156,176,60,279,1272,271,1494,164,170,451,857,317,1379,44,166,115,823,349,4,352,54,389,1548,302,454,1412,231,86,2,239,117,272,462,1030,171,14,301,249,66,114,360,676,510,1149,58,91,46,317,425,1219,64,1538,638,1227,62,214,386,1148,180,327,1084,27,886,565,157,215,313,462,129,1293,397,823,753,50,539,705,813,531,779,30,501,1072,1125,2,1640,691,1140,573,1081,1232,488,721,113,113,127,270,1095,6,68,301,465,43,322,88,892,841,323,981,642,1231,346,247,623,161,1291,76,709,1148,306,87,1147,645,818,1520,692,352,133,71,443,1190,271,1171,42,980,589,493,312,211,78,1369,329,304,1057,202,405,1294,49,363,835,1295,53,530,20,24,947,885,1054,252,1170,337,460,476,50,657,1201,715,555,132,344,26,1369,675,234,1362,875,224,1910,338,175,93,595,27,211,210,787,790,990,425,1176,48,43,201,15,279,344,203,15,790,255,125,159,45,162,290,198,796,52,146,512,200,1051,1850,1202,775,237,767,13,180,294,26,896,1263,749,1239,1621,642,607,88,123,651,630,1178,135,5,686,989,1250,60,1266,360,49,1089,175,355,162,375,350,1203 2 | -------------------------------------------------------------------------------- /src/day07/mod.rs: -------------------------------------------------------------------------------- 1 | use arrayvec::ArrayVec; 2 | 3 | use crate::utils::*; 4 | 5 | type T = i16; // element type 6 | type C = i32; // cost function 7 | 8 | const N: usize = 1 << 10; 9 | 10 | #[inline] 11 | fn parse_input(mut s: &[u8]) -> ArrayVec { 12 | let mut x = ArrayVec::new_const(); 13 | while s.len() > 1 { 14 | unsafe { 15 | x.push_unchecked(parse_int_fast_skip_custom::<_, 1, 4, 1>(&mut s)); 16 | } 17 | } 18 | debug_assert_eq!(x.len() % 2, 0); 19 | x 20 | } 21 | 22 | #[inline] 23 | fn median(x: &mut [T]) -> T { 24 | let n = x.len(); 25 | let (_, mid, _) = x.select_nth_unstable(n >> 1); 26 | *mid 27 | } 28 | 29 | #[inline] 30 | fn cost1(x: &[T], m: T) -> C { 31 | x.iter().map(|&x| (x - m).abs() as C).sum() 32 | } 33 | 34 | #[inline] 35 | fn mean_floor(x: &[T]) -> T { 36 | (x.iter().map(|&x| x as C).sum::() / x.len() as C) as T 37 | } 38 | 39 | pub fn input() -> &'static [u8] { 40 | include_bytes!("input.txt") 41 | } 42 | 43 | pub fn part1(s: &[u8]) -> C { 44 | /* 45 | Cost function: 46 | 47 | c(x_i) = abs(x_i - m) 48 | 49 | => L1 problem, solution is m := median(X) 50 | */ 51 | let mut x = parse_input(s); 52 | let m = median(&mut x); 53 | cost1(&x, m) 54 | } 55 | 56 | pub fn part2(s: &[u8]) -> C { 57 | /* 58 | Cost function: 59 | 60 | c(x_i) = 61 | x_i == m => 0 62 | x_i > m => 1 + 2 + 3 + ... + (x_i - m) 63 | x_i < m => 1 + 2 + 3 + ... + (m - x_i) 64 | 65 | = k * (k + 1) / 2, where k = abs(x_i - m) 66 | = ((x_i - m) ^ 2 + abs(x_i - m)) / 2 67 | 68 | => mix of L1 and L2 69 | 70 | L1 minimum = median, L2 = minimum = mean 71 | 72 | sum(c'(X)) = 0: 73 | 74 | 2 * sum(X - m) + sum(sgn(X - m)) = 0 75 | 2 * sum(X) - 2 * m * n + sum(sgn(X - m)) = 0 76 | mean(X) - m + mean(sgn(X - m)) / 2 = 0 77 | => m \in [mean(X) - 1/2; mean(X) + 1/2] 78 | */ 79 | let x = parse_input(s); 80 | let m = mean_floor(&x); 81 | 82 | // a bit more ugly, but lets us iterate over the array once only 83 | let (mut c1, mut c2) = (0, 0); 84 | for &x in &x { 85 | let d1 = (x - m) as C; 86 | c1 += d1 * d1 + d1.abs(); 87 | let d2 = d1 - 1; 88 | c2 += d2 * d2 + d2.abs(); 89 | } 90 | 91 | c1.min(c2) >> 1 92 | } 93 | 94 | #[test] 95 | fn test_day07_part1() { 96 | assert_eq!(part1(input()), 335271); 97 | } 98 | 99 | #[test] 100 | fn test_day07_part2() { 101 | assert_eq!(part2(input()), 95851339); 102 | } 103 | -------------------------------------------------------------------------------- /src/day08/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | pub fn input() -> &'static [u8] { 4 | include_bytes!("input.txt") 5 | } 6 | 7 | pub fn part1(mut s: &[u8]) -> usize { 8 | // 1, 4, 7, 8: number of digits = 2, 4, 3, 7 9 | let mut count = 0; 10 | 'outer: loop { 11 | s = s.skip_past(b'|', 1); 12 | loop { 13 | let n = s.memchr2(b' ', b'\n'); 14 | if let 2 | 3 | 4 | 7 = n { 15 | count += 1; 16 | } 17 | let c = s.get_at(n); 18 | s = s.advance(n + 1); 19 | if s.len() <= 1 { 20 | break 'outer; 21 | } else if c == b'\n' { 22 | break; 23 | } 24 | } 25 | } 26 | count 27 | } 28 | 29 | pub fn parse_digit(s: &mut &[u8]) -> u8 { 30 | let mut digit = 0; 31 | loop { 32 | let c = s.get_first().wrapping_sub(b'a'); 33 | *s = s.advance(1); 34 | if c < 7 { 35 | digit |= 1_u8 << c; 36 | } else { 37 | break; 38 | } 39 | } 40 | digit 41 | } 42 | 43 | fn parse_digits(s: &mut &[u8]) -> [u8; N] { 44 | let mut digits = [0; N]; 45 | for i in 0..N { 46 | digits[i] = parse_digit(s); 47 | } 48 | digits 49 | } 50 | 51 | fn parse_line(s: &mut &[u8]) -> ([u8; 10], [u8; N]) { 52 | let inputs = parse_digits::<10>(s); 53 | *s = s.advance(2); 54 | let outputs = parse_digits::(s); 55 | (inputs, outputs) 56 | } 57 | 58 | fn decode_segments(inputs: &[u8; 10]) -> [u8; 7] { 59 | /* 60 | 0 61 | 1 2 62 | 3 63 | 4 5 64 | 6 65 | */ 66 | 67 | // First, split the inputs into buckets by number of segments 68 | let (mut one, mut four, mut seven) = (0, 0, 0); 69 | let mut zero_six_nine = [0; 3]; 70 | let eight = 0b0111_1111; 71 | for &x in inputs { 72 | match x.count_ones() { 73 | 2 => one = x, 74 | 3 => seven = x, 75 | 4 => four = x, 76 | 6 => { 77 | zero_six_nine.rotate_right(1); 78 | zero_six_nine[0] = x; 79 | } 80 | _ => (), // it's eight or a 5-segment digit 81 | } 82 | } 83 | 84 | // top segment can be inferred directly 85 | let mut segments = [0; 7]; 86 | segments[0] = seven & !one; 87 | 88 | // now let's process 6-segment digits, that should be sufficient 89 | for x in &zero_six_nine[..3] { 90 | // look which digit is missing from eight 91 | let c = eight & !x; 92 | if c & one != 0 { 93 | // it's 6 94 | segments[2] = c; 95 | segments[5] = one & !c; 96 | } else if c & four != 0 { 97 | // it's 0 98 | segments[3] = c; 99 | segments[1] = four & !one & !c; 100 | } else { 101 | // it's 9 102 | segments[4] = c; 103 | segments[6] = x & !four & !seven; 104 | } 105 | } 106 | segments 107 | } 108 | 109 | fn decode_digits(segments: &[u8; 7]) -> [u8; 10] { 110 | let eight = 0b0111_1111; 111 | let one = segments[2] | segments[5]; 112 | let seven = one | segments[0]; 113 | let four = one | segments[1] | segments[3]; 114 | let zero = eight & !segments[3]; 115 | let six = eight & !segments[2]; 116 | let nine = eight & !segments[4]; 117 | let two = eight & !segments[1] & !segments[5]; 118 | let three = eight & !segments[1] & !segments[4]; 119 | let five = eight & !segments[2] & !segments[4]; 120 | [zero, one, two, three, four, five, six, seven, eight, nine] 121 | } 122 | 123 | fn decode_outputs(outputs: &[u8; N], digits: &[u8; 10]) -> usize { 124 | let mut decoder = [0; 256]; 125 | for i in 0..10 { 126 | decoder.set_at(digits[i] as _, i); 127 | } 128 | let mut number = 0; 129 | for i in 0..N { 130 | number *= 10; 131 | number += decoder.get_at(outputs[i] as _) as usize; 132 | } 133 | number 134 | } 135 | 136 | pub fn part2(mut s: &[u8]) -> usize { 137 | let mut sum = 0; 138 | while s.len() > 1 { 139 | let (inputs, outputs) = parse_line::<4>(&mut s); 140 | let segments = decode_segments(&inputs); 141 | let digits = decode_digits(&segments); 142 | sum += decode_outputs(&outputs, &digits); 143 | } 144 | sum 145 | } 146 | 147 | pub fn part2_faster(mut s: &[u8]) -> usize { 148 | // implementation of @orlp's solution (probably the fastest possible here) 149 | let mut decoder = [0_u8; 256]; 150 | decoder[42] = 0; 151 | decoder[17] = 1; 152 | decoder[34] = 2; 153 | decoder[39] = 3; 154 | decoder[30] = 4; 155 | decoder[37] = 5; 156 | decoder[41] = 6; 157 | decoder[25] = 7; 158 | decoder[49] = 8; 159 | decoder[45] = 9; 160 | 161 | let mut sum = 0; 162 | while s.len() > 1 { 163 | let mut input_counts = [0_u8; 256]; 164 | for i in 0..58 { 165 | input_counts.add_at(s.get_at(i) as _, 1); 166 | } 167 | s = s.advance(61); 168 | let mut num = 0_usize; 169 | let mut output_counts = 0_u8; 170 | loop { 171 | match s.get_first() { 172 | ch @ b'a'..=b'g' => { 173 | output_counts += input_counts.get_at(ch as _); 174 | } 175 | ch => { 176 | let digit = decoder.get_at(output_counts as _) as usize; 177 | num = num * 10 + digit; 178 | output_counts = 0; 179 | if ch == b'\n' { 180 | s = s.advance(1); 181 | sum += num; 182 | break; 183 | } 184 | } 185 | } 186 | s = s.advance(1); 187 | } 188 | } 189 | sum 190 | } 191 | 192 | #[test] 193 | fn test_day08_part1() { 194 | assert_eq!(part1(input()), 301); 195 | } 196 | 197 | #[test] 198 | fn test_day08_part2() { 199 | assert_eq!(part2(input()), 908067); 200 | } 201 | -------------------------------------------------------------------------------- /src/day09/input.txt: -------------------------------------------------------------------------------- 1 | 5432345678989998934579789765459876765467892399767954567893212987898410456789329876710145678998765432 2 | 6754656789879987899698678954398765452356953989654543456789329876987321345697634965431236989239879321 3 | 9865769898767656798979567893249876321257899878653432568996499865696534456789549876542345892125998945 4 | 5976778999656545987665456799345985432348989965432101457897989879987876567998756987656456789234987899 5 | 4987889998945439876567344678969876543489879876543212345689878998998997688959987998966567897649876798 6 | 3298998987832123965432123499999989865678967989654346896893567897899989789543998999878689998799965457 7 | 9989867896543239876321014989989595978789656998767567998932456956912978997659899987989789459987654346 8 | 8678456789656798765432199878879434989892546799987678979321767899899767998798789876699892398996543212 9 | 6532349898767899878543987654568923996921234789898889765433479998765656899987698765459921987987652101 10 | 6431239929898910989654598743478919875210145698789999876764989999854345678965439999568939875498778212 11 | 5310128939969899699875689654569101964321234989654321997875678979865234569654323987679198764398765323 12 | 6542337898656798569989798765678999875432349876543210398876799569954358978943212398789098963239765434 13 | 7653456789545987458999899898789989876565489988974341239987965498765467899954101459894987656145978565 14 | 9874567897639876567899999979899876987676679999765632545698954349876978979876532345993496541034797678 15 | 8765678999545987978978998765989765698989998999876784678999983242987989765989673456789987632123698789 16 | 9896789998956798989769876564678954569999887899989875789998772101298997654398784567893298749234569898 17 | 7949899987897999193458989423567893678998766789993987891987653232359876543219895978989109898945678977 18 | 6433949876789891012567898734678954889999855898932299910998754543679987652109999899878919987896989565 19 | 9921234965686789123678987646789967999985543367940198899879987654568998543398898789767898765679995434 20 | 7894349874245878934999998987897898999874321256791987678965498765679659964987657678954987654569874320 21 | 6789498992134568949878999798956999998765432345989436578954349876789789895976543567895698943478965431 22 | 5678986789347679998767987659345899989896543469876523488943234997899898789765432456789989992589996542 23 | 4568995458957898999659876541236789876987675698765414567892123989989998697654321238999878989695987656 24 | 3467954357898967899643988632345898765698876799876203456789349869878976589765799959998765979964598769 25 | 2756953236989998998732199545456789654569987898943212347899998756767897478986987898999874867893239898 26 | 1234892125678999987643298756568999943978999987654433456999876545658789569999896556987653456932199987 27 | 2346789234789998798974369899879879891389989899875544587899987632345678978998765439876542347893989896 28 | 3457895345678987649965459965989765789498965632987655678988998543456799899899887545994321456789876745 29 | 4767896567899895439876598764599954599987654321298967989876987655667898798789998976987450167896565434 30 | 5678998678998794321987699853698863468996543210129878999765499876878987689678979989876571278999432123 31 | 8789109799987679910198985432987654567898756321238989988654345987989976563569965698997692489998945245 32 | 9899239987986567899239974321098765878969895432347899876545234598999876432457894347898786599987656356 33 | 9978998896562433978998765452349878989954996543756789965432125679101989641238989656789998789098767467 34 | 8765487789421012569899878543456989099892987654567897899541016789232998750345678967896549892129879678 35 | 5654346678932123456798987654567899198791998769698946788952125698949879821657899878999656954998998789 36 | 4323234579543544567987898769878998989679899978789434567893434987898765434568954989998767899887679893 37 | 3210123678954656779876789878989987676576799989892123456794545696789876945878963598999878999764569954 38 | 4321234899767787898785698989999876532345678999943035677895676987898989876789012467987989998993298765 39 | 5632345678978998987654567899987654321236899459754129889976789998987697987898943569876590987789109879 40 | 6789767899989659298789698968898965632345995398765234999987898989998545299987897699965421986678999998 41 | 7898989995796542129898789456789876789496789219976545678998987878999432109656789987895439434569989987 42 | 8987599989989953235979892345678987898989898999987656789899996567896563298545698976789598921459878876 43 | 9987679878977894346965921297889599987678936789598767896798987458897785397434767895699987892368965965 44 | 2398798765666989457893932989993498986569545894349978945997854367798996986323656997789876789459954324 45 | 3569899654545678967999899878932987897479678932123499439876543235689129765412345789898965679567895434 46 | 9678998543434589878998789567899876789678989321029567921995432145789099877101256899987654568989998545 47 | 8989987632123478989987678456798765499789895432198979899876543234892987654312345678998963487898987656 48 | 7899964321034569999876573345689876988998789543987898799987869395901298769543659789899872346987898767 49 | 6789875432145678999854321234599989876987689659876797679299998989992989898754578996799965459876789878 50 | 5678986593856789998765410195678998765456598998765636569123987678989876929765678925679876599865678989 51 | 4389997989767895989875431989789987654323457899854323478939876567678954319878989434789998987654577999 52 | 3239899878978934976986549878990198996412368967965434567897654376589978909989299645679899876543456899 53 | 2198788569989129875697698767891239987625459659876567679976543212368899898792198767789799998732345678 54 | 4986676459891098764569987856792345999976569845987678899987987643456789768679019878895678984321234567 55 | 9975434345789197653456976745689559876987778934599789978998998754567897657578999989944569876532345688 56 | 8764323238995987652399875436789698765498899895989894567899439865789976545489789992233456987654556899 57 | 9943210127894598743987664323899989434329956789875923456789329989898765432395699921012345898985678997 58 | 9874321236789987654976543212999878921012345678954212375678998795989897321234999892323456799876789986 59 | 8765432345692198767987432101899867892124589789843201234679877654678989432349899789434567987997899765 60 | 9876744657789029898999843456789456789435678998743212345799865863789678943498788678976679876598988979 61 | 9987855678899999999898754567992345678948789987654323567898754322345567895987654569897798765439567998 62 | 8998976789998789998789865778921256789656894398765634878998763210123498939876543458789899984323467897 63 | 7839987892197678987699876899434347998767893219878765989019854321294989321985432347678999876412359976 64 | 6323498999984569876567987998765456899878992101999878992123965439989878939876521014569899998563458965 65 | 5213459998975698765455698999878567958989989213456989219239876698768767897998762523456789987654767894 66 | 4323467897896789987344569799989879767899878994569894398949987989856456896549654434567894398779898985 67 | 5674598956989898873212897678799998979997656789698765987898999876543267896539765565978999219899989876 68 | 6785679449876987654323679545679997898976545678999876976567976987675378955429876676789878923998978987 69 | 7896789234965598785654568934569876987895434567789989895456895498986489543212989989894767899836569898 70 | 8997893149874429876765678925698775876789212455678998789877912359987599432101296799923458998725456789 71 | 9598954298743212989876789212987654345694301234789989678988909498898678943232345698534569987612345899 72 | 3449765987652101599989899323498765468965412345899864569899998987649789959543456987645989896501246789 73 | 1239876798969292349897978944569976789998543456789753758789897698739899898954567998786798765432357899 74 | 0997989899898989498766567895678987894987654589897542345698789549899998767895998999897899876754456789 75 | 9876591998767678987654456789789998923498765678954321456789678934999877656789899899999932987896578998 76 | 9987410987658569876543345899899989534579876789765432345894567895698965345898788789998921298987689787 77 | 8999329876543456984321256987959876545679987897989876567903456789797893234987675678997899349999897676 78 | 7996534985432367895432397896543998696798998986799987678912369899986932129876554789976798956910998545 79 | 6989549876553456789545679987692129989997899565678999789425458999895891013985432479995487999891986532 80 | 5879956987687677897656789998989239879896789434569349896436567898784692129876321567989256789789897910 81 | 4768899998798788998987899899878998768765698945679234987587899987643989298765410179878145897659799891 82 | 3456798999899899329998947698767569854234567896789154987699998765432478999876321259765236976648645789 83 | 2369987889932998919879434569953498963123456797891023498932987656321367899987433349874358985432125698 84 | 3498965678901987898754323459832987654345567898932934569321298543210458999998944856985767896985334567 85 | 4987654569899876798654218598721098765457678999549895698990987654431567898999659769876878987976455698 86 | 9876353456789954987654327987543179876569989297659789987989998765545678967899879878987989098987866789 87 | 8765232345899893298785436987674567987678997398798678976979999877656789456789989989998992129998979892 88 | 7654101236789789109896545698789678998789876469987567995468899998967894345678995497899764398989989910 89 | 8763212347897678912987656789998989329893989598765456789345678979878965456989764346789875987678999329 90 | 9874323456789567893999767899987798912992198999876567894234789565989876587899953235678989876545678998 91 | 9765654567893457999888998999876587893989987989989878965656895434599998799999892124567898765436799987 92 | 9878765678912346898767889998765466789878876778999989879867896125678989890198789234678959976525689976 93 | 8989878789323456789657678999854345678967465767989899989878989296789976989997678999789545987634569865 94 | 7599989995435767893234569998743234569654343459878789993989879989899875679876567788997656798875698764 95 | 5459899987546789954345679987642157878943212399767678921299768679998764598785454567898987899986789652 96 | 4399799998987898966656789998656788989754103988656567892998656588976543987654323456789599998797898741 97 | 5987678979598967898967897898768899998763219876543456789877543487799432398743212345695421987698999432 98 | 9878589765439456899878965439889978999865434965432345698766432345678943997432101236789439876559876543 99 | 8765478954321366789989874321994567895986549874321236789854321334567899876543232348896598765432987656 100 | 9987569765542345794396543210123458934987656983210123498763210125878910987654643456789987654321098967 101 | -------------------------------------------------------------------------------- /src/day09/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | const N: usize = 100; 4 | const M: usize = 1 << 10; 5 | 6 | macro_rules! lanes_min { 7 | ($lhs:expr, $rhs:expr) => { 8 | ($lhs).lanes_ge(($rhs)).select(($rhs), ($lhs)) 9 | }; 10 | } 11 | 12 | pub fn input() -> &'static [u8] { 13 | include_bytes!("input.txt") 14 | } 15 | 16 | pub fn part1(mut s: &[u8]) -> usize { 17 | type T = i8; 18 | const LANES: usize = 16; // width of SIMD vector 19 | const K: usize = (N + LANES - 1) / LANES; // number of iterations for each line 20 | type S = core_simd::Simd; 21 | 22 | let mut prev = [S::splat(T::MAX); K]; 23 | let mut prev_min3 = [S::splat(T::MAX); K]; 24 | let mut out = 0; 25 | 26 | let zero = S::splat(0); 27 | let threshold = S::splat((b'0' - 1) as _); 28 | 29 | for i in 0..(N + 1) { 30 | let mut line = [T::MAX; K * LANES + 2]; // line with 'ghost cells' (starts with index 1) 31 | 32 | if i < N { 33 | // copy the line directly into the buffer without parsing 34 | unsafe { 35 | std::ptr::copy_nonoverlapping(s.as_ptr(), line.as_mut_ptr().add(1).cast(), N) 36 | }; 37 | s = s.advance(N + 1); 38 | } 39 | 40 | for j in 0..K { 41 | let left = S::from_array(unsafe { *line.as_ptr().add(j * LANES + 0).cast() }); 42 | let this = S::from_array(unsafe { *line.as_ptr().add(j * LANES + 1).cast() }); 43 | let right = S::from_array(unsafe { *line.as_ptr().add(j * LANES + 2).cast() }); 44 | 45 | let this_min3 = lanes_min!(left, right); 46 | let this_min3 = lanes_min!(this_min3, prev[j]); 47 | 48 | if i != 0 { 49 | let min_cross = lanes_min!(this, prev_min3[j]); 50 | let value = prev[j] - threshold; 51 | out += prev[j].lanes_lt(min_cross).select(value, zero).horizontal_sum() as usize; 52 | } 53 | 54 | prev[j] = this; 55 | prev_min3[j] = this_min3; 56 | } 57 | } 58 | out as _ 59 | } 60 | 61 | #[allow(unused)] 62 | pub fn part1_naive(mut s: &[u8]) -> usize { 63 | let mut grid = [[0xff_u8; N + 2]; N + 2]; 64 | for i in 1..=N { 65 | for j in 1..=N { 66 | grid[i][j] = s.get_digit_at(j - 1); 67 | } 68 | s = s.advance(N + 1); 69 | } 70 | let mut sum = 0; 71 | for i in 1..=N { 72 | for j in 1..=N { 73 | let x = grid[i][j]; 74 | if x < grid[i - 1][j] && x < grid[i][j - 1] && x < grid[i + 1][j] && x < grid[i][j + 1] 75 | { 76 | sum += (1 + x) as usize; 77 | } 78 | } 79 | } 80 | sum 81 | } 82 | 83 | #[derive(Debug, Default, Copy, Clone)] 84 | struct Element { 85 | parent: u16, 86 | rank: u16, 87 | } 88 | 89 | struct UnionFind { 90 | elements: [Element; M], 91 | len: u16, 92 | } 93 | 94 | impl UnionFind { 95 | pub fn new() -> Self { 96 | Self { elements: [Element::default(); M], len: 0 } 97 | } 98 | 99 | fn get(&self, x: u16) -> &Element { 100 | unsafe { &*self.elements.get_unchecked(x as usize) } 101 | } 102 | 103 | fn get_mut(&mut self, x: u16) -> &mut Element { 104 | unsafe { &mut *self.elements.get_unchecked_mut(x as usize) } 105 | } 106 | 107 | pub fn add_leaf(&mut self) -> u16 { 108 | let x = self.len; 109 | self.len += 1; 110 | *self.get_mut(x) = Element { parent: x, rank: 0 }; 111 | x 112 | } 113 | 114 | pub fn find(&mut self, mut x: u16) -> u16 { 115 | loop { 116 | let e = self.get(x); 117 | let p = e.parent; 118 | if p == x { 119 | break; 120 | } 121 | let gp = self.get(p).parent; 122 | self.get_mut(x).parent = gp; 123 | x = gp; 124 | } 125 | x 126 | } 127 | 128 | pub fn union(&mut self, x: u16, y: u16) { 129 | let x = self.find(x); 130 | let y = self.find(y); 131 | if x == y { 132 | return; 133 | } 134 | let (rx, ry) = (self.get(x).rank, self.get(y).rank); 135 | let (x, y) = if rx < ry { (y, x) } else { (x, y) }; 136 | self.get_mut(y).parent = x; 137 | if rx == ry { 138 | self.get_mut(x).rank += 1; 139 | } 140 | } 141 | 142 | pub fn len(&self) -> usize { 143 | self.len as _ 144 | } 145 | } 146 | 147 | #[allow(unused)] 148 | pub fn part2_dfs(mut s: &[u8]) -> usize { 149 | // Simple DFS implementation - works but is 3x slower than union-find 150 | 151 | fn dfs(grid: &mut [u8], i: usize, j: usize, coord: usize) -> usize { 152 | if grid.get_at(coord) == b'9' { 153 | 0 154 | } else { 155 | grid.set_at(coord, b'9'); 156 | let mut size = 1; 157 | if j != 0 { 158 | size += dfs(grid, i, j - 1, coord - 1); 159 | } 160 | if j != N - 1 { 161 | size += dfs(grid, i, j + 1, coord + 1); 162 | } 163 | if i != 0 { 164 | size += dfs(grid, i - 1, j, coord - N - 1); 165 | } 166 | if i != N - 1 { 167 | size += dfs(grid, i + 1, j, coord + N + 1); 168 | } 169 | size 170 | } 171 | } 172 | 173 | let mut grid = s.to_vec(); 174 | let mut sizes = vec![]; 175 | for i in 0..N { 176 | let row = i * (N + 1); 177 | for j in 0..N { 178 | let size = dfs(&mut grid, i, j, row + j); 179 | if size != 0 { 180 | sizes.push(size); 181 | } 182 | } 183 | } 184 | sizes.sort_unstable(); 185 | sizes[sizes.len() - 3..].iter().product::() 186 | } 187 | 188 | pub fn part2(mut s: &[u8]) -> usize { 189 | // This is basically a 4-connected CCL problem for binary images. 190 | 191 | let mut labels_this = [u16::MAX; M]; 192 | let mut labels_prev = [u16::MAX; M]; 193 | 194 | let mut counts = [0_usize; M]; 195 | let mut uf = UnionFind::new(); 196 | 197 | for _ in 1..=N { 198 | for j in 1..=N { 199 | labels_this[j] = if s.get_at(j - 1) != b'9' { 200 | let n = labels_prev[j]; 201 | let w = labels_this[j - 1]; 202 | let label = match (n, w) { 203 | (u16::MAX, u16::MAX) => uf.add_leaf(), 204 | (u16::MAX, _) => w, 205 | (_, u16::MAX) => n, 206 | (n, w) if n == w => n, 207 | _ => { 208 | uf.union(n, w); 209 | n.min(w) 210 | } 211 | }; 212 | counts.add_at(label as _, 1); 213 | label 214 | } else { 215 | u16::MAX 216 | }; 217 | } 218 | s = s.advance(N + 1); 219 | labels_prev = labels_this; 220 | } 221 | 222 | let mut sizes = vec![0_usize; uf.len()]; 223 | for (i, &c) in counts.iter().take(uf.len() as usize).enumerate() { 224 | sizes[uf.find(i as _) as usize] += c; 225 | } 226 | sizes.retain(|&s| s != 0); 227 | sizes.sort_unstable(); 228 | sizes[sizes.len() - 3..].iter().product::() 229 | } 230 | 231 | #[test] 232 | fn test_day09_part1() { 233 | assert_eq!(part1(input()), 518); 234 | } 235 | 236 | #[test] 237 | fn test_day09_part2() { 238 | assert_eq!(part2(input()), 949905); 239 | } 240 | -------------------------------------------------------------------------------- /src/day10/input.txt: -------------------------------------------------------------------------------- 1 | <({<[(({(((({(<><>)[[][]]}<<()>{{}}>)(<{(){}}((){})>))<[((<><>){()()})[(<>{}){[]{}}]]>){{(({[]()}<[][]> 2 | {<({[[<<{(<{(<{}()>([][])){<<>}[<>()]}}[<(<>()){()()}>[[(){}]({}())]]>{({{<>{}}[<><>]}<{()<>}{{}() 3 | {{<<<[<({[{{<({}())(<>{})>(<()<>><()[]>)}<([<>{}](<>[]))<{{}<>]>>}<[[<<><>><[]()>][[[]{}]{{}}]][{(<>( 4 | [[<<<[([[([<(({}[]){{}[]})><{([]<>)[(){}]}[{()[]}([]{})]>][({({}[])<[]{}>}{[{}()](<>())}){(([]{}){[][]})[ 5 | {((({{<[(((<(<()><()()>)>[{<[]()>{<>{}}}{([][])<[]()>}]){(({[][]}{()})(({}<>)[<>{}]))({{()< 6 | [[[(({[<<[([[[[]<>]{[]()}]([{}()]{{}{}}]][{[()()]{(){}}}(([]())<{}>)])][{[(([][]){[]{}})]<{(()< 7 | {<[{[({<{[{[<[()<>]>({[]<>}{[]()})]}{[([<>{}]({}{})){([]{})}]{{<{}{}>}{<()<>>(<>{})}}}](([{{(){}}<{}{}> 8 | <{({{[(({({<[[[][]]]{[<>()][{}()]}>((<{}<>>))})(<(<[{}[]]({}<>)><({}<>)>)[[{()<>}{<>{}}}[{[]<> 9 | [<[[[{<[([<(<<<>{}><(){}>>(<[]()>)){<<{}<>>[()]>[<[]<>>([][])]}><<{[{}()][{}[]]}<({}{})>>({{{}{}}} 10 | {[[{<(<[{[<(<<{}{}>{[]()}>){{(()<>)[[]<>]}}>[[[[<><>]<[]{}>]]]]}({{{{([]<>)[[]{}]}}{{(()[])[[]{}]}}}}((<(<< 11 | <[([({<({(<{[[[][]][<>()]][<{}[]>]}[{(()())<{}{}>}<({}())(<>{})>]>{(<<[]{}>>{{{}<>}[[]<>]}){{([] 12 | {<<[<(<{[[<[{[()[]](<><>)}{<[]{}>(()[])}]<{{[]{}}<{}<>>}([[]()]([])))>(([[<><>]]))]<[<{{[][ 13 | (((<<([[([<<[(()[]]<()<>>]<(()[]){{}[]}>><<[{}{}](()())>{<()()>[{}()]}>>])(([[({(){}}<<><>>)[{{}[]}[{ 14 | [<{([[<(<<[[([<>[]][<>()])(((){})([]()))](<{[]<>}({}())>[<<>[]>(()[])])]{[((<>())[{}()])(([])((){}) 15 | (({<{<([[[(<(<[]()>{<><>}){[[]()]{{}<>}}>)]<([<{()[]}<<><>>>{{<>()}{[][]}}][<{[]<>}<{}()>>])[<{ 16 | <<<<[([({{(<[<<>{})]<[[][]][{}{}]>>[<{{}()}[[]<>]><[[]<>]{[]()}>])}}<(<([(()())({}())]({<> 17 | {<[{{(<((<{<[<()()>[{}<>]][([]())[{}{}]]><{[[]{}]{()()}}{([]<>)<()<>>}>}><{(<<<>{}>[[]]><({}[])({}()]>)}<{[ 18 | (<{{<(([[({<(<{}><<>{}>)><{[(){}]}<{<>()}[[]<>]>>}{({<(){}}({}{})})})<<[[<(){}>{[]()}]<[{}{}]>] 19 | <{((<{[{<{[((((){})(<>{}))[<{}[]>[()]])(<[()()]{()<>}>)]{{({()}<{}[]))}[<(()[])><[()[]]({}<>)> 20 | (<(<({[{<{{{<[{}][[]<>]><{<><>}(<>[])>}}}>}<{<[({<[]{}>[{}()]}([()[]]{[]<>}))[[({}[])]{({}{})[{}[]]}]][<{{<>( 21 | [({<<[{{{<(<<<{}{}>{[]}>({()[]}({}()))>{<[{}()][{}{}]>[[<>{}](<><>)]})>(<<[<{}<>>]{<[]{}>([ 22 | <(({{[(({(<{{([]<>)[{}<>]}}{<<[][]>{<>{}}>({<>()}{<>()})}>{[[[[]<>]](<<>{}><()<>>)]})({<([< 23 | <<[(<<([([({<[{}[]]<{}()>]{<[][]>[[][]]}}({<()()>{()[]}}({<>()}((){})))){{(<()[]>[[]])(<<>{}>)}{<{{}[ 24 | {{(<<{([{[{(([{}{}]((){})))}{<[(()())({}())][{()<>}]>}][{<{({}())<[]()>}[[<><>]{<>()}]>}]}[((< 25 | <[[{(([<<<{<([[][]][()[]}){{[]<>}(()[])}>([(<>[]){{}[]}]{({})<<>{}>})}[[<{<>[]}<[]()>>][{{()[]}}[{{}() 26 | {{([{<((<{<[<<()[]>(<>())>{[<>()][[]<>]}]([({}[]][<>()]][(<>())<()<>>])>({<[[]<>]>[[()()][[][]]]}<[<[]() 27 | [<<({<{[[({[<((){})[{}]><<[][]>{()[]}>][<({}{})>[[{}()]{{}<>}]]}{{<<[]()>([]())>{{<>()}{<>[]}} 28 | [({[({{(<(<{<<<>[]><<>()>>({()[]}{()[]})]>){(([[()()](<>{})]{([][])<()()>})(({()[]}<{}()>)[ 29 | {<(<{<{(({{[(<<>()>{<>[]})(({}())[[]()])]([({}())(<>{}}])}{{<{{}()}[[][]]>{{[]{}}<<>[]>}}}}{<[{< 30 | [((<{{{([<<<[({}[])[()<>]]<{<><>}<<>[]>>>>>[(<{[{}]<[]()>}{[<>]<[][]>}>{{(()[])}(([][]){<>[]} 31 | {<((<{(({{{<([[][]]{{}{}}){{[]{}}{[]<>}}>[{<{}()>([]<>)}(<[][]>{<>[]})]}<([[()[]]]{{()()}([][])})([{[][]}<{} 32 | [{([(([<{([(<{[]{}}[()[]]>(([])[<><>]))])[[{(({}())<[]<>>)<({}())[()[]]]}([<()()>[<><>]](<[]<>><<>()>))]( 33 | {{[[[(((([[{[([]())[()>]}(<<()<>>({}<>)>[{<>[]}[()<>]])]<<[{[]()}{[]{}}]>({[{}{}]([]{})}[{(){}}{{}[]}])>] 34 | [({[<(<[{[{({<<>{}>{{}{}]}[(<>())[<>{}]])(((<>[])<{}[]>)[<()()>[{}{}]])}[[<<{}<>>{{}[]}>[(<>< 35 | [{<((([{{{(<{[{}<>][[]<>]}]){[({{}<>})<<{}()>{{}{}}>]{<([]<>)<[]{}>>[<(){}>(<>[])]}}}(([{[<>]<[]()>}([<>{}][ 36 | {(([<{[[<({[<<<>{})([]<>)>[{[]()}(<><>)]][<(()[])>{(<>{}){[][]}}]}<{[([]())<[]{}>]<{[]()}(() 37 | <{[{[<<{[(([{(<>{})<[][]>}<([]<>)(<><>)>](<[<>[]][[]<>]>[[[][]]({}[])])))]{[[{({<>}[()<>])[<[]<>>{[]()}]}( 38 | {(<(({{(<{<[<<<>{}>[<>[]]>([[]][[][]))]([(<>{})({})])><[[{{}[]}({}[])][{<><>}<{}>]](<([][]){[]}><{[][] 39 | {[[(({{({<(<(({}<>){{}}){([])({}{})}>)>}<<[([{<>[]}[[]<>]])<({[]()}[{}<>])<[{}{}][[][]]>>][{< 40 | ({[{[{[<([{{[[()()](<>{})]((<>{})(()<>))}[({[]()}({}{}))[<<><>>{(){}}]]}<((([]){()<>}))>])><<< 41 | [{<({([<(([{[{[]<>}][(()<>)<<>[]>]}]<(<({}{})(()())>[([][])[(){}]]){<<()[]>>}>))<[{<[[[]{}]([]())][{{}{}} 42 | {[(((<<{[[(([<[]()>(<><>)])(<<<>{}>[<>{}]>{<<>><[]<>>}))[{(<<>()>[[]<>])(([]<>){<><>})}[((<>)[[][]])(([]{})[[ 43 | {([<<{((({[[[(<>{})[()()]]]]<[([{}{}]<[]<>>){<<>[]><()[]>}]>}{<<{<()()>}>{{([]<>)[[]<>]}{<()[]>[[ 44 | <<[(<(<[({<{<([]())(<>[])>[{{}<>}((){})]}>{({(<>())({}<>)})}}{<{<(<>[])><{[]{}}<{}()>>}[{(())(()[])}[({}())<[ 45 | {{([{{<{{<[(<[[][]]{{}()}>)[<{[][]}<{}[]>}({{}()}{()()})]][{[[[]()]{()[]}]<{{}}([]())>}{(< 46 | [<<{{<<<[[[({[{}()]}{<{}[]>(()())}){({[]<>}([]{}))<({}{})(<>())>}]{({<[]<>>([]<>}}{{[][]}[[ 47 | (({[[[{<(<{[[([][]){<>[]}]([[]<>])]<{[{}()]<{}[]>}[({}<>)<{}()>]>}[[(<<>[]>[<>()]){<()<>>{{}{}} 48 | {<{([[<<(<<{<[()<>][()()]>[[()[]]({})]}>>)>>]])<{({<<[[<([(){}]<[]()>)<<[][]>[<><>]>]]]>[({[{<()<>>< 49 | {({([(([({{((<()()>([][])))}{{{<<>>}[[()<>](()())]}<{<<><>><{}[]>}>}})({<[{<{}{}>[<>()]}[{{}<>}[{}{}]]]({( 50 | {{(<{<[[(<(<[(<><>){[]()}]>)(([<{}{}>[[]<>]][<<><>>(<>{})])<<[[][]]><<[]()>{<>}>>)><<{<({}{})[<><>]>}< 51 | {[[[[{{(<<{<{{[]{}}<{}[]>}[<()[]>[<>[]]]>{([{}()])(<{}{}>{<>{}}]}}[<<{<>{}}<()()>>{[<>]}>{[(<>{})<()<>>] 52 | ((<[{<[({<({[(()())(<>[])]<[<><>]{[][]}>}([([])[{}()]]<{<>()}{{}<>}>))><([<([]{}){[]}>[{[]}[[][]]] 53 | [<[<({[{{({<[(<><>)<[][]>](<<>{}>(<>()))>}(<<<{}{}>[{}<>]><<[]{}>[<><>]>>(((<>())<()>))))}}[{[(<[{()[] 54 | [{<[<(<<{[<([<{}[]><<>()>][[[]()]<()[]>])>[(<[(){}][{}{}]>{[<>{}]<{}()]})]]({[(<<>>)<[{}<>]<[]{}>>]<<<(){}>< 55 | [<{<{<<<(((([<()>{<><>}][(()())[{}()]])[[{{}()}<()()>][{()}]])<(<<[][]>><<{}()>[{}[]]>)[([[][]][<>[]] 56 | ({{<[{[{(<<[((<>[])<[]()>)[[{}{}]({}{})]]>([[(()<>)<<>{}>]{(()<>)[{}()]}]{(([]())([]()))[[[]<>][<>{}]]})> 57 | ({<<[<{{[[([{<()<>>}])[<{<()[]>}[{(){}]<{}[]>]>[[[[][]]](<[]<>>{<><>})]]]<[{[([]{})<()()>]}(<({}<>){< 58 | <([<<{(<({{{<({})(<><>)>{{<>[]}<[][]>}}<([()[]]({}{}))>}})>{{({[[{{}<>}]{[(){}][(){}]}]([{{}{}}({}{})][[ 59 | {[({<[<[([[<<({}{}){()[]}>{([]<>)}>{(({}<>)<[][]>)[{{}<>}(<>{})]}]])[({[(([]<>){<><>})(([]<>)<[ 60 | <[[[{<<({<{([<()[]><[]()>])<[{{}()}<()[]>](([]<>){[]()})>}>{[[(<{}()){<>{}})[<[]()><()<>>]]{[{[][] 61 | {[(<{<{{{[(((({}[]){(){}})(<(){}>{{}<>})){([[]<>]{[]<>})[[<>{}]{<>()}]}){(([<><>][{}[]])([<>] 62 | [<({[[[[{<<{[{[]()}<[][]>](<{}<>>[{}{}])}{({{}()}((){}))([()<>]<<>()>)}>>[<([{()()}{[]()}]{[< 63 | {<{{([{<([<[{<(){}>(()[])}<<(){}>{{}{}}>][{[(){}](<>())}[{<><>}<[]{})]]>({({[]()}[[][]])<{<>()}<[]() 64 | [{{<[{<((([{{<[]{}>[[]{}]}{<<><>>[<>[]]}}](({<<>{}><[]>}<(<>)>)[((<>{}){<>[]})[{{}<>}<[]()>]] 65 | ([<<{([<[<<([([]{})[{}()]]<(<><>)<()<>>>)><([{{}<>}[(){}]]([{}<>](<>{}))){<<[]<>>{()<>}>[<()<>>(<>) 66 | {{({({(<{({<{[()()]{[]{}}}[<{}[]>]>{[{<>[]}{{}()}](<<>{}>[{}<>])}}[{<[{}{}]<<>[])>([{}[]]{{}[]}) 67 | <{((<([<[{([([<>{}]([]<>))]{{<{}[]>[[][]]}})([(<{}{}>{()<>})[[[]()][{}{}]]}[{{{}()}<<>()>} 68 | [{<[<<({({<[{<<>[]><<>{}>}<{<><>}<{}()>>][([[]()]{<>{}})]>{(<[{}[]]([]<>)>}<<[{}[]][{}<>]>{{{}()}{<>[] 69 | [{<<([([[{<((({}<>)[{}()])[{[]()}(<><>)])<[<()<>)(<>())]>>([((<>()))[[{}]([][])]]<([<>()]<()()>)>)}(([<{ 70 | (<(([{<{(<([[[<>[]]{[][]}][((){})]])([((()())({}{}))(<<><>>)]<([[]<>]((){}>)({[]{}}{<>()})>)>)({{{{[ 71 | {<<{{(<{[<{{<({}[])<{}[]>><([]())<{}<>>>}<([[]{}]<()<>>)>}>{<(([<>[]]([]()))<{{}{}}(<>[])>){[([]() 72 | {{(({<{[{[[[([{}<>](()))]{{{{}{}}{<>{}}}[[{}{}]([]<>)]}][([(<><>)[[][]]])<<(()())(()<>)>[([]()){() 73 | (<[{<<[<<[(<{{<>{}}{[]<>}}[{[][]}[()[]]]>[<(<>())((){})>{({}{}){[]<>}}])]]>((([(<[<>{}]{{}<>}>{( 74 | (<<{{<[{[(<<<[{}{}]([][])>[{()<>}[{}]]>{({()[]})(<()<>>(()))}>)}}][[<([({<{}>[<>[]]}){({()[]}(()[])){ 75 | <(<([<<({[{(((<>[])<<><>>){{<>{}>}){{[()[]]<{}{}>}{({}{}){<>()}}}}[(<<<>{}>[{}{}]>(<()[]>[<><>]) 76 | [{[<<{[<(([[({<>{}}(<>))<<()()>[<>{}]>][{{[]{}}}<<<>()>({})>]]><{([(<><>)]<<(){}>{{}{}}>){{{{}[]}<<><>>}[[() 77 | [[[[<{(({{(<<<{}><[]{}>>((()[])[{}()])><<{[]<>}{<>[]}>[(<>()){{}<>}]>)(({(<>())({}[])}){[<(){}><[]{}>][[ 78 | <{[[<{<[<<[{([()()]{()()})[{[]()){{}{}}]}][{({<>{}})<[()()]{[]()}>}<[[(){}][{}[]]]{{<>[]}}>]><(([(()()) 79 | {<<(<(([<<{[{<[][]>}{([]())[()<>]}]{[[<>]<[][]>](([]{})(()[]))})[<<[{}<>]{<>{}}>[([]<>)[{}[]]]><( 80 | [([({([([{<({<<>{}>[{}]})<[({}{})({}{})][{{}()}(<>{})]>><{{([]{})([][])}[[{}[]]<<><>>]}<((<><>)[() 81 | ([[[[{{{{{{{<<(){}>{<><>}}{[{}[]]({}[])}}<({{}[]}[<>]){<<>{}>{()[]}}>}{{{(()[])}{{{}}}}{[([]()) 82 | (<{(({<<<{(<[<[][]>]<<{}<>>{{}{}}>><[{[]<>][<>[]]][[<><>]<[]()>]>)[(<([]{}){[]{}}>({{}{}}) 83 | <((({[(<<{({(([][])){[[]<>]}}<(({}{})({}{}))(<[]()>[()()])>)}>({(<[([]())[[]<>>]([[]{}]<[]<>>)><{{()[]} 84 | <{(<<({[(({{({<>[]}(<>{}))<<()[]>{<><>}>}<<<()[]>[(){}]>>})<{({(<>[]){<>[]}}[[<><>]])<[(())(<>[]) 85 | [([<[{[[{({{({[]<>}{[]()})([{}{}](()<>))}{(<[]<>><<>[]>)}})}<<([<[<>()]<[][]>>([[][]]{[]{}})](<<() 86 | <<<(<({[{[{{(<{}>[{}{}])(([][])[(){}])}{([{}<>](<>))}}]}[<<{<((){}){[]{}}>({{}<>}{[][]})}<{{()()}<<><>>}>>{(( 87 | <<<{{{((<[<<{<[]{}>}><[({}{})[[]<>]]>>[<([<>()](()))<(<><>)(()())>>[{<()<>>{()()}}]]]({(({[]{}}({}[])))<({{ 88 | [<{[{[[{{{[{({<>[]}<[][]>)[{(){}}{{}()}]}<[[()()][{}()]](({}<>)[()()])>]<({<{}<>>({})}([()<>])){[{()< 89 | <{{{{([(([{{{<{}[]>(()[])}{({}[])({}[])}}}])<{({<({}<>]<<>{}>>[<()<>>({}())]}[<<[]()>[<>()]>(<()<>>{<>[]})]) 90 | ((([({[<[[([([<>[]]<[]<>>)(<()<>>)]{[{<>)[()()]][([]()){[]<>}]})]][{((<[<>[]]{<>()}>[<()<>>[{ 91 | <[<{[[<[<<{{(<[]{}>){[()]({}{})}}(<[()[]]{[]()}>[<()[]>])}{{({[]<>>([]{})){{()<>}{<>[]}}}(<(< 92 | <[<<<[{<[<[[{(()<>)[()<>]}]({{()<>}({}())}[[{}()]])][{([<>{}]){({}[])([]{})}}]>[[[<(<>{})<(){}>>]}]] 93 | <<[[[{[<[(<<<{<><>}(()[])>{{()()}[()[]]}>>)[<{[<[]()>({}{})]{{{}[]}[[]]}}{{{[]<>}{()()}}}>[[[[(){}]({}<>)]{ 94 | <[<((<<<{<[({[[][]]<{}{}>})({{<>{}}[()<>]}(({}{})[[]()]))]({{(<><>)<<>()>}{[[]{}]}}({(()())[{}() 95 | -------------------------------------------------------------------------------- /src/day10/mod.rs: -------------------------------------------------------------------------------- 1 | use arrayvec::ArrayVec; 2 | 3 | use crate::utils::*; 4 | 5 | const fn map() -> [u8; 256] { 6 | let mut map = [0; 256]; 7 | map[b'(' as usize] = 2; 8 | map[b')' as usize] = 3; 9 | map[b'[' as usize] = 4; 10 | map[b']' as usize] = 5; 11 | map[b'{' as usize] = 6; 12 | map[b'}' as usize] = 7; 13 | map[b'<' as usize] = 8; 14 | map[b'>' as usize] = 9; 15 | map 16 | } 17 | 18 | #[inline] 19 | fn build_stack<'a>(s: &[u8], stack: &'a mut [u8]) -> (u8, &'a [u8]) { 20 | const MAP: [u8; 256] = map(); 21 | let mut stack = UnsafeStack::new(stack); 22 | for &c in s { 23 | let c = MAP.get_at(c as _); 24 | if c & 1 == 0 { 25 | stack.push(c); 26 | } else if c != stack.pop() | 1 { 27 | return (c, stack.into_slice()); 28 | } 29 | } 30 | (0, stack.into_slice()) 31 | } 32 | 33 | const fn part1_scores() -> [u32; 10] { 34 | let mut scores = [0; 10]; 35 | scores[3] = 3; 36 | scores[5] = 57; 37 | scores[7] = 1197; 38 | scores[9] = 25137; 39 | scores 40 | } 41 | 42 | pub fn input() -> &'static [u8] { 43 | include_bytes!("input.txt") 44 | } 45 | 46 | pub fn part1(mut s: &[u8]) -> u32 { 47 | const SCORES: [u32; 10] = part1_scores(); 48 | let mut stack = [0; 128]; 49 | let mut answer = 0; 50 | while s.len() > 1 { 51 | let n = s.memchr(b'\n'); 52 | let c = build_stack(&s[..n], &mut stack).0; 53 | answer += SCORES.get_at(c as _); 54 | s = s.advance(n + 1); 55 | } 56 | answer 57 | } 58 | 59 | pub fn part2(mut s: &[u8]) -> usize { 60 | let mut scores = ArrayVec::::new(); 61 | let mut stack = [0; 128]; 62 | while s.len() > 1 { 63 | let n = s.memchr(b'\n'); 64 | let (c, a) = build_stack(&s[..n], &mut stack); 65 | if c == 0 { 66 | scores.push(a.iter().rev().fold(0, |acc, &c| acc * 5 + (c >> 1) as usize)); 67 | } 68 | s = s.advance(n + 1); 69 | } 70 | let n = scores.len(); 71 | *scores.select_nth_unstable(n >> 1).1 72 | } 73 | 74 | #[test] 75 | fn test_day10_part1() { 76 | assert_eq!(part1(input()), 166191); 77 | } 78 | 79 | #[test] 80 | fn test_day10_part2() { 81 | assert_eq!(part2(input()), 1152088313); 82 | } 83 | -------------------------------------------------------------------------------- /src/day11/input.txt: -------------------------------------------------------------------------------- 1 | 2264552475 2 | 7681287325 3 | 3878781441 4 | 6868471776 5 | 7175255555 6 | 7517441253 7 | 3513418848 8 | 4628736747 9 | 1133155762 10 | 8816621663 11 | -------------------------------------------------------------------------------- /src/day11/mod.rs: -------------------------------------------------------------------------------- 1 | use std::iter; 2 | use std::mem; 3 | 4 | use crate::utils::*; 5 | 6 | const N: usize = 10; 7 | const W: usize = N + 2; 8 | 9 | type Cell = i16; 10 | type Grid = [[Cell; W]; W]; 11 | 12 | fn parse_grid(mut s: &[u8]) -> Grid { 13 | let mut grid = [[Cell::MIN; W]; W]; 14 | for i in 1..=N { 15 | for j in 1..=N { 16 | grid[i][j] = s.get_digit_at(j - 1) as Cell; 17 | } 18 | s = s.advance(N + 1); 19 | } 20 | grid 21 | } 22 | 23 | fn evolve_dfs(grid: Grid) -> impl Iterator { 24 | type FlatGrid = [Cell; W * W]; 25 | let mut grid: FlatGrid = unsafe { mem::transmute(grid) }; 26 | 27 | type Stack = Vec; 28 | let mut stack = Stack::with_capacity(W * W); 29 | let mut next = stack.clone(); 30 | 31 | #[inline] 32 | fn bump_and_check(stack: &mut Stack, grid: &mut FlatGrid, i: usize, reset: bool) { 33 | let cell = unsafe { grid.get_unchecked_mut(i) }; 34 | if *cell < 9 { 35 | if reset { 36 | *cell = (*cell).max(0) + 1; 37 | } else { 38 | *cell += 1; 39 | } 40 | } else { 41 | *cell = Cell::MIN; 42 | stack.push(i); 43 | } 44 | } 45 | 46 | iter::from_fn(move || { 47 | let mut n_flashes = 0; 48 | for i in 1..=N { 49 | for j in 1..=N { 50 | bump_and_check(&mut stack, &mut grid, i * W + j, true); 51 | } 52 | } 53 | while !stack.is_empty() { 54 | n_flashes += stack.len(); 55 | mem::swap(&mut stack, &mut next); 56 | unsafe { 57 | stack.set_len(0); 58 | } 59 | for &i in &next { 60 | for j in [i - W - 1, i - W, i - W + 1, i - 1, i + 1, i + W - 1, i + W, i + W + 1] { 61 | bump_and_check(&mut stack, &mut grid, j, false); 62 | } 63 | } 64 | } 65 | Some(n_flashes) 66 | }) 67 | } 68 | 69 | pub fn input() -> &'static [u8] { 70 | include_bytes!("input.txt") 71 | } 72 | 73 | pub fn part1(s: &[u8]) -> usize { 74 | evolve_dfs(parse_grid(s)).take(100).sum() 75 | } 76 | 77 | pub fn part2(s: &[u8]) -> usize { 78 | 1 + evolve_dfs(parse_grid(s)).take_while(|n| *n != N * N).count() 79 | } 80 | 81 | #[test] 82 | fn test_day11_part1() { 83 | assert_eq!(part1(input()), 1632); 84 | } 85 | 86 | #[test] 87 | fn test_day11_part2() { 88 | assert_eq!(part2(input()), 303); 89 | } 90 | -------------------------------------------------------------------------------- /src/day12/input.txt: -------------------------------------------------------------------------------- 1 | start-co 2 | ip-WE 3 | end-WE 4 | le-ls 5 | wt-zi 6 | end-sz 7 | wt-RI 8 | wt-sz 9 | zi-start 10 | wt-ip 11 | YT-sz 12 | RI-start 13 | le-end 14 | ip-sz 15 | WE-sz 16 | le-WE 17 | le-wt 18 | zi-ip 19 | RI-zi 20 | co-zi 21 | co-le 22 | WB-zi 23 | wt-WE 24 | co-RI 25 | RI-ip 26 | -------------------------------------------------------------------------------- /src/day12/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Debug}; 2 | 3 | use arrayvec::ArrayVec; 4 | 5 | use crate::utils::*; 6 | 7 | const MAX_NODES: usize = 16; 8 | const MAX_EDGES: usize = 8; 9 | const START: usize = 0; 10 | const END: usize = 1; 11 | const START_NAME: [u8; 2] = [0, 0]; 12 | const END_NAME: [u8; 2] = [0xff, 0xff]; 13 | 14 | type Mask = u8; 15 | type VisitedCache = ArrayVec<[[u32; 256]; 2], MAX_NODES>; 16 | 17 | #[inline] 18 | fn cache_get_mut(cache: &mut VisitedCache, i: usize, twice: bool, mask: Mask) -> &mut u32 { 19 | unsafe { 20 | cache 21 | .get_unchecked_mut(i) 22 | .get_unchecked_mut(twice as usize) 23 | .get_unchecked_mut(mask as usize) 24 | } 25 | } 26 | 27 | #[derive(Clone)] 28 | struct Node { 29 | mask: Mask, 30 | edges: ArrayVec, 31 | name: [u8; 2], 32 | } 33 | 34 | impl Debug for Node { 35 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 36 | write!(f, "Node(")?; 37 | if self.name == START_NAME { 38 | write!(f, "start")?; 39 | } else if self.name == END_NAME { 40 | write!(f, "end")?; 41 | } else { 42 | write!(f, "\"{}{}\"", char::from(self.name[0]), char::from(self.name[1]))?; 43 | } 44 | if self.mask != 0 { 45 | write!(f, ", mask={}", self.mask)?; 46 | } 47 | write!(f, ", edges={:?})", self.edges) 48 | } 49 | } 50 | 51 | impl Node { 52 | pub fn new(name: [u8; 2], mask: Mask) -> Self { 53 | Self { mask, edges: ArrayVec::new(), name } 54 | } 55 | } 56 | 57 | #[derive(Debug, Clone)] 58 | struct Graph { 59 | nodes: ArrayVec, 60 | n_small: usize, 61 | } 62 | 63 | impl Graph { 64 | pub fn new() -> Self { 65 | let mut nodes = ArrayVec::new(); 66 | nodes.push(Node::new(START_NAME, 0)); 67 | nodes.push(Node::new(END_NAME, 0)); 68 | Self { nodes, n_small: 0 } 69 | } 70 | 71 | fn find_or_insert_node(&mut self, name: &[u8]) -> usize { 72 | match name.len() { 73 | 5 => START, 74 | 3 => END, 75 | 2 => { 76 | let name = [name.get_at(0), name.get_at(1)]; 77 | self.nodes.iter().position(|n| n.name == name).unwrap_or_else(|| { 78 | let index = self.nodes.len(); 79 | let mask = if name[0].is_ascii_lowercase() { 80 | self.n_small += 1; 81 | assert!(self.n_small <= 8); 82 | 1 << (self.n_small - 1) 83 | } else { 84 | 0 85 | }; 86 | self.nodes.push(Node::new(name, mask)); 87 | index 88 | }) 89 | } 90 | _ => unsafe { core::hint::unreachable_unchecked() }, 91 | } 92 | } 93 | 94 | fn add_edge(&mut self, i: usize, j: usize) { 95 | if i != END && j != START { 96 | self.nodes[i].edges.push(j); 97 | } 98 | if j != END && i != START { 99 | self.nodes[j].edges.push(i); 100 | } 101 | } 102 | 103 | pub fn trim(mut self) -> Self { 104 | // remove nodes that will be unused anyway (that have a single edge leading to small) 105 | let mut remove = ArrayVec::::new(); 106 | for (i, node) in self.nodes.iter().enumerate().rev() { 107 | if node.edges.len() == 1 && self.nodes[node.edges[0]].mask != 0 { 108 | remove.push(i); 109 | } 110 | } 111 | for i in remove { 112 | if self.nodes[i].mask != 0 { 113 | self.n_small -= 1; 114 | } 115 | for node in &mut self.nodes { 116 | node.edges = node 117 | .edges 118 | .iter() 119 | .filter_map(|&e| { 120 | if e == i { 121 | None 122 | } else if e < i { 123 | Some(e) 124 | } else { 125 | Some(e - 1) 126 | } 127 | }) 128 | .collect(); 129 | } 130 | self.nodes.remove(i); 131 | } 132 | self 133 | } 134 | 135 | pub fn parse(mut s: &[u8]) -> Self { 136 | let mut g = Self::new(); 137 | while s.len() > 1 { 138 | let k = s.memchr(b'-'); 139 | let i = g.find_or_insert_node(&s[..k]); 140 | s = s.advance(k + 1); 141 | let k = s.memchr(b'\n'); 142 | let j = g.find_or_insert_node(&s[..k]); 143 | s = s.advance(k + 1); 144 | g.add_edge(i, j); 145 | } 146 | g 147 | } 148 | 149 | pub fn count_paths(&self, allow_twice: bool) -> usize { 150 | let mut cache = VisitedCache::new(); 151 | for _ in 0..self.nodes.len() { 152 | cache.push([[u32::MAX; 256]; 2]); 153 | } 154 | self.count_paths_impl(START, false, 0, allow_twice, &mut cache) as _ 155 | } 156 | 157 | fn count_paths_impl( 158 | &self, i: usize, twice: bool, mask: Mask, allow_twice: bool, cache: &mut VisitedCache, 159 | ) -> u32 { 160 | let cached = *cache_get_mut(cache, i, twice, mask); 161 | if cached != u32::MAX { 162 | cached 163 | } else if i == END { 164 | 1 165 | } else { 166 | let node = unsafe { self.nodes.get_unchecked(i) }; 167 | let (new_mask, new_twice) = if node.mask & mask != 0 { 168 | if allow_twice && !twice { 169 | (mask, true) 170 | } else { 171 | return 0; 172 | } 173 | } else { 174 | (mask | node.mask, twice) 175 | }; 176 | let count = node 177 | .edges 178 | .iter() 179 | .map(|&j| self.count_paths_impl(j, new_twice, new_mask, allow_twice, cache)) 180 | .sum(); 181 | *cache_get_mut(cache, i, twice, mask) = count; 182 | count 183 | } 184 | } 185 | 186 | #[allow(unused)] 187 | pub fn count_paths_naive(&self, allow_twice: bool) -> usize { 188 | self.count_paths_naive_impl(START, 0, false, allow_twice) 189 | } 190 | 191 | fn count_paths_naive_impl( 192 | &self, i: usize, mut mask: Mask, mut twice: bool, allow_twice: bool, 193 | ) -> usize { 194 | if i == END { 195 | return 1; 196 | } 197 | let node = &self.nodes[i]; 198 | if node.mask & mask != 0 { 199 | if allow_twice && !twice { 200 | twice = true; 201 | } else { 202 | return 0; 203 | } 204 | } else { 205 | mask |= node.mask; 206 | } 207 | node.edges.iter().map(|&j| self.count_paths_naive_impl(j, mask, twice, allow_twice)).sum() 208 | } 209 | } 210 | 211 | pub fn input() -> &'static [u8] { 212 | include_bytes!("input.txt") 213 | } 214 | 215 | pub fn part1(s: &[u8]) -> usize { 216 | Graph::parse(s).trim().count_paths(false) 217 | } 218 | 219 | pub fn part2(s: &[u8]) -> usize { 220 | // note: we can't trim the graph here since we can return to small caves twice 221 | Graph::parse(s).count_paths(true) 222 | } 223 | 224 | #[test] 225 | fn test_day12_part1() { 226 | assert_eq!(part1(input()), 5756); 227 | } 228 | 229 | #[test] 230 | fn test_day12_part2() { 231 | assert_eq!(part2(input()), 144603); 232 | } 233 | -------------------------------------------------------------------------------- /src/day13/input.txt: -------------------------------------------------------------------------------- 1 | 724,201 2 | 596,511 3 | 883,560 4 | 637,47 5 | 869,537 6 | 251,505 7 | 851,618 8 | 980,544 9 | 818,661 10 | 1093,390 11 | 641,95 12 | 1006,621 13 | 447,434 14 | 820,865 15 | 475,847 16 | 788,72 17 | 1066,829 18 | 1303,882 19 | 1165,696 20 | 164,229 21 | 202,333 22 | 244,485 23 | 261,840 24 | 1116,581 25 | 976,513 26 | 550,635 27 | 1151,728 28 | 1211,570 29 | 228,422 30 | 223,539 31 | 406,369 32 | 306,758 33 | 1247,894 34 | 760,859 35 | 826,737 36 | 340,637 37 | 1293,47 38 | 99,187 39 | 264,553 40 | 927,523 41 | 940,189 42 | 586,313 43 | 525,67 44 | 296,581 45 | 353,694 46 | 55,264 47 | 582,491 48 | 264,154 49 | 512,394 50 | 1101,225 51 | 555,187 52 | 1021,535 53 | 805,772 54 | 783,891 55 | 403,402 56 | 1243,94 57 | 495,593 58 | 1031,695 59 | 13,472 60 | 705,637 61 | 459,618 62 | 939,322 63 | 251,82 64 | 899,523 65 | 301,131 66 | 873,891 67 | 880,374 68 | 894,737 69 | 306,593 70 | 1257,280 71 | 88,885 72 | 621,655 73 | 38,640 74 | 514,539 75 | 1222,885 76 | 1257,135 77 | 1191,303 78 | 1034,715 79 | 649,738 80 | 719,103 81 | 1131,367 82 | 907,402 83 | 169,297 84 | 482,408 85 | 977,866 86 | 1280,432 87 | 1087,803 88 | 473,810 89 | 182,546 90 | 785,155 91 | 1257,871 92 | 1091,483 93 | 310,52 94 | 758,712 95 | 870,715 96 | 1211,772 97 | 1173,40 98 | 73,460 99 | 117,312 100 | 228,243 101 | 918,822 102 | 475,50 103 | 765,3 104 | 1113,410 105 | 127,544 106 | 880,422 107 | 291,675 108 | 1088,187 109 | 957,506 110 | 591,791 111 | 566,437 112 | 1178,593 113 | 159,728 114 | 1237,684 115 | 490,665 116 | 929,311 117 | 641,267 118 | 966,766 119 | 1081,253 120 | 735,649 121 | 857,750 122 | 999,367 123 | 989,221 124 | 0,185 125 | 445,395 126 | 108,168 127 | 586,761 128 | 1203,595 129 | 1115,89 130 | 838,665 131 | 487,301 132 | 289,647 133 | 903,133 134 | 251,53 135 | 887,800 136 | 1093,443 137 | 775,684 138 | 1026,481 139 | 601,311 140 | 661,476 141 | 1198,627 142 | 0,753 143 | 1231,786 144 | 410,821 145 | 358,742 146 | 1179,780 147 | 763,435 148 | 1077,133 149 | 927,182 150 | 681,144 151 | 497,597 152 | 1088,483 153 | 649,476 154 | 1202,415 155 | 440,583 156 | 1198,14 157 | 104,775 158 | 619,443 159 | 410,660 160 | 1034,656 161 | 115,575 162 | 601,728 163 | 338,222 164 | 84,301 165 | 1111,891 166 | 1211,122 167 | 653,614 168 | 1290,282 169 | 209,582 170 | 440,43 171 | 929,583 172 | 53,166 173 | 1004,301 174 | 263,572 175 | 818,233 176 | 1183,319 177 | 228,472 178 | 1257,166 179 | 656,329 180 | 53,135 181 | 669,267 182 | 815,593 183 | 1111,767 184 | 802,576 185 | 1226,660 186 | 1215,800 187 | 341,218 188 | 181,422 189 | 1046,565 190 | 159,280 191 | 119,303 192 | 1027,303 193 | 147,417 194 | 571,859 195 | 1173,261 196 | 1054,885 197 | 239,302 198 | 228,131 199 | 85,217 200 | 1231,226 201 | 137,709 202 | 21,131 203 | 1290,612 204 | 718,845 205 | 837,782 206 | 164,141 207 | 632,467 208 | 749,313 209 | 525,379 210 | 858,561 211 | 851,786 212 | 1228,857 213 | 33,239 214 | 868,670 215 | 1183,3 216 | 248,548 217 | 328,345 218 | 898,436 219 | 438,893 220 | 823,301 221 | 820,589 222 | 937,771 223 | 875,58 224 | 790,617 225 | 64,504 226 | 95,675 227 | 508,576 228 | 729,434 229 | 186,91 230 | 1092,392 231 | 403,166 232 | 87,514 233 | 1261,114 234 | 1141,597 235 | 217,390 236 | 689,151 237 | 457,515 238 | 585,805 239 | 1131,360 240 | 1212,472 241 | 669,464 242 | 318,682 243 | 485,73 244 | 1154,644 245 | 738,37 246 | 1297,870 247 | 361,207 248 | 932,238 249 | 880,264 250 | 376,738 251 | 87,380 252 | 174,94 253 | 411,819 254 | 845,633 255 | 1288,721 256 | 189,261 257 | 1294,374 258 | 72,267 259 | 649,642 260 | 156,644 261 | 517,406 262 | 705,562 263 | 1059,614 264 | 813,856 265 | 623,702 266 | 619,462 267 | 403,728 268 | 344,52 269 | 1178,634 270 | 1275,238 271 | 656,47 272 | 1176,169 273 | 244,821 274 | 328,121 275 | 1092,255 276 | 872,1 277 | 845,185 278 | 251,707 279 | 79,674 280 | 659,705 281 | 1048,520 282 | 1121,709 283 | 107,768 284 | 427,334 285 | 1257,311 286 | 112,14 287 | 997,351 288 | 552,429 289 | 1064,159 290 | 1114,453 291 | 398,306 292 | 1208,182 293 | 187,175 294 | 654,719 295 | 1225,665 296 | 735,245 297 | 1078,245 298 | 544,598 299 | 691,238 300 | 1168,164 301 | 264,740 302 | 855,833 303 | 1260,267 304 | 661,156 305 | 333,194 306 | 1212,870 307 | 555,803 308 | 445,11 309 | 1275,443 310 | 1067,35 311 | 783,787 312 | 785,379 313 | 162,141 314 | 661,866 315 | 873,3 316 | 321,476 317 | 1136,800 318 | 673,47 319 | 723,800 320 | 1129,84 321 | 127,891 322 | 927,371 323 | 781,647 324 | 1099,247 325 | 1275,3 326 | 691,891 327 | 218,639 328 | 731,626 329 | 1093,504 330 | 550,735 331 | 1019,880 332 | 477,142 333 | 147,508 334 | 392,822 335 | 542,432 336 | 209,235 337 | 410,234 338 | 895,113 339 | 107,798 340 | 7,23 341 | 119,591 342 | 709,364 343 | 1059,340 344 | 1198,148 345 | 179,360 346 | 226,49 347 | 43,98 348 | 195,640 349 | 452,561 350 | 49,52 351 | 359,761 352 | 1307,749 353 | 1235,392 354 | 556,355 355 | 547,58 356 | 790,725 357 | 8,683 358 | 1261,724 359 | 301,185 360 | 69,89 361 | 545,339 362 | 957,759 363 | 509,84 364 | 1235,564 365 | 663,12 366 | 1017,743 367 | 739,332 368 | 1213,392 369 | 1067,444 370 | 291,616 371 | 969,851 372 | 353,819 373 | 669,95 374 | 902,436 375 | 127,575 376 | 887,143 377 | 671,79 378 | 796,539 379 | 865,11 380 | 289,247 381 | 465,709 382 | 605,724 383 | 194,581 384 | 1223,788 385 | 810,771 386 | 932,208 387 | 333,225 388 | 1308,96 389 | 1257,23 390 | 709,311 391 | 87,123 392 | 845,807 393 | 845,574 394 | 552,630 395 | 1226,234 396 | 16,374 397 | 1247,0 398 | 381,311 399 | 957,11 400 | 393,392 401 | 545,219 402 | 523,332 403 | 820,661 404 | 472,229 405 | 1079,542 406 | 99,570 407 | 311,847 408 | 1130,500 409 | 519,135 410 | 207,434 411 | 435,235 412 | 373,499 413 | 731,368 414 | 800,348 415 | 373,771 416 | 904,861 417 | 687,192 418 | 1297,24 419 | 681,131 420 | 545,555 421 | 705,170 422 | 1009,200 423 | 63,828 424 | 1193,582 425 | 211,647 426 | 982,495 427 | 1206,159 428 | 1014,581 429 | 284,481 430 | 1294,394 431 | 5,156 432 | 641,627 433 | 744,885 434 | 900,212 435 | 557,887 436 | 908,289 437 | 786,856 438 | 785,515 439 | 527,61 440 | 73,684 441 | 698,637 442 | 522,294 443 | 79,226 444 | 843,175 445 | 754,315 446 | 798,606 447 | 25,730 448 | 790,169 449 | 947,686 450 | 509,646 451 | 157,38 452 | 994,451 453 | 31,702 454 | 622,453 455 | 390,742 456 | 256,558 457 | 1274,448 458 | 950,833 459 | 619,238 460 | 723,94 461 | 67,94 462 | 490,383 463 | 447,658 464 | 654,686 465 | 407,313 466 | 1054,9 467 | 982,175 468 | 1215,766 469 | 1198,880 470 | 1054,306 471 | 1305,156 472 | 407,245 473 | 328,208 474 | 273,787 475 | 693,807 476 | 939,751 477 | 232,245 478 | 1047,770 479 | 1063,133 480 | 87,828 481 | 1285,409 482 | 787,803 483 | 1056,715 484 | 654,701 485 | 1201,56 486 | 865,728 487 | 1000,318 488 | 546,31 489 | 671,63 490 | 490,29 491 | 863,658 492 | 234,841 493 | 940,481 494 | 7,460 495 | 1213,495 496 | 411,75 497 | 1280,856 498 | 949,599 499 | 743,106 500 | 301,435 501 | 390,497 502 | 416,157 503 | 411,523 504 | 1057,12 505 | 907,492 506 | 1138,486 507 | 132,301 508 | 383,571 509 | 833,304 510 | 271,323 511 | 788,238 512 | 726,112 513 | 30,432 514 | 1288,313 515 | 688,441 516 | 605,649 517 | 982,345 518 | 174,652 519 | 527,721 520 | 284,257 521 | 927,571 522 | 623,254 523 | 1082,243 524 | 977,669 525 | 472,665 526 | 705,724 527 | 947,768 528 | 559,800 529 | 951,133 530 | 207,460 531 | 279,247 532 | 360,833 533 | 1223,514 534 | 63,0 535 | 182,5 536 | 522,520 537 | 17,495 538 | 555,324 539 | 390,397 540 | 827,882 541 | 107,683 542 | 430,856 543 | 1150,656 544 | 579,788 545 | 769,170 546 | 164,677 547 | 1082,651 548 | 883,894 549 | 982,656 550 | 641,198 551 | 576,320 552 | 863,210 553 | 857,144 554 | 984,549 555 | 672,766 556 | 67,800 557 | 35,443 558 | 412,682 559 | 326,529 560 | 304,621 561 | 556,539 562 | 117,669 563 | 918,72 564 | 654,47 565 | 219,388 566 | 654,753 567 | 1246,56 568 | 654,641 569 | 1250,848 570 | 562,681 571 | 72,403 572 | 1228,305 573 | 641,422 574 | 758,856 575 | 1082,472 576 | 701,256 577 | 1077,761 578 | 820,511 579 | 755,324 580 | 658,509 581 | 960,733 582 | 801,10 583 | 769,378 584 | 430,38 585 | 647,12 586 | 129,291 587 | 201,750 588 | 522,374 589 | 837,422 590 | 75,564 591 | 977,225 592 | 609,256 593 | 855,350 594 | 1128,5 595 | 1245,495 596 | 1240,530 597 | 591,551 598 | 555,154 599 | 45,275 600 | 381,359 601 | 922,253 602 | 1026,257 603 | 251,280 604 | 629,798 605 | 739,371 606 | 492,708 607 | 719,551 608 | 508,318 609 | 678,427 610 | 1109,302 611 | 754,539 612 | 884,472 613 | 705,245 614 | 654,453 615 | 256,530 616 | 1184,793 617 | 79,201 618 | 731,788 619 | 1076,53 620 | 430,264 621 | 999,54 622 | 691,432 623 | 837,810 624 | 669,696 625 | 181,810 626 | 132,520 627 | 885,641 628 | 117,480 629 | 729,460 630 | 437,891 631 | 242,212 632 | 1263,507 633 | 353,75 634 | 316,787 635 | 179,24 636 | 967,815 637 | 490,305 638 | 214,583 639 | 801,646 640 | 1278,441 641 | 1163,392 642 | 485,521 643 | 845,709 644 | 104,159 645 | 276,715 646 | 85,229 647 | 522,145 648 | 214,851 649 | 377,257 650 | 490,661 651 | 1285,485 652 | 278,828 653 | 492,661 654 | 363,686 655 | 709,82 656 | 970,705 657 | 535,882 658 | 256,364 659 | 131,114 660 | 427,635 661 | 440,179 662 | 890,681 663 | 1029,571 664 | 360,61 665 | 78,413 666 | 746,179 667 | 1128,889 668 | 1288,173 669 | 1213,47 670 | 321,700 671 | 137,40 672 | 720,315 673 | 1241,89 674 | 137,807 675 | 99,539 676 | 104,287 677 | 527,891 678 | 415,116 679 | 229,253 680 | 574,605 681 | 276,686 682 | 329,838 683 | 1309,728 684 | 95,667 685 | 899,819 686 | 561,805 687 | 669,430 688 | 1206,735 689 | 1006,313 690 | 231,542 691 | 438,669 692 | 1211,355 693 | 947,880 694 | 783,168 695 | 93,581 696 | 415,302 697 | 195,254 698 | 231,784 699 | 442,670 700 | 872,225 701 | 800,98 702 | 817,58 703 | 1079,94 704 | 341,340 705 | 131,780 706 | 426,315 707 | 1211,826 708 | 1247,707 709 | 363,219 710 | 406,817 711 | 820,383 712 | 465,633 713 | 547,459 714 | 334,605 715 | 1115,254 716 | 927,164 717 | 5,866 718 | 239,778 719 | 97,847 720 | 271,730 721 | 75,392 722 | 438,225 723 | 326,686 724 | 570,301 725 | 564,179 726 | 195,192 727 | 1225,217 728 | 751,367 729 | 477,116 730 | 1116,805 731 | 801,84 732 | 247,674 733 | 189,126 734 | 1101,499 735 | 1161,570 736 | 989,418 737 | 400,491 738 | 810,123 739 | 468,397 740 | 1235,523 741 | 803,607 742 | 247,133 743 | 0,847 744 | 1146,305 745 | 884,315 746 | 164,569 747 | 913,313 748 | 412,212 749 | 112,627 750 | 209,312 751 | 711,523 752 | 427,894 753 | 1235,140 754 | 131,803 755 | 1232,413 756 | 199,891 757 | 49,724 758 | 947,14 759 | 313,351 760 | 898,10 761 | 1277,655 762 | 887,334 763 | 982,719 764 | 1230,829 765 | 316,222 766 | 209,728 767 | 592,845 768 | 1285,803 769 | 490,589 770 | 903,245 771 | 283,591 772 | 1197,516 773 | 197,827 774 | 619,451 775 | 509,884 776 | 1297,43 777 | 1141,73 778 | 1131,63 779 | 584,530 780 | 820,29 781 | 107,836 782 | 251,841 783 | 529,247 784 | 400,715 785 | 607,387 786 | 301,759 787 | 1048,374 788 | 227,707 789 | 281,771 790 | 711,607 791 | 1049,392 792 | 304,313 793 | 1235,626 794 | 209,883 795 | 452,333 796 | 30,408 797 | 403,492 798 | 510,98 799 | 933,68 800 | 161,58 801 | 1242,693 802 | 251,389 803 | 1191,322 804 | 1131,527 805 | 1213,439 806 | 586,201 807 | 904,369 808 | 783,319 809 | 929,359 810 | 838,348 811 | 878,411 812 | 109,443 813 | 1082,131 814 | 350,621 815 | 1048,889 816 | 326,208 817 | 763,96 818 | 132,593 819 | 84,350 820 | 1059,82 821 | 678,467 822 | 1091,836 823 | 1235,371 824 | 582,715 825 | 641,464 826 | 55,795 827 | 293,687 828 | 723,336 829 | 341,472 830 | 371,322 831 | 555,602 832 | 840,500 833 | 199,833 834 | 455,833 835 | 169,73 836 | 97,392 837 | 783,385 838 | 623,640 839 | 1111,840 840 | 765,891 841 | 1046,553 842 | 383,164 843 | 907,812 844 | 1131,870 845 | 1067,892 846 | 1129,472 847 | 246,436 848 | 644,670 849 | 624,38 850 | 353,135 851 | 666,227 852 | 835,399 853 | 112,148 854 | 247,859 855 | 383,99 856 | 535,684 857 | 338,555 858 | 552,805 859 | 594,17 860 | 880,472 861 | 801,436 862 | 997,472 863 | 559,667 864 | 341,676 865 | 247,35 866 | 1193,225 867 | 1,56 868 | 545,3 869 | 1149,58 870 | 455,710 871 | 753,887 872 | 687,640 873 | 1220,379 874 | 1115,724 875 | 1203,574 876 | 465,320 877 | 84,772 878 | 1273,359 879 | 873,339 880 | 783,3 881 | 199,54 882 | 1193,669 883 | 264,329 884 | 246,513 885 | 33,655 886 | 1293,495 887 | 432,187 888 | 601,871 889 | 803,47 890 | 825,373 891 | 259,110 892 | 586,245 893 | 412,436 894 | 927,347 895 | 345,775 896 | 970,257 897 | 870,311 898 | 899 | fold along x=655 900 | fold along y=447 901 | fold along x=327 902 | fold along y=223 903 | fold along x=163 904 | fold along y=111 905 | fold along x=81 906 | fold along y=55 907 | fold along x=40 908 | fold along y=27 909 | fold along y=13 910 | fold along y=6 911 | -------------------------------------------------------------------------------- /src/day13/mod.rs: -------------------------------------------------------------------------------- 1 | use std::iter; 2 | use std::mem; 3 | use std::str; 4 | 5 | use crate::utils::*; 6 | 7 | type T = i16; 8 | type Point = (T, T); 9 | 10 | const N_CHARS: usize = 8; 11 | const CHAR_W: usize = 4; 12 | const CHAR_H: usize = 6; 13 | 14 | #[inline] 15 | fn fold_1d(coord: &mut T, pivot: T) { 16 | if *coord > pivot { 17 | *coord = 2 * pivot - *coord 18 | } 19 | } 20 | 21 | #[derive(Debug, Copy, Clone)] 22 | struct Fold { 23 | pivot: T, 24 | is_y: bool, 25 | } 26 | 27 | impl Fold { 28 | #[inline] 29 | pub fn parse(s: &mut &[u8]) -> Option { 30 | if s.len() <= 1 { 31 | None 32 | } else { 33 | *s = s.advance(11); 34 | let is_y = s.get_first() == b'y'; 35 | *s = s.advance(2); 36 | let coord = parse_int_fast::(s); 37 | Some(Self { pivot: coord, is_y }) 38 | } 39 | } 40 | 41 | #[inline] 42 | pub fn apply<'a>(&self, points: impl IntoIterator) { 43 | if self.is_y { 44 | for point in points { 45 | fold_1d(&mut point.1, self.pivot); 46 | } 47 | } else { 48 | for point in points { 49 | fold_1d(&mut point.0, self.pivot); 50 | } 51 | } 52 | } 53 | } 54 | 55 | fn parse_points(s: &mut &[u8]) -> Vec<(T, T)> { 56 | let mut points = Vec::with_capacity(1 << 10); 57 | while s.get_first() != b'\n' { 58 | let x = parse_int_fast::(s); 59 | let y = parse_int_fast::(s); 60 | points.push((x, y)); 61 | } 62 | *s = s.advance(1); 63 | points 64 | } 65 | 66 | pub fn input() -> &'static [u8] { 67 | include_bytes!("input.txt") 68 | } 69 | 70 | pub fn part1(mut s: &[u8]) -> usize { 71 | let mut points = parse_points(&mut s); 72 | Fold::parse(&mut s).unwrap().apply(points.iter_mut()); 73 | 74 | assert_eq!(mem::size_of::(), mem::size_of::()); 75 | let mut points: Vec = unsafe { mem::transmute(points) }; // so that sort is faster 76 | points.sort_unstable(); 77 | 78 | points.iter().fold((u32::MAX, 0), |(prev, sum), &x| (x, sum + (x != prev) as usize)).1 79 | } 80 | 81 | #[allow(unused)] 82 | fn display_points<'a>(points: impl IntoIterator) -> String { 83 | let points = points.into_iter().collect::>(); 84 | let xmin = points.iter().map(|&p| p.0).min().unwrap(); 85 | let ymin = points.iter().map(|&p| p.1).min().unwrap(); 86 | let xmax = points.iter().map(|&p| p.0).max().unwrap(); 87 | let ymax = points.iter().map(|&p| p.1).max().unwrap(); 88 | let w = (xmax - xmin + 1) as usize; 89 | let h = (ymax - ymin + 1) as usize; 90 | let init = iter::repeat(b'.').take(w).collect::>(); 91 | let mut byte_lines = iter::repeat_with(|| init.clone()).take(h).collect::>(); 92 | for &point in points { 93 | byte_lines[(point.1 - ymin) as usize][(point.0 - xmin) as usize] = b'#'; 94 | } 95 | let str_lines = byte_lines.into_iter().map(|line| str::from_utf8(&line).unwrap().to_owned()); 96 | str_lines.fold(String::new(), |a, b| format!("{}\n{}", a, b)) 97 | } 98 | 99 | pub fn extract_letters<'a>(points: impl IntoIterator + Copy) -> [u8; N_CHARS] { 100 | let (xmin, xmax, ymin, ymax) = 101 | points.into_iter().fold((T::MAX, T::MIN, T::MAX, T::MIN), |acc, &(x, y)| { 102 | (acc.0.min(x), acc.1.max(x), acc.2.min(y), acc.3.max(y)) 103 | }); 104 | let w = (xmax - xmin + 1) as usize; 105 | let h = (ymax - ymin + 1) as usize; 106 | assert_eq!(w, 39); 107 | assert_eq!(h, 6); 108 | 109 | let mut pixels = [[[false; CHAR_W]; CHAR_H]; N_CHARS]; 110 | for &(x, y) in points { 111 | let x = (x - xmin) as usize; 112 | let y = (y - ymin) as usize; 113 | let (i, x) = (x / 5, x % 5); 114 | pixels[i][y][x] = true; 115 | } 116 | 117 | let mut letters_encoded = [0_u32; N_CHARS]; 118 | for (i, &pixel) in pixels.iter().enumerate() { 119 | let mut j = 0; 120 | for row in pixel { 121 | for c in row { 122 | letters_encoded[i] |= (c as u32) << j; 123 | j += 1; 124 | } 125 | } 126 | } 127 | 128 | const KNOWN_LETTERS: [(u32, u8); 7] = [ 129 | (0x00f1171f, b'E'), 130 | (0x00117997, b'P'), 131 | (0x00699999, b'U'), 132 | (0x00f11111, b'L'), 133 | (0x00117997, b'P'), 134 | (0x00799797, b'B'), 135 | (0x00957997, b'R'), 136 | ]; 137 | 138 | let mut out = [0_u8; N_CHARS]; 139 | for (i, &e) in letters_encoded.iter().enumerate() { 140 | for (known_encoded, known_char) in KNOWN_LETTERS { 141 | if e == known_encoded { 142 | out[i] = known_char; 143 | } 144 | } 145 | } 146 | out 147 | } 148 | 149 | pub fn part2(mut s: &[u8]) -> String { 150 | let mut points = parse_points(&mut s); 151 | while let Some(fold) = Fold::parse(&mut s) { 152 | fold.apply(&mut points); 153 | } 154 | str::from_utf8(&extract_letters(&points)).unwrap().to_owned() 155 | } 156 | 157 | #[test] 158 | fn test_day13_part1() { 159 | assert_eq!(part1(input()), 770); 160 | } 161 | 162 | #[test] 163 | fn test_day13_part2() { 164 | assert_eq!(part2(input()), "EPUELPBR"); 165 | } 166 | -------------------------------------------------------------------------------- /src/day14/input.txt: -------------------------------------------------------------------------------- 1 | KHSSCSKKCPFKPPBBOKVF 2 | 3 | OS -> N 4 | KO -> O 5 | SK -> B 6 | NV -> N 7 | SH -> V 8 | OB -> V 9 | HH -> F 10 | HP -> H 11 | BP -> O 12 | HS -> K 13 | SN -> B 14 | PS -> C 15 | BS -> K 16 | CF -> H 17 | SO -> C 18 | NO -> H 19 | PP -> H 20 | SS -> P 21 | KV -> B 22 | KN -> V 23 | CC -> S 24 | HK -> H 25 | FN -> C 26 | OO -> K 27 | CH -> H 28 | CP -> V 29 | HB -> N 30 | VC -> S 31 | SP -> F 32 | BO -> F 33 | SF -> H 34 | VO -> B 35 | FF -> P 36 | CN -> O 37 | NP -> H 38 | KK -> N 39 | OP -> S 40 | BH -> F 41 | CB -> V 42 | HC -> P 43 | KH -> V 44 | OV -> V 45 | NK -> S 46 | PN -> F 47 | VV -> N 48 | HO -> S 49 | KS -> C 50 | FP -> F 51 | FH -> F 52 | BB -> C 53 | FB -> V 54 | SB -> K 55 | KP -> B 56 | FS -> C 57 | KC -> P 58 | SC -> C 59 | VF -> F 60 | VN -> B 61 | CK -> C 62 | KF -> H 63 | NS -> C 64 | FV -> K 65 | HV -> B 66 | HF -> K 67 | ON -> S 68 | CV -> N 69 | BV -> F 70 | NB -> N 71 | NN -> F 72 | BF -> N 73 | VB -> V 74 | VS -> K 75 | BK -> V 76 | VP -> P 77 | PB -> F 78 | KB -> C 79 | VK -> O 80 | NF -> F 81 | FO -> F 82 | PH -> N 83 | VH -> B 84 | HN -> B 85 | FK -> K 86 | PO -> H 87 | CO -> B 88 | FC -> V 89 | OK -> F 90 | OF -> V 91 | PF -> F 92 | BC -> B 93 | BN -> O 94 | NC -> K 95 | SV -> H 96 | OH -> B 97 | PC -> O 98 | OC -> C 99 | CS -> P 100 | PV -> V 101 | NH -> C 102 | PK -> H 103 | -------------------------------------------------------------------------------- /src/day14/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::iter::Sum; 3 | use std::ops::{Add, AddAssign, Sub, SubAssign}; 4 | 5 | use crate::utils::*; 6 | 7 | const N: usize = 10; 8 | 9 | type Rules = [[u8; N]; N]; 10 | 11 | fn parse(mut s: &[u8]) -> (Vec, Rules) { 12 | let k = s.memchr(b'\n'); 13 | let word = &s[..k]; 14 | s = s.advance(k + 2); 15 | let (mut rev_map, mut n_chars, mut rules) = ([0xff; 256], 0, [[0; N]; N]); 16 | for _ in 0..N * N { 17 | assert!(!s.is_empty()); 18 | let mut line = [0; 3]; 19 | for (i, j) in [0, 1, 6].into_iter().enumerate() { 20 | let c = s.get_at(j); 21 | if rev_map[c as usize] == 0xff { 22 | rev_map[c as usize] = n_chars as u8; 23 | n_chars += 1; 24 | } 25 | line[i] = rev_map[c as usize]; 26 | } 27 | let [x, y, z] = line; 28 | rules[x as usize][y as usize] = z; 29 | s = s.advance(8); 30 | } 31 | let word = word.iter().map(|c| rev_map[*c as usize]).collect(); 32 | (word, rules) 33 | } 34 | 35 | fn solve(word: &[u8], rules: &Rules, n_iter: usize) -> T 36 | where 37 | T: Sum 38 | + Default 39 | + Copy 40 | + From 41 | + AddAssign 42 | + SubAssign 43 | + Sub 44 | + Ord 45 | + Debug 46 | + Add, 47 | { 48 | let mut matrix = [[T::default(); N]; N]; 49 | for i in 1..word.len() { 50 | matrix[word[i - 1] as usize][word[i] as usize] += T::from(1_u8); 51 | } 52 | 53 | let mut next = matrix; 54 | for _ in 0..n_iter { 55 | for left in 0..N { 56 | for right in 0..N { 57 | let c = rules[left][right] as usize; 58 | let n = matrix[left][right]; 59 | next[left][right] -= n; 60 | next[left][c] += n; 61 | next[c][right] += n; 62 | } 63 | } 64 | matrix = next; 65 | } 66 | 67 | let mut counts = matrix.map(|row| row.into_iter().sum::()); 68 | counts.sort_unstable(); 69 | counts[N - 1] - counts[0] + T::from(1_u8) 70 | } 71 | 72 | pub fn input() -> &'static [u8] { 73 | include_bytes!("input.txt") 74 | } 75 | 76 | pub fn part1(s: &[u8]) -> i16 { 77 | let (word, rules) = parse(s); 78 | solve(&word, &rules, 10) 79 | } 80 | 81 | pub fn part2(s: &[u8]) -> i64 { 82 | let (word, rules) = parse(s); 83 | solve(&word, &rules, 40) 84 | } 85 | 86 | #[test] 87 | fn test_day14_part1() { 88 | assert_eq!(part1(input()), 5656); 89 | } 90 | 91 | #[test] 92 | fn test_day14_part2() { 93 | assert_eq!(part2(input()), 12271437788530); 94 | } 95 | -------------------------------------------------------------------------------- /src/day15/input.txt: -------------------------------------------------------------------------------- 1 | 9956978467598825771298981722484596335818889199959653868179249999625599695779356228986873188891687284 2 | 2689689264298797391119983529199959929858717969159391918681149969777492315688758986884866649397344369 3 | 7172588131466121589783888671998218118876859987982967195137181498916455889797182194619794894661629837 4 | 1233915929951588187849869199557858368639699117699688284859878443929999216978195119999586994518395892 5 | 9936995927995999181961898584664489968882718885899689991948779689429318576999239788488143592176591999 6 | 4897812918593459844917171834839975629813379971269169715938988896273649199919822997859787183217266891 7 | 3933479167694699988319796863899446989269729449353695242844661984577961677295376286699769399319179358 8 | 8987971987557238146557624799143829841679714886637818814698722922629981272226771789888594293727111941 9 | 9674793972799591469997914789999881914562866899896527271538614679686339678188599786718883888297884985 10 | 3961546999429929697613295879446959999892529586841738538988955529791599788979945996552179737819798781 11 | 8844499362795969617994798868899899967824718292987354124929799999999618888579375128149986291724818549 12 | 6319846159183995575829928989855577928968687494197997676113642777249672499899922998489399689953482875 13 | 9318687755659372657924997867798988249219919195777499949395644897994967496851972899172918985191986597 14 | 1998599789837695923861376925899583587862947979985968841769887158695968694796847698692896798761999877 15 | 5389282482999389799417698173893793899555831488784993293489986775988887249661449988932199149826678929 16 | 8885947487894125927844118934698315379199888789929515426975914988499896859985997738397828665929167667 17 | 6298126815327916531712852259122155187297979818671127395658129297993863829999995739149985894397989743 18 | 1891818878562954593599769891715178798578198418759575992878686979669849659989376719878793751989873589 19 | 7985499598548294965777989549188571469396129839958919965359993968917797946999895164825697975265318994 20 | 8939965352883349869987249262938897838999248787325191338911189196687898923799292934597931568686612994 21 | 7883898892974459457272249846188161917193149598787915749973585899456996887596471274789926636819983548 22 | 2893991266649412992998149988584297828117178919999295117889696435789899766195171297784699292989289912 23 | 1889714497629498271876915259919916877619271584853928872546293189869749972719666595921649989796592959 24 | 7989499773979971784991185677884772123776243315312592283695855829888699449884842589715776989991789788 25 | 7969795549486918991741685993996689683991966793692719315219418594972994877669188497657994424741182716 26 | 9891947169875483798968286797952944449969337387522685989126929899999186138748689929857925548689799775 27 | 9934896897676629969846778999787616627743482859289949899173264238945619889896999992469794974489738168 28 | 9649159979125986881692895488749887858778122897977996878266986997989985581382219174136998186328958999 29 | 5868691619999883889799358879965896559782969287865997969412992135731371297995484417789177978999385999 30 | 4987897118498941972858679939188913296758597957999159988899986765499688389749658649972788771194622759 31 | 1484677635957996929559394997115194644415987837679917276568956717892651758726847486766995239622121618 32 | 9989825558961948591989389179598799512428197998473996198491319844117397786299159926869928984999524599 33 | 9917489296996997892917815829949821398462883759798899955315774553399987927967851318618379995454697825 34 | 9899299512998939797198987378498237991935772689793749139688253135773898648876616593117848746989718389 35 | 9997972916561279591989268558868997998782877967294893997282835818298696664999271999816281912219699946 36 | 6799984995998883892269931298291819919852918918797134688842882966259814991647587815893276276818959675 37 | 2871799844997986881319989698985799523755429889896999957822163591959924968239999854149897942628668477 38 | 1995516921867788958199262639437657998684938999998937819965919589587365113799977817192699734182899375 39 | 5911698839287819813698283389479956621591539915445638599938928889889999987592185459259842276386718359 40 | 6988184995767228398797357898988136259292456271151782749739585392874599153488799986677756154921998775 41 | 5889929568199528716917269697939589839936697973974687392391998983885167197295577686933487169797662969 42 | 3576282138549491591775319176995538717999696588956995986695547613191839999512898715915936144392561948 43 | 5329291717962161983227685489686918845996485997797396429999778881967959896987173997982847473369768897 44 | 9164877781748889899469935799585918943989878977762998481869615689939727996997779688475748199844328798 45 | 7991798237196899759673953382693927758496873888976788729351868197693796999369249969791967491137567799 46 | 9991695968149396561848295799981998693141199398256927816469955854719769376962761743394948485552314828 47 | 7186982892991599596272997398958488711982959664528917897576966858736399542649887128419993918518649589 48 | 8999989998887485976988528481447878238888715919917699589959417318968677596299273377619723799734898143 49 | 5169759894554293926482859352168158938898158397815319411261867193588842668867949888992986989912694675 50 | 8427473979159967517766496846922999759861788196891899348748453495589395979484411832439745788998684749 51 | 8979884898599659995653699764474992169918891845926589298187821985789331496992892739877557699399978889 52 | 4117135275897846694979693356776419864316434198781749699399367328249826173831856819118872599887929117 53 | 9879692658499978199599958786823949284997756118947995691794672327135471866488699919688193434735639585 54 | 5691984588698969477979699978918969898918843129191794615781694841492886319696159938666583888649697795 55 | 7189792431819239183896995186829891998578999466945599954117398899964997997971389145796939891639759499 56 | 9969315998289288839685999879984999391938198897279438593919898811199693927729161249553274797871579955 57 | 1397679395879587899999669189986964964999618829967419381999986859319416977398958959718958929978957382 58 | 6894969894281478382719899781799987581557999826119214189196671986242299959884989979649529422543719967 59 | 5981739475817947337868896926557129487952934635768334175511729813799968872337293512818311266539869789 60 | 5859971281996158947896999985565894597181699999239559563991657519998757442189829991395937666836311593 61 | 9968994867989926199441198198936757993274471923418981999389838988468878984888673962722692615494994916 62 | 3412989194698818488388395996795357868465884171614913988853947119968999199694989575882882897788754196 63 | 4767793319914896979199935929955397569993689616359493297947517199829987968826779949998365977814959924 64 | 2579972398289957987898849924347928451689465791831947348756986989948598821793892916666725547789741299 65 | 9698989769676955862992919199339895299629837998423697491249883483599482292954759887829993292627872191 66 | 1894619155917969889918757658925899599689781921899269989427239978652658489188493949679618396136949299 67 | 7712943759193929987161997175874316616112999266279789989697738811792676856992288912397788157897879898 68 | 7891199595911898419259681615768959188518795943876188369392846121938555699336786418329929798119869899 69 | 2796935459996838899793711969696999482299355989299989966798699899578998998995999694942878296779957749 70 | 4719483381989998499982591777895592799878676851889999639599194219135897985978325759838972952973185948 71 | 8965912619221745652577826328989598641499946592178869488499927162899585757385941597967851868197894763 72 | 8968695392792679597328229296399468238915291348856156176658189554419981971975789178898588648216792946 73 | 3694899896814879119881449917673689939386629993879189938479899217774991999917899821137417799198637637 74 | 5645661179381989929244868899917199387518895199571843654858799839999745993352769499895481849381896897 75 | 9651497219912776328185181986618747416337918889734673282681872989791999949935713999993969339279198953 76 | 4314949398895886943322397517587556441759979499928122411997918368816918184399881141261381347876568616 77 | 5187293161286489982862974561982928899978837649549913847496156789731291181557888959476992992881482582 78 | 9317992939383168491917991759264246565676891875962999958999757698623183898357397767392891287912962868 79 | 1799982437869993916939953411873913995541879869793889572866919896412765623887865749378966915413927898 80 | 9519787945431432316313866197973328267939581218979649989439384224999472881299732999597352772753791368 81 | 9288483569399269795915929419419136973331899194387846645998973819199773878634519282999223793324966229 82 | 6755829165937992937993893768199949761128166811959979779699129626188827215694641186878869191698651191 83 | 9799359993719926899876838991998368937197882188149191968977826896378899978686199548658893562678998579 84 | 3897958689718149561892985516687895789198398548689645643884695999999847494283968756796765389139599839 85 | 5818578147898416913367195515611597885861963578883578997187918599287756577474396983356312967793128892 86 | 9999892769284995919972819835547962786736828152819184951161662279799894817599791878181753149877894881 87 | 8299976964465999287197581918879685397888356594792988199697982765599427566287823683431351869995623962 88 | 8989496693957987663678978593593738931986779777991313898594961994695949896798884139938616151819966565 89 | 6898258912998949478473966768888494482448481939998236784669299799997816791891267967195319818818979489 90 | 7768427926996979688996299284916648789185799693838939518998993658998919289198619735288918586275797617 91 | 9877886949939119114117598819669599875829575673498688598163398885845347726982589975482198997862547995 92 | 5597689771938983973982619291188793285821886981895899191372797519999399581692538649838931291961891287 93 | 8577194549714988975998688698899479153995216852979764837138991671792834878995969442481912618443911927 94 | 9586172919854431896891871994969319226453687499979851699789283289898959899239286739579255644212647999 95 | 3966599598558974987689898899966735148191945177788188358719588958287189491299792478998288954884975941 96 | 9857984259191773999893262946889397892366998191262597118924895918951469846746979119989112768998759988 97 | 9487493194185853443118348557381979199114998581958626984133689529217198991359988198776267891998985428 98 | 7253864979196694796646966283794927398942982897999588293398762766965949771799885768956895355878512657 99 | 7939941892849576866851816855958734169789934758298874844919928289119988823599357892155959839679679918 100 | 8195996699568965579198729534577878698778991795617454587967117967862889252256796526887997997398959165 101 | -------------------------------------------------------------------------------- /src/day15/mod.rs: -------------------------------------------------------------------------------- 1 | use std::iter; 2 | use std::mem; 3 | use std::slice; 4 | 5 | use crate::utils::*; 6 | 7 | type Weight = u8; 8 | type Score = u16; 9 | 10 | const CAP: usize = 1 << 8; 11 | const K: usize = 16; // because cell weights are <= 9 12 | 13 | use arrayvec::ArrayVec; 14 | 15 | struct Queue { 16 | store: [ArrayVec; K], 17 | min_score: Score, 18 | start: usize, 19 | } 20 | 21 | impl Queue { 22 | pub fn new() -> Self { 23 | let store = 24 | iter::repeat_with(ArrayVec::new).take(K).collect::>().try_into().unwrap(); 25 | let (min_score, start) = (0, 0); 26 | Self { store, min_score, start } 27 | } 28 | 29 | #[inline] 30 | pub fn iter_min(&mut self, mut func: impl FnMut(&mut Queue, usize)) -> bool { 31 | for _ in 0..K { 32 | if !self.store[self.start].is_empty() { 33 | // ok, this is the dodgy part - BUT: 34 | // min node weight is >= 1, so there won't be any contention since 35 | // mutated nodes won't overlap with the top row being iterated over 36 | let queue_ref = unsafe { &mut *(self as *mut _) }; 37 | for &i in &self.store[self.start] { 38 | func(queue_ref, i); 39 | } 40 | self.store[self.start].clear(); 41 | return true; 42 | } 43 | self.start = (self.start + 1) % K; 44 | self.min_score += 1; 45 | } 46 | false 47 | } 48 | 49 | #[inline] 50 | pub fn push(&mut self, dist: Score, index: usize) { 51 | let i = (self.start + (dist - self.min_score) as usize) % K; 52 | unsafe { self.store[i].push_unchecked(index) }; 53 | } 54 | } 55 | 56 | #[derive(Debug, Clone, Copy)] 57 | #[repr(packed)] 58 | struct Cell { 59 | pub dist: Score, 60 | pub weight: Weight, 61 | pub is_free: bool, 62 | } 63 | 64 | struct Grid { 65 | cells: Vec, 66 | } 67 | 68 | impl Grid { 69 | const S: usize = (W - N * R) >> 1; 70 | const START: usize = W * Self::S + Self::S; 71 | const END: usize = W * W - W * Self::S - Self::S - 1; 72 | 73 | pub fn parse(mut s: &[u8]) -> Self { 74 | let mut cells = Vec::::with_capacity(W * W); 75 | unsafe { 76 | cells.set_len(W * W); 77 | slice::from_raw_parts_mut( 78 | cells.as_mut_ptr().cast::(), 79 | W * W * mem::size_of::(), 80 | ) 81 | .fill(0xff); 82 | } 83 | for i in 0..N { 84 | for j in 0..N { 85 | let weight = s.get_digit_at(j); 86 | let index = (Self::S + i) * W + (Self::S + j); 87 | for i_r in 0..R { 88 | for j_r in 0..R { 89 | let weight = if i_r != 0 || j_r != 0 { 90 | (((weight + i_r as Weight + j_r as Weight) - 1) % 9) + 1 91 | } else { 92 | weight 93 | }; 94 | let cell = &mut cells[index + N * (i_r * W + j_r)]; 95 | cell.weight = weight; 96 | cell.is_free = true; 97 | } 98 | } 99 | } 100 | s = s.advance(N + 1); 101 | } 102 | let start = &mut cells[Self::START]; 103 | start.is_free = false; 104 | start.dist = 0; 105 | Self { cells } 106 | } 107 | 108 | pub fn dijkstra(self) -> Score { 109 | let mut grid = self.cells; 110 | 111 | let mut queue = Queue::new(); 112 | queue.push(0, Self::START); 113 | 114 | while queue.iter_min(|queue, i| { 115 | let cell = grid[i]; 116 | for j in [i - W, i - 1, i + 1, i + W] { 117 | let neighbor = &mut grid[j]; 118 | if neighbor.weight == 0xff { 119 | continue; 120 | } 121 | let alt = cell.dist + neighbor.weight as Score; 122 | if alt < neighbor.dist { 123 | neighbor.dist = alt; 124 | if neighbor.is_free { 125 | neighbor.is_free = false; 126 | queue.push(alt, j); 127 | } 128 | } 129 | } 130 | }) {} 131 | grid[Self::END].dist 132 | } 133 | } 134 | 135 | pub fn input() -> &'static [u8] { 136 | include_bytes!("input.txt") 137 | } 138 | 139 | pub fn part1(s: &[u8]) -> Score { 140 | Grid::<100, 128, 1>::parse(s).dijkstra() 141 | } 142 | 143 | pub fn part2(s: &[u8]) -> Score { 144 | Grid::<100, 512, 5>::parse(s).dijkstra() 145 | } 146 | 147 | #[test] 148 | fn test_day15_part1() { 149 | assert_eq!(part1(input()), 714); 150 | } 151 | 152 | #[test] 153 | fn test_day15_part2() { 154 | assert_eq!(part2(input()), 2948); 155 | } 156 | -------------------------------------------------------------------------------- /src/day16/input.txt: -------------------------------------------------------------------------------- 1 | 4054460802532B12FEE8B180213B19FA5AA77601C010E4EC2571A9EDFE356C7008E7B141898C1F4E50DA7438C011D005E4F6E727B738FC40180CB3ED802323A8C3FED8C4E8844297D88C578C26008E004373BCA6B1C1C99945423798025800D0CFF7DC199C9094E35980253FB50A00D4C401B87104A0C8002171CE31C41201062C01393AE2F5BCF7B6E969F3C553F2F0A10091F2D719C00CD0401A8FB1C6340803308A0947B30056803361006615C468E4200E47E8411D26697FC3F91740094E164DFA0453F46899015002A6E39F3B9802B800D04A24CC763EDBB4AFF923A96ED4BDC01F87329FA491E08180253A4DE0084C5B7F5B978CC410012F9CFA84C93900A5135BD739835F00540010F8BF1D22A0803706E0A47B3009A587E7D5E4D3A59B4C00E9567300AE791E0DCA3C4A32CDBDC4830056639D57C00D4C401C8791162380021108E26C6D991D10082549218CDC671479A97233D43993D70056663FAC630CB44D2E380592FB93C4F40CA7D1A60FE64348039CE0069E5F565697D59424B92AF246AC065DB01812805AD901552004FDB801E200738016403CC000DD2E0053801E600700091A801ED20065E60071801A800AEB00151316450014388010B86105E13980350423F447200436164688A4001E0488AC90FCDF31074929452E7612B151803A200EC398670E8401B82D04E31880390463446520040A44AA71C25653B6F2FE80124C9FF18EDFCA109275A140289CDF7B3AEEB0C954F4B5FC7CD2623E859726FB6E57DA499EA77B6B68E0401D996D9C4292A881803926FB26232A133598A118023400FA4ADADD5A97CEEC0D37696FC0E6009D002A937B459BDA3CC7FFD65200F2E531581AD80230326E11F52DFAEAAA11DCC01091D8BE0039B296AB9CE5B576130053001529BE38CDF1D22C100509298B9950020B309B3098C002F419100226DC 2 | -------------------------------------------------------------------------------- /src/day16/mod.rs: -------------------------------------------------------------------------------- 1 | use arrayvec::ArrayVec; 2 | 3 | use crate::utils::*; 4 | 5 | type BitVec = ArrayVec; 6 | 7 | const fn hex2bin_map() -> [[u8; 4]; 256] { 8 | // for each u8 character, if it's in 0-9A-F range, convert it to binary representation 9 | let mut map = [[0xff; 4]; 256]; 10 | let mut i = 0_u8; 11 | while i < 16 { 12 | let c = if i < 10 { i + b'0' } else { i + b'A' - 10 }; 13 | let mut j = 0_u8; 14 | while j < 4 { 15 | map[c as usize][j as usize] = (i & (1 << (3 - j)) != 0) as u8; 16 | j += 1; 17 | } 18 | i += 1; 19 | } 20 | map 21 | } 22 | 23 | const HEX2BIN_MAP: [[u8; 4]; 256] = hex2bin_map(); 24 | 25 | fn decode_bin(s: &mut &[u8]) -> usize { 26 | assert!(N <= 16); 27 | let mut i = 0; 28 | let mut v = 0_u16; 29 | while i < N { 30 | v = (v << 1) | (s.get_at(i) as u16); 31 | i += 1; 32 | } 33 | *s = s.advance(N); 34 | v as usize 35 | } 36 | 37 | fn parse_hex2bin(s: &[u8]) -> BitVec { 38 | let mut v = BitVec::new(); 39 | unsafe { v.set_len(s.len() * 4) }; 40 | let mut ptr = v.as_mut_ptr().cast::<[u8; 4]>(); 41 | for &c in s { 42 | unsafe { 43 | *ptr = HEX2BIN_MAP[c as usize]; 44 | ptr = ptr.add(1); 45 | } 46 | } 47 | v 48 | } 49 | 50 | fn sum_versions(s: &mut &[u8]) -> usize { 51 | let version = s.get_at(0) * 4 + s.get_at(1) * 2 + s.get_at(2); 52 | let mut version_sum = version as usize; 53 | let is_literal = s.get_at(3) != 0 && s.get_at(4) == 0 && s.get_at(5) == 0; 54 | *s = s.advance(6); 55 | if is_literal { 56 | while s.get_at(0) != 0 { 57 | *s = s.advance(5); 58 | } 59 | *s = s.advance(5); 60 | } else { 61 | let is_bit_length = s.get_at(0) == 0; 62 | *s = s.advance(1); 63 | if is_bit_length { 64 | let n = decode_bin::<15>(s); 65 | let mut t = &s[..n]; 66 | while t.len() > 6 { 67 | version_sum += sum_versions(&mut t); 68 | } 69 | *s = s.advance(n); 70 | } else { 71 | let n = decode_bin::<11>(s); 72 | for _ in 0..n { 73 | version_sum += sum_versions(s); 74 | } 75 | } 76 | } 77 | version_sum 78 | } 79 | 80 | #[inline] 81 | fn reduce(type_id: u8, acc: usize, v: usize) -> usize { 82 | match type_id { 83 | 0 => acc + v, 84 | 1 => acc * v, 85 | 2 => acc.min(v), 86 | 3 => acc.max(v), 87 | 5 => (acc > v) as _, 88 | 6 => (acc < v) as _, 89 | 7 => (acc == v) as _, 90 | _ => unsafe { core::hint::unreachable_unchecked() }, 91 | } 92 | } 93 | 94 | fn eval_packet(s: &mut &[u8]) -> usize { 95 | let type_id = s.get_at(3) * 4 | s.get_at(4) * 2 | s.get_at(5); 96 | *s = s.advance(6); 97 | let mut v = 0_usize; 98 | if type_id == 4 { 99 | loop { 100 | let is_end = s.get_at(0) == 0; 101 | *s = s.advance(1); 102 | v = (v << 4) | decode_bin::<4>(s); 103 | if is_end { 104 | break; 105 | } 106 | } 107 | } else { 108 | let is_bit_length = s.get_at(0) == 0; 109 | *s = s.advance(1); 110 | if is_bit_length { 111 | let n = decode_bin::<15>(s); 112 | let mut t = &s[..n]; 113 | v = eval_packet(&mut t); 114 | while t.len() > 6 { 115 | v = reduce(type_id, v, eval_packet(&mut t)); 116 | } 117 | *s = s.advance(n); 118 | } else { 119 | let n = decode_bin::<11>(s); 120 | v = eval_packet(s); 121 | for _ in 1..n { 122 | v = reduce(type_id, v, eval_packet(s)); 123 | } 124 | } 125 | } 126 | v 127 | } 128 | 129 | pub fn input() -> &'static [u8] { 130 | include_bytes!("input.txt") 131 | } 132 | 133 | pub fn part1(s: &[u8]) -> usize { 134 | sum_versions(&mut parse_hex2bin(s).as_slice()) 135 | } 136 | 137 | pub fn part2(s: &[u8]) -> usize { 138 | eval_packet(&mut parse_hex2bin(s).as_slice()) 139 | } 140 | 141 | #[test] 142 | fn test_day16_part1() { 143 | assert_eq!(part1(input()), 889); 144 | } 145 | 146 | #[test] 147 | fn test_day16_part2() { 148 | assert_eq!(part2(input()), 739303923668); 149 | } 150 | -------------------------------------------------------------------------------- /src/day17/input.txt: -------------------------------------------------------------------------------- 1 | target area: x=209..238, y=-86..-59 2 | -------------------------------------------------------------------------------- /src/day17/mod.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Range; 2 | 3 | use num_integer::div_ceil; 4 | 5 | use crate::utils::*; 6 | 7 | type T = i32; 8 | 9 | fn parse(mut s: &[u8]) -> ((T, T), (T, T)) { 10 | s = s.advance(15); 11 | let x0 = parse_int_fast::(&mut s); 12 | s = s.advance(1); 13 | let x1 = parse_int_fast::(&mut s); 14 | s = s.advance(3); 15 | assert_eq!(s.get_at(0), b'-'); 16 | s = s.advance(1); 17 | let y0 = parse_int_fast::(&mut s); 18 | s = s.advance(1); 19 | assert_eq!(s.get_at(0), b'-'); 20 | s = s.advance(1); 21 | let y1 = parse_int_fast::(&mut s); 22 | ((x0, x1), (-y0, -y1)) 23 | } 24 | 25 | pub fn input() -> &'static [u8] { 26 | include_bytes!("input.txt") 27 | } 28 | 29 | pub fn part1(s: &[u8]) -> T { 30 | let ((_xmin, _xmax), (ymin, _ymax)) = parse(s); 31 | (ymin * (ymin + 1)) / 2 32 | } 33 | 34 | #[inline] 35 | fn dio(x: T) -> f64 { 36 | // xv * (xv + 1) / 2 = x => xv = (-1 + sqrt(1 + 8x)) / 2 37 | (-1. + (1. + 8. * x as f64).sqrt()) / 2. 38 | } 39 | 40 | #[inline] 41 | fn v_range(min: T, max: T, n: T, lb: T) -> Range { 42 | let vmin = div_ceil(min, n).max(lb); 43 | let mut vmax = vmin; 44 | let mut bound = vmax * n; 45 | while bound <= max { 46 | vmax += 1; 47 | bound += n; 48 | } 49 | vmin..vmax 50 | } 51 | 52 | pub fn part2(s: &[u8]) -> usize { 53 | let ((xmin, xmax), (ymin, ymax)) = parse(s); 54 | 55 | // range of vx where eventually vx = 0 and we hit the box on x coordinate 56 | let (vx_stop_min, vx_stop_max) = (dio(xmin).ceil() as T, dio(xmax).floor() as T); 57 | 58 | let mut n_paths: T = 0; 59 | 60 | // first, handle the 'stop' range of vx where the trajectory eventually hits vx = 0 61 | for vx in vx_stop_min..=vx_stop_max { 62 | // fast-forward to vx=0 point first 63 | let mut n = vx; 64 | // now backtrack within the box 65 | let mut x = (vx * (vx + 1)) / 2; 66 | // println!("vx={}, n={}, x={}", vx, n, x); 67 | let mut vx_t = 0; 68 | loop { 69 | if x - vx_t - 1 < xmin { 70 | break; 71 | } 72 | vx_t += 1; 73 | x -= vx_t; 74 | n -= 1; 75 | } 76 | let mut acc = (n * (n - 1)) / 2; 77 | let mut vymax_prev = T::MIN; 78 | // for each n forward, search for all valid vy 79 | 'outer: for n in n.. { 80 | let vyr = v_range(ymin + acc, ymax + acc, n, T::MIN); 81 | if vyr.is_empty() { 82 | acc += n; 83 | continue; 84 | } 85 | let (vymin, vymax) = (vyr.start, vyr.end); 86 | let dvy = vymax - vymin; 87 | n_paths += dvy; 88 | if vymin < vymax_prev { 89 | n_paths -= vymax_prev - vymin; 90 | } 91 | if vymax > -ymin - 1 { 92 | break 'outer; 93 | } 94 | vymax_prev = vymax; 95 | acc += n; 96 | } 97 | } 98 | 99 | // handle the 'continuous' range 100 | let mut acc = 0; 101 | let (mut vxmin_prev, mut vymax_prev) = (T::MAX, T::MIN); 102 | for n in 1.. { 103 | // search for valid vx 104 | let vxr = v_range(xmin + acc, xmax + acc, n, (vx_stop_max + 1).max(n)); 105 | if vxr.is_empty() { 106 | break; 107 | } 108 | let (vxmin, vxmax) = (vxr.start, vxr.end); 109 | let dvx = vxmax - vxmin; 110 | // search for valid vy 111 | let vyr = v_range(ymin + acc, ymax + acc, n, T::MIN); 112 | if vyr.is_empty() { 113 | continue; 114 | } 115 | let (vymin, vymax) = (vyr.start, vyr.end); 116 | let dvy = vymax - vymin; 117 | // count the number of trajectories and account for overlaps 118 | n_paths += dvx * dvy; 119 | if vxmax > vxmin_prev && vymin < vymax_prev { 120 | n_paths -= (vxmax - vxmin_prev) * (vymax_prev - vymin); 121 | } 122 | vxmin_prev = vxmin; 123 | vymax_prev = vymax; 124 | acc += n; 125 | } 126 | 127 | n_paths as _ 128 | } 129 | 130 | #[test] 131 | fn test_day17_part1() { 132 | assert_eq!(part1(input()), 3655); 133 | } 134 | 135 | #[test] 136 | fn test_day17_part2() { 137 | assert_eq!(part2(input()), 1447); 138 | } 139 | -------------------------------------------------------------------------------- /src/day18/input.txt: -------------------------------------------------------------------------------- 1 | [9,[[8,3],[6,9]]] 2 | [[[0,[5,0]],[9,[1,0]]],[[8,0],[6,[3,3]]]] 3 | [[5,[[4,1],[3,3]]],[[7,5],[[1,5],9]]] 4 | [8,3] 5 | [[[[0,5],3],2],[2,[6,0]]] 6 | [[[0,8],[7,5]],6] 7 | [[8,[9,[7,6]]],2] 8 | [[[[2,3],9],[0,0]],[8,[[8,2],6]]] 9 | [[[[8,7],[4,9]],[[0,1],9]],[[[2,1],[9,5]],2]] 10 | [[5,[6,0]],[[1,[6,5]],[[3,4],2]]] 11 | [[6,[5,6]],[6,5]] 12 | [[[[6,0],0],3],[[[7,8],6],[[2,5],[8,8]]]] 13 | [[[[1,4],[3,4]],[[1,3],7]],6] 14 | [[[[9,7],[3,9]],2],9] 15 | [[8,[1,7]],[[[9,4],3],5]] 16 | [[[[9,9],[6,1]],5],[[2,6],[7,0]]] 17 | [4,[[0,5],2]] 18 | [[[1,8],7],[[5,[7,1]],[[2,6],8]]] 19 | [[[3,[8,5]],9],[[6,1],[[8,1],3]]] 20 | [[9,[[6,3],5]],[[[5,3],9],[[5,0],7]]] 21 | [[[[3,4],[2,3]],[6,[2,1]]],[2,[7,1]]] 22 | [[1,[9,[4,8]]],[4,9]] 23 | [[0,[[5,0],0]],[[[6,6],[1,4]],8]] 24 | [[[[0,9],[1,4]],[[3,4],3]],[1,[[7,7],[3,5]]]] 25 | [8,[4,[[2,5],8]]] 26 | [[7,6],[1,9]] 27 | [[[1,[6,0]],1],[[[5,8],4],1]] 28 | [[[6,[1,1]],[[3,0],[9,7]]],[[[2,3],[0,4]],[4,5]]] 29 | [[3,9],[4,[6,1]]] 30 | [[[5,2],[[4,1],2]],[[9,[9,2]],[5,[6,6]]]] 31 | [[[2,5],[3,[5,5]]],[[8,[6,1]],[[1,3],[1,4]]]] 32 | [[5,[3,2]],[[1,0],[[1,6],[0,3]]]] 33 | [[[3,[3,0]],[[4,8],9]],[[[6,0],3],[1,[5,2]]]] 34 | [[6,[8,1]],1] 35 | [[[[8,6],4],[[2,0],[1,3]]],[8,7]] 36 | [[[1,7],1],[[2,5],[[5,1],6]]] 37 | [8,9] 38 | [[6,[6,7]],[[[1,8],6],[6,[5,4]]]] 39 | [[[[9,2],[2,4]],[[4,9],[5,0]]],[[[0,4],9],[[0,7],[6,2]]]] 40 | [[0,4],0] 41 | [[[[6,8],[8,9]],0],[[0,3],[[7,0],7]]] 42 | [[6,[[9,6],6]],[[7,[5,4]],[7,6]]] 43 | [[[7,7],[[6,8],[7,3]]],[[7,[9,8]],[[2,2],1]]] 44 | [[[8,5],[[8,2],[7,4]]],[[9,[3,3]],[[5,1],[1,9]]]] 45 | [2,6] 46 | [[[3,[4,4]],[[5,4],[0,0]]],[[1,6],[1,[1,0]]]] 47 | [[[8,9],[[0,1],[3,0]]],[[[1,8],1],[6,6]]] 48 | [[[[9,2],[1,5]],7],[[8,2],3]] 49 | [[[[0,5],1],[[8,1],[2,8]]],[[3,[8,4]],[[4,2],[0,9]]]] 50 | [[[[2,8],[4,2]],9],[3,[3,[8,0]]]] 51 | [[[2,[3,8]],[[6,8],1]],[[5,4],0]] 52 | [[3,[7,9]],[[3,[8,6]],[2,1]]] 53 | [[[3,6],[[4,4],[1,7]]],[4,0]] 54 | [[7,[0,[7,6]]],[[[1,8],4],[4,[7,8]]]] 55 | [[[[9,4],[2,9]],[[1,8],[1,4]]],[3,[0,8]]] 56 | [[[7,2],[[0,7],[8,8]]],[3,[[5,9],3]]] 57 | [[[[9,9],[3,1]],2],[[[2,3],1],[[8,9],2]]] 58 | [[[[9,6],7],2],[[[0,8],7],[[6,9],2]]] 59 | [[[[0,0],[7,7]],0],[[3,9],[0,[9,5]]]] 60 | [[[1,[3,0]],[8,9]],[2,[[5,7],5]]] 61 | [[[6,[7,2]],[9,0]],[6,[1,[2,7]]]] 62 | [[[7,[0,2]],[1,[8,6]]],[[[8,9],5],[[1,5],[9,3]]]] 63 | [[[[6,1],[2,0]],[6,8]],[8,[8,4]]] 64 | [[[7,[2,8]],1],[[[9,4],[7,9]],[[7,6],[5,7]]]] 65 | [[[8,3],[[4,1],9]],[[[6,7],1],[6,7]]] 66 | [[[[2,2],4],[[0,3],[9,7]]],[[[9,0],7],0]] 67 | [[[[8,7],[3,7]],[[1,9],0]],[[[4,8],7],[[2,0],1]]] 68 | [[2,9],[8,1]] 69 | [[[[6,4],[8,0]],[2,2]],[9,[5,[9,4]]]] 70 | [[[[4,4],[7,3]],[3,0]],[[[4,5],5],[1,3]]] 71 | [[[[2,0],5],[7,[2,1]]],[1,[[3,5],[9,5]]]] 72 | [1,[[4,[3,6]],[[1,1],[2,3]]]] 73 | [6,[3,[[1,6],5]]] 74 | [[[9,5],[7,[8,3]]],[[9,8],[[6,6],5]]] 75 | [[[[8,8],3],[7,[3,3]]],[5,[9,[2,5]]]] 76 | [9,[[[1,0],6],[3,[3,3]]]] 77 | [[[[4,0],[6,5]],5],[7,[8,1]]] 78 | [7,[[[3,8],4],[[2,8],8]]] 79 | [[[[1,0],[4,2]],[0,1]],[5,[[9,9],[6,9]]]] 80 | [[[[1,8],[9,8]],[3,[4,2]]],0] 81 | [[[[1,2],4],7],[[2,6],[7,3]]] 82 | [3,[[0,[0,1]],[[3,0],[2,0]]]] 83 | [[[8,[5,1]],[[4,8],2]],[3,7]] 84 | [[9,[[1,3],[1,7]]],[[9,2],7]] 85 | [[[[5,1],[2,6]],[[6,8],[7,9]]],[[[2,4],[2,0]],[6,0]]] 86 | [[8,[4,[7,3]]],[6,[7,[2,5]]]] 87 | [[8,[1,8]],4] 88 | [[[2,[5,6]],[[3,0],[2,6]]],[[[2,7],6],[[6,3],0]]] 89 | [[7,[8,6]],[[[0,0],4],[7,9]]] 90 | [[3,[[2,7],1]],[[5,[3,4]],1]] 91 | [[4,[[7,7],5]],[[[9,4],[6,0]],6]] 92 | [[[8,5],[[1,0],[0,9]]],[[4,[3,2]],[1,3]]] 93 | [1,[6,1]] 94 | [[8,[9,[3,9]]],[[0,6],[0,[6,6]]]] 95 | [8,[[[8,9],[5,1]],[[7,9],5]]] 96 | [[[[4,8],0],[1,3]],[5,[1,0]]] 97 | [[4,1],[[[7,3],4],[[0,4],[5,8]]]] 98 | [[[[6,9],3],7],[[[5,3],[0,1]],[[7,7],[4,5]]]] 99 | [[6,[8,5]],[[[7,8],[5,7]],[3,[7,8]]]] 100 | [[[[1,3],2],[8,[9,5]]],[[3,[9,2]],[[9,0],[4,8]]]] 101 | -------------------------------------------------------------------------------- /src/day20/input.txt: -------------------------------------------------------------------------------- 1 | #....##..##...####...##.#..####..#.#.#.#..##....##....#.....#.##....##..###.#..####.#..#.###...##....##...#.#####..#.....#.#####.##....##..#.#####.....#.....###..#.#.###...###..#..#.#.#####....#.#..#..##..#.####.###.#.#...##.##.#.###...#####......#.........##.#.#####.##.##........#..#.##.####.#...#..#####.####.#.##.####.#.#.##.#..#..#.#....#.###.#.###.#......#..#...#.#..#..###..#....####...##....##.#..###...##.##.####..#..#..#..#.#...###.#.##.##.#..####.#.#..#....####......##.###.####..###.....##..##..##... 2 | 3 | .#...##.#...#.##.#.....#..###...#.##.##...##.##.##.###...##.#.#...#..##..###.....#..##...#....#.#### 4 | ##.#####..#.#...##.#..##..#.#.######...#.##.#...#...##.#...#.#.#......#.#####.....#.######.....#...# 5 | ....#..###..#.###.####....##.#...#...##.###.###...#...####.#.......#########.####.#.#..###.##..###.. 6 | .#..#.##.###...#.##...#.....#.#.#...##....##.......####...#...####.####.#...#..#..##..###.#..#.#.... 7 | ..#.###..##.......#.##...##..#...####.####.##..#####.#..#.####..#....#..##..##....##.##...#.......#. 8 | #.#.#..#.####..###..#..#..##.#...#.#..###.##..#.##.###.##..#.......##.###.#..###.####..#####.....#.. 9 | #.#...#..#.##..#.###...###.#....#...#..###.#.#..####.#..#.#.#.#..###.####.......#.#..#.####...###..# 10 | ###.#.##.#..#.##.#.#....###...##..#.##.#.##..####...##.#.#....###.#.###.##.#.#####..#....#......##.. 11 | .#.#..##.#.###..#..#.####.######.########....##.#.#.###.#..#...#.##.##..#.#.##.####.####.#.###...##. 12 | .#..#...#####..##..##..#.#.##.#######...####...#..#.###..#.#####..#..#...#..###...#.##....#.###..#.. 13 | ##...####.....###.#....##..#...#...##..#.#..##.####..#.##.#..##.##.#...##.##..##.##.#.##.##.####.#.# 14 | #...#.#.#..#......#.#.##.#.##.#......#.....#####..#.###.##.##.###..#.#.###..#####...#.#....###.#.#.. 15 | ..##.##.#.#.#..#######.##..#...##.....#..#.##.#...#..#.....#.#.##..##.#..#.##.#..#.#..##.#.##.###### 16 | #..##...##...###.###..##.#.....#..#.#.#.###..#......#...##.#...####.##..#...##..#...####.##....##.#. 17 | ##.#.###.###.#.#.....#.#.##..###.#####.#.#####.###.##.##.##.##.....#...####.....#.#....#.###.#.#...# 18 | .#.#..#.###.##.###.#......#..#..##.##..#.#..#......#.##.#..#......##.##.##...#.##.....#...#.##..#..# 19 | ###....####.###.#.#.#...#.###.#####.##.###.#...#.#.#..#.##..#..##.....####.#.##..##..#.###..###..#.. 20 | ##.##..####...#......#..##..#..#.#.......###..####..#...##..####..#####....##.#..#..###...#####..... 21 | ####..##.#...#.####..#####..#..#..###.#.##.#.###..###.#....#..#.#.#.#..##.#...#..#.####....#......#. 22 | #.####.##.##.####.#..#..#...##.##.##....#########....#.#.###.#.#.#.......#..#####.##...#..#....#.#.# 23 | ..##.###..####.#.###.#.#...##..#.###..####.##..#.......##.##..#..#####.########..####.#..###.#..#### 24 | #..##...###....##.#...#.#..###....##..####..#...##.####.###..##......####..#..#...#..#....#.##.#.#.# 25 | #.##..#......##....##.#.#..##..#.#...#.##..#.#.#.#####.#.##...###.#.#.####..###.###.#.....#....#..## 26 | .####...#...####...##..###...##..####.####...#.#.#.....#####.##..#.#..#..#..#.....#.#..##......#.#.# 27 | .....#....#..#.#.####.#.#..#..#.##...#....#####.###.###.####.##..####.#..#####..#...###.#..#.#.###.# 28 | #.###..#....####.##..#.....#...#.#.##.###..#.....#..#.#.#####.##.####.#.###..###.....#.##.##.#.##..# 29 | ..##..#..#####..#...#.#.#..###...#.#.####.###....#.##.#...#.##.##...##.#.####...#..###.#..#.#.##..#. 30 | .#.##...###...####.#..##.#.#####.#....#..#..#.##..###..#.#..##.#..#...####.#.####.#..##..#.#####...# 31 | #.####...##...#.##.####.###..#...####.###...#..#.#..#.####.##...#.#....#.#..#.#.###.#.###.###.###... 32 | .#.#.....#....###.#..#.#.##.##....#.#..##....###..###...######.##..###..#####...#..##..###.#.#.###.# 33 | #..#.#.#...##..##.#....#.##.##..##.###.###..###.....#...##..#..#######..##.#.##.##..#.#.#.#.#.#.#### 34 | .#.#.....#...#...#.####.....##...#.##..###.####.#.#..####.#####...#..#.....##..#..##...##..######### 35 | ..##.#.....#.#.###.#.#..##..#.#.#..#..###.#.#..####..##.####..#...##.#.#.###..##...#..##.##...#..#.# 36 | .######.####...#.#..#.#.###.##...#.##.#.##.#..##....#..#.#..#.#.##...#.#....##..##...#.#.##.#.#.#.#. 37 | ..##...###.#.#.#......#.#.###.##...#.###.#.##.#....####.###..#.##...#..#..###.#.####..#....####.##.# 38 | ##.#.###.#.##......##.####.#..###...#..#..#.#..##.#.#..#.###..#..##..#.#...##..##.##.###.##.....#### 39 | #...#..#.######.#.#...#.##.##....###.##..#..###..##.###.....##.#########..##..#....#...#.##.#....##. 40 | #.######.#.##.###...##..##...#..##...####.#.#.....##.#.##.####..###.##..##.#.####...###.#.#.####.#.# 41 | #####..####....#.##..##...#..#...#####...#.#..#...#.#####.#.....####..#..####.######.##.#....###.#.# 42 | ##.#.#..####.#.......#...##..#.#..#..#..##..####.####...#......#.#....###.#.#.....##..#.#.#..#...#.# 43 | ......###....#.......#.#.#...##...###.#...##..##..#..##...#.#.##.##.###...##....#####...#####.#..##. 44 | .##..##.##..#.##....#..#.###..#.###..#.#.##..###....##.###..#.#.##.#...#.##.#.#.###...#.#...#...#..# 45 | ..#.....#.#.#...###.#.##.....###...##.####...##.#.#.#..##.#..#....#.##.##.##..#.#.##..###.#..#####.. 46 | #...#..#.......##..###.#...##..####.###.....###..####.....#..#.####...#..#.#......##..##.##..##.#..# 47 | .#..#...#########.....###...##..##..##.##.###......##.####.####.....#..##.#.###.##...#.#....#.###### 48 | #..#..#....###.##.#...##.#..#...#.##...#.###...#..#####.#.##.#....####..###.#.#.#...##..##.....#..#. 49 | ####.#..#.........######..#...#.##.###.###....#...#.#.#.##..#.####....#####.......##....#..#....#### 50 | #....##.#.###.#....####.##...#####......#...#..#.#..####.##..###########..##.##....#...#..####..##.. 51 | #.#..#.#..#.####......##..#.#.#.#......#.##.####.#..###.###..#.#...##.#.#..#.#.##..#....###.#.###.## 52 | ..#..##...#####.##.###########..###.##.##...#.........###..#.##.#.###....#..####..###.#....#...##### 53 | ...#....#.....###.....##.#.###..#..#####..#.....###.....#..##..#...#.##.###....#.#####.....#.###.### 54 | ##.##..#.#.....##.#..#####.####...#.#.#....####.#.###.###.##......#.##...#...#...#.#.#.####..#.####. 55 | ##..#...###.#.#..##..###.#.#...##.#.#.....#.#.####.##.##.#..##....#.##.#####.#...#.#.##....###.#.#.# 56 | ###.....#.#..#####.#..###...####....#.#..#..#.##.#.#...##..#.#.#..###....#.#.....##.#.#.######.##.## 57 | #####..#..#.#.##..#..##.##..##.####.#.....#....#########.#######.##.###.#..#.#....#....#.##.######.# 58 | #......####.#...##.#...###..##.######..##..#...####....#...###.##..#.###..##########..#.##.##.#.#..# 59 | ####...##..#..#.....#..#...##..##.####........#..##...#..#...#####.#.#.......####..##.##.###.##.#.## 60 | .##..##......##.##....##..#..#.#.#.....#####.#...####..######...##.##..#.#..#.##.#.##.##.#####.##... 61 | ..#..#####....####.##.###..#...#..##.####.##.###...##.....#.####...#.#..##.#..##.###.##....#.#.#..#. 62 | #.#.#.#.#..#...#.####...##.#..#..###.####..#..##..#.......#..#.##.#...####.####..#.##..##..#.###.### 63 | ..#...#...####...#..###.###.....#....#.#.##.####..#....###...###..#.......###....#.#.#.#...#..###.#. 64 | .###...#############.#####.##...#.#.#.#.#..##.....####.###.#...#.####..#....#...#.#...###.#.#.##.#.. 65 | ..#.#....#..#....#####.####..##..#..#.#..####.###..#.#.##.########....#.#....#########....#.#.##.#.. 66 | .#...#.###.#.#.#####.###.##.#####...##.....##...####.##.#####....###...#.#.#.#####.###.###.###...#.. 67 | #.#####...#.##.#.##...#....###.#..####.##..#..#..###.#.###..#.#.....#..#.#.#.####.#.......#.###....# 68 | .######.#.##....###.###.####...#...#######..#.#.#...###...#........#.###.#####..##..###.####...#.### 69 | #...##..##...###.#.#.##.##.#....#....#.#.##..###..##.#.#..#..#...#...######.#..###..#.#..#.#..#....# 70 | ...####..##.#..###.##.#.#.##.#....#.....#...#####....#..###....#.#.#....##.########..##..##.#.##.#.# 71 | .####.######..####.###...#####.##.####..#..##..##.#.#.#.#.#.###...##......#..#####.#..##.#.####....# 72 | ##.#.#.##....#..#.##.#...######.###..#####.....#..#.#..#.#..#..##.#.#.#.##.#..#..##.##.#......#####. 73 | .###......##.#..##.#.....#..##..##....#....########.#.##.####..##..#########...##..#.#..#.##....#.## 74 | .###.#.####.#########....#....#.###...###..#########..#..########.#..###.###.#..#..#.##.#....#..#.## 75 | ..#..######...##...#.#...#..#...#.....##...#.#.#...##..#.##.##.#.##..#.......##.....##.#......#.###. 76 | .#..####...#.##.#.....###..##.#.##.....#.#.###..#...#.#...###.#...##.##....#.###.#.####.#..#.....#.# 77 | ##.#..#.##.#.#.###......##...#.##.#.#.#.#...####..##....#.##.....###..#.###.#...###.##.#.....#..#.#. 78 | ###.##...###.###.###.....#####.#####.#.#..#..##...##..#.#....##..#.#.####.#.#.###.#..##.#.###..##..# 79 | .##.#.####..#......#.#..###..######.#######.###..#####.##.#....##.###.##.##.##.#.####.#..##..#.###.# 80 | .#..#.....###.###.#.##..#.#.#.##....##...#..#..#.##...###.#.###..###.####.#..#..#########..##..##.#. 81 | ....#...###.#.#....##..#..###..#.#.####.###.######..#.##.#...#..#.##...#...##.###..............##.## 82 | .##..####..##....#.###......#.##.#.####..#....#..###..#.###..####..##.#.#.....###.#..#.#..#.#.....## 83 | ###.####....##..##.#..#######.#...#..#.##..#########.......#..#####..##.##..#..#..#..#..##...#..#.## 84 | ##.##.#..#.##..#..###.#..#.####..#.#.#....#.#..####.#...#..####.#####....###.##....#..##..#..#.###.. 85 | .....#.#..###..##....###.......#.######....##.#..##....#..###...#..##.##.#.....#..###...##......###. 86 | ..#.#...#.....#...#....##.#.##.#.#.#.###.#..#....###.....#.#......#....##..##.##.####.##.#####.#...# 87 | ..##..#.#..###..#..##..##...#..##..#...###..##.#...#..#...##.###.##.##.#.##...#.##......###.#...##.. 88 | .####..###.#..#.###...#.##........#.##.#..#.#..###.##..##.#....#.#.#..##...#..#.####....#.....##...# 89 | #.......###....##..##.#.#..#.#..##.##...#.#.#.#.#.#..###.#...#..###.########....#.#######..#.##..### 90 | #..#.####..#.##.#...####....##.######.####...####..#.####...........#.##..###..#....#.##..#.#...###. 91 | ..####....#.#.##.#.###...##..#.###..#......####.#.##.##.#..#.#..###.##...#..#.##.###..###.###.###..# 92 | ..#....#.###..#.#...#.####.########.####..#.#.#....#.#.##.##...####.#.##..##.#.#.##.##.#..#..#..##.# 93 | .##.#...###.###..#..###.#..####.#...#.#..##.##.###...#.###.#..##.#.##......#..##..##.#.#.#.#.##.###. 94 | #######.##.#####.#..#....##..#.###..#..##.######.....##.#....###..###.#.#...##.####.#.#....#..#..### 95 | .##.###.####...##.#......#..#..#####...###.###..##..####.#....#...#..###..######..##.##.####....##.. 96 | .#.....#...##...##.#.######..####.....#.#.#####....#..##....#..#...###.#.##.#.#......#.######.#.#... 97 | #####.#....#..#.#.##...##..#.#...#.#.#.##.##.#.#####.#..#.#...######.........###....#.##.###.#.#.#.# 98 | ....#...##.#.###..#######.##..####.###....#.####...####.#..####.#.####...#.#....#.##...#.##.##..##.. 99 | #..#.#####.#####..###.#.....#.#.#.##......#.#..###......#...#.####.#..##.#.###...#.#.......###.####. 100 | ##..###...#..........#..#.###.##.##..##.#...##..#.#...##.#..#.##...##..####.######.#..#.####.#.##### 101 | ..######..#...##.#.#....#.##.#.#.#.#..#..###..###..##..##..#.....#.#.###.##.#.#.#.###..##....#..#### 102 | #.#.####.#.....##..#..#.#.#.##..#.#.#######.#....###.##...##.##.#.#..##..#......######.#....#....#.. 103 | -------------------------------------------------------------------------------- /src/day20/mod.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | use core_simd::*; 4 | 5 | use crate::utils::*; 6 | 7 | const W: usize = 256; // max board width 8 | type T = u64; 9 | const SHIFT: usize = 6; 10 | const BITS: usize = mem::size_of::() << 3; 11 | const MASK: usize = BITS - 1; 12 | const K: usize = 256 / BITS; 13 | 14 | type Bitmap = [u8; 512]; 15 | 16 | fn parse_bitmap(s: &mut &[u8]) -> Bitmap { 17 | let mut bitmap = [0; 512]; 18 | for i in 0..512 { 19 | bitmap[i] = s.get_at(i) & 1; 20 | } 21 | *s = s.advance(514); 22 | bitmap 23 | } 24 | 25 | const fn range() -> [usize; N] { 26 | let mut out = [0; N]; 27 | let mut i = 0; 28 | while i < N { 29 | out[i] = i; 30 | i += 1; 31 | } 32 | out 33 | } 34 | 35 | #[inline] 36 | const fn transpose8x8(mut x: u64) -> u64 { 37 | // see ch. 7-3 of Hacker's Delight for details 38 | x = x & 0xaa55_aa55_aa55_aa55 39 | | (x & 0x00aa_00aa_00aa_00aa) << 7 40 | | (x >> 7) & 0x00aa_00aa_00aa_00aa; 41 | x = x & 0xcccc_3333_cccc_3333 42 | | (x & 0x0000_cccc_0000_cccc) << 14 43 | | (x >> 14) & 0x0000_cccc_0000_cccc; 44 | x = x & 0xf0f0_f0f0_0f0f_0f0f 45 | | (x & 0x0000_0000_f0f0_f0f0) << 28 46 | | (x >> 28) & 0x0000_0000_f0f0_f0f0; 47 | x 48 | } 49 | 50 | #[inline] 51 | fn transpose8x8x8(x: [u64; 8]) -> [u8; 64] { 52 | const fn swizzle_transpose() -> [usize; 64] { 53 | let mut out = [0; 64]; 54 | let mut i = 0; 55 | while i < 64 { 56 | out[i] = (i & 7) << 3 | (i >> 3); 57 | i += 1; 58 | } 59 | out 60 | } 61 | 62 | const SWIZZLE_TRANSPOSE: [usize; 64] = swizzle_transpose(); 63 | 64 | unsafe { 65 | let x = u8x64::from_array(mem::transmute(x)); 66 | let mut x: [u64; 8] = mem::transmute(simd_swizzle!(x, SWIZZLE_TRANSPOSE)); 67 | for i in 0..8 { 68 | x[i] = transpose8x8(x[i]); 69 | } 70 | mem::transmute(x) 71 | } 72 | } 73 | 74 | #[inline] 75 | const fn get_row(row: &[u64; 4], j: usize, inf: u64) -> [u64; 3] { 76 | let x = match j { 77 | 0 => [inf, row[0], row[1]], 78 | 1 => [row[0], row[1], row[2]], 79 | 2 => [row[1], row[2], row[3]], 80 | _ => [row[2], row[3], inf], 81 | }; 82 | [x[1] << 1 | x[0] >> 63, x[1], x[1] >> 1 | x[2] << 63] 83 | } 84 | 85 | struct PackedBoard { 86 | bits: [[[T; K]; W]; 2], 87 | size: usize, 88 | offset: usize, 89 | inf: T, 90 | } 91 | 92 | impl PackedBoard { 93 | pub fn parse(mut s: &[u8], bitmap: &Bitmap) -> Self { 94 | let mut bits = [[0; K]; W]; 95 | let width = s.memchr(b'\n'); 96 | let offset = (W - width) >> 1; 97 | for i in 0..width { 98 | for j in 0..width { 99 | let v = (s.get_at(j) & 1) as T; 100 | bits[offset + i][(offset + j) >> SHIFT] |= v << ((offset + j) & MASK); 101 | } 102 | s = s.advance(width + 1); 103 | } 104 | let inf = if bitmap[0] == 0 { 0 } else { !0 }; 105 | Self { bits: [bits, [[inf; K]; W]], size: width, offset, inf } 106 | } 107 | 108 | #[allow(unused)] 109 | pub fn print(&self) { 110 | let bits = &self.bits[0]; // even only 111 | println!(); 112 | for i in 0..self.size { 113 | for j in 0..self.size { 114 | let c = bits[self.offset + i][(self.offset + j) >> SHIFT] 115 | & (1 << ((self.offset + j) & MASK)) 116 | != 0; 117 | print!("{}", if c { '#' } else { '.' }); 118 | } 119 | println!(); 120 | } 121 | } 122 | 123 | pub fn count_ones(&self) -> usize { 124 | let bits = &self.bits[0]; // even only 125 | let mut out = 0; 126 | for i in 0..self.size { 127 | for j in 0..K { 128 | out += bits[self.offset + i][j].count_ones(); 129 | } 130 | } 131 | out as _ 132 | } 133 | 134 | pub fn double_step(&mut self, bitmap: &Bitmap) { 135 | self.step::(bitmap); 136 | self.step::(bitmap); 137 | } 138 | 139 | fn step(&mut self, bitmap: &Bitmap) { 140 | self.size += 2; 141 | self.offset -= 1; 142 | 143 | let (even, odd) = self.bits.split_at_mut(1); 144 | let (src, dst) = 145 | if EVEN { (&mut even[0], &mut odd[0]) } else { (&mut odd[0], &mut even[0]) }; 146 | 147 | for j in 0..K { 148 | let mut mid = get_row(&src[self.offset - 1], j, self.inf); 149 | let mut bottom = get_row(&src[self.offset], j, self.inf); 150 | 151 | for i in 0..self.size { 152 | let top = mid; 153 | mid = bottom; 154 | bottom = get_row(&src[self.offset + i + 1], j, self.inf); 155 | 156 | let idx_hi = transpose8x8x8([ 157 | bottom[1], bottom[0], mid[2], mid[1], mid[0], top[2], top[1], top[0], 158 | ]); 159 | let mut idx_lo = bottom[2]; 160 | 161 | let mut out = 0; 162 | for k in 0..BITS { 163 | let hi = (idx_hi[k] as u16) << 1; 164 | let lo = (idx_lo as u16) & 1; 165 | out |= (bitmap[usize::from(hi | lo)] as T) << k; 166 | idx_lo >>= 1; 167 | } 168 | dst[self.offset + i][j] = out; 169 | } 170 | } 171 | } 172 | } 173 | 174 | struct Board { 175 | bits: [[u8; W * W]; 2], // 0 = even, 1 = odd 176 | width: usize, 177 | offset: usize, 178 | steps: usize, 179 | } 180 | 181 | #[allow(unused)] 182 | impl Board { 183 | pub fn parse(mut s: &[u8], bitmap: &Bitmap) -> Self { 184 | let mut bits = [0; W * W]; 185 | let width = s.memchr(b'\n'); 186 | let offset = ((W - width) / 2) * (W + 1); 187 | let mut row = offset; 188 | for _ in 0..width { 189 | let mut pos = row; 190 | for i in 0..width { 191 | bits[pos] = s.get_at(i) & 1; 192 | pos += 1; 193 | } 194 | s = s.advance(width + 1); 195 | row += W; 196 | } 197 | Self { bits: [bits, [bitmap[0]; W * W]], width, offset, steps: 0 } 198 | } 199 | 200 | #[allow(unused)] 201 | pub fn print(&self) { 202 | let bits = &self.bits[self.steps & 1]; 203 | println!(); 204 | for i in 0..self.width { 205 | for j in 0..self.width { 206 | let c = bits[self.offset + i * W + j]; 207 | print!("{}", if c == 1 { '#' } else { '.' }); 208 | } 209 | println!(); 210 | } 211 | } 212 | 213 | pub fn step_naive(&mut self, bitmap: &Bitmap) -> usize { 214 | // note: offsets are from the top left corner to keep them non-negative 215 | const OFFSETS: [usize; 9] = [0, 1, 2, W, W + 1, W + 2, 2 * W, 2 * W + 1, 2 * W + 2]; 216 | 217 | self.width += 2; 218 | self.offset -= W + 1; 219 | 220 | let (even, odd) = self.bits.split_at_mut(1); 221 | let (src, dst) = if self.steps & 1 == 0 { 222 | (&mut even[0], &mut odd[0]) 223 | } else { 224 | (&mut odd[0], &mut even[0]) 225 | }; 226 | self.steps += 1; 227 | 228 | let mut total = 0; 229 | for i in 0..self.width { 230 | let row = self.offset + i * W; 231 | for j in 0..self.width { 232 | let index = range::<9>() 233 | .map(|k| (src[row + j - W - 1 + OFFSETS[k]] as usize) << (8 - k)) 234 | .into_iter() 235 | .sum::(); 236 | let bit = bitmap[index]; 237 | dst[row + j] = bit; 238 | total += bit as usize; 239 | } 240 | } 241 | total 242 | } 243 | } 244 | 245 | pub fn input() -> &'static [u8] { 246 | include_bytes!("input.txt") 247 | } 248 | 249 | pub fn part1(mut s: &[u8]) -> usize { 250 | let bitmap = parse_bitmap(&mut s); 251 | let mut board = PackedBoard::parse(s, &bitmap); 252 | board.double_step(&bitmap); 253 | board.count_ones() 254 | } 255 | 256 | pub fn part2(mut s: &[u8]) -> usize { 257 | let bitmap = parse_bitmap(&mut s); 258 | let mut board = PackedBoard::parse(s, &bitmap); 259 | for _ in 0..25 { 260 | board.double_step(&bitmap); 261 | } 262 | board.count_ones() 263 | } 264 | 265 | #[test] 266 | fn test_day20_part1() { 267 | assert_eq!(part1(input()), 5203); 268 | } 269 | 270 | #[test] 271 | fn test_day20_part2() { 272 | assert_eq!(part2(input()), 18806); 273 | } 274 | -------------------------------------------------------------------------------- /src/day21/input.txt: -------------------------------------------------------------------------------- 1 | Player 1 starting position: 9 2 | Player 2 starting position: 10 3 | -------------------------------------------------------------------------------- /src/day21/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | fn parse(mut s: &[u8]) -> [u16; 2] { 4 | s = s.advance(28); 5 | let p0 = parse_int_fast::<_, 1, 2>(&mut s); 6 | s = s.advance(28); 7 | let p1 = parse_int_fast::<_, 1, 2>(&mut s); 8 | [p0, p1] 9 | } 10 | 11 | pub fn input() -> &'static [u8] { 12 | include_bytes!("input.txt") 13 | } 14 | 15 | pub fn part1(s: &[u8]) -> usize { 16 | const fn deterministic_rolls() -> [[u16; 16]; R] { 17 | let mut table = [[0; 16]; R]; 18 | let mut i = 0; 19 | while i < R { 20 | let mut j = 1; 21 | while j <= 10 { 22 | table[i][j] = j as _; 23 | j += 1; 24 | } 25 | i += 1; 26 | } 27 | let mut i = 0; 28 | while i < 3 * R { 29 | let mut j = 1; 30 | while j <= 10 { 31 | table[i / 3][j] = 1 + (table[i / 3][j] + (i + 1) as u16 - 1) % 10; 32 | j += 1; 33 | } 34 | i += 1; 35 | } 36 | table 37 | } 38 | 39 | const ROLLS: [[u16; 16]; 100] = deterministic_rolls::<100>(); 40 | 41 | let mut pos = parse(s); 42 | let mut score = [0_u16; 2]; 43 | 44 | let mut player = 0; 45 | for roll in &ROLLS { 46 | pos[player] = roll[pos[player] as usize]; 47 | score[player] += pos[player]; 48 | player ^= 1; 49 | } 50 | let mut n = ROLLS.len(); 51 | loop { 52 | for (j, roll) in ROLLS.iter().enumerate() { 53 | pos[player] = roll[pos[player] as usize]; 54 | score[player] += pos[player]; 55 | if score[player] >= 1000 { 56 | return (n + j + 1) * 3 * score[player ^ 1] as usize; 57 | } 58 | player ^= 1; 59 | } 60 | n += ROLLS.len(); 61 | } 62 | } 63 | 64 | pub fn part2(s: &[u8]) -> u64 { 65 | const ROLLS: [(usize, u64); 7] = [(3, 1), (4, 3), (5, 6), (6, 7), (7, 6), (8, 3), (9, 1)]; 66 | let p = parse(s); 67 | // positions/players are rotating, but scores only increase (at least by 1), so we can sweep 68 | // diagonally from (0, 0) all the way to (20, 20) 69 | let mut dp = [[[[[0_u64; 2]; 10]; 10]; 21]; 21]; // [score0][score1][pos0][pos1][player] 70 | dp[0][0][p[0] as usize - 1][p[1] as usize - 1][0] = 1; 71 | let mut wins = [0_u64; 2]; 72 | for sum in 0..21 * 2 { 73 | for score0 in 0..sum + 1 { 74 | let score1 = sum - score0; 75 | if score0 < 21 && score1 < 21 { 76 | for (roll, count) in ROLLS { 77 | for pos0 in 0..10 { 78 | for pos1 in 0..10 { 79 | let new_pos0 = (pos0 + roll) % 10; 80 | let new_score0 = score0 + new_pos0 + 1; 81 | if new_score0 >= 21 { 82 | wins[0] += dp[score0][score1][pos0][pos1][0] * count; 83 | } else { 84 | dp[new_score0][score1][new_pos0][pos1][1] += 85 | dp[score0][score1][pos0][pos1][0] * count; 86 | } 87 | let new_pos1 = (pos1 + roll) % 10; 88 | let new_score1 = score1 + new_pos1 + 1; 89 | if new_score1 >= 21 { 90 | wins[1] += dp[score0][score1][pos0][pos1][1] * count; 91 | } else { 92 | dp[score0][new_score1][pos0][new_pos1][0] += 93 | dp[score0][score1][pos0][pos1][1] * count; 94 | } 95 | } 96 | } 97 | } 98 | } 99 | } 100 | } 101 | wins[0].max(wins[1]) 102 | } 103 | 104 | #[test] 105 | fn test_day21_part1() { 106 | assert_eq!(part1(input()), 707784); 107 | } 108 | 109 | #[test] 110 | fn test_day21_part2() { 111 | assert_eq!(part2(input()), 157595953724471); 112 | } 113 | -------------------------------------------------------------------------------- /src/day22/mod.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Neg; 2 | 3 | use arrayvec::ArrayVec; 4 | 5 | use crate::utils::*; 6 | 7 | const N: usize = 512; 8 | 9 | type Range = [R; 2]; 10 | type Cube = [Range; D]; 11 | 12 | fn parse_cube>(s: &mut &[u8]) -> Cube { 13 | let xmin = parse_int_fast_signed::(s); 14 | *s = s.advance(1); 15 | let xmax = parse_int_fast_signed::(s) + T::from(1); 16 | *s = s.advance(2); 17 | let ymin = parse_int_fast_signed::(s); 18 | *s = s.advance(1); 19 | let ymax = parse_int_fast_signed::(s) + T::from(1); 20 | *s = s.advance(2); 21 | let zmin = parse_int_fast_signed::(s); 22 | *s = s.advance(1); 23 | let zmax = parse_int_fast_signed::(s) + T::from(1); 24 | [[xmin, xmax], [ymin, ymax], [zmin, zmax]] 25 | } 26 | 27 | fn parse_input(mut s: &[u8], full: bool) -> (ArrayVec, N>, ArrayVec) 28 | where 29 | T: Integer + Neg, 30 | { 31 | let mut cubes = ArrayVec::new(); 32 | let mut state = ArrayVec::new(); 33 | while s.len() > 1 { 34 | let is_on = s.get_at(1) == b'n'; 35 | s = s.advance(5 + (!is_on) as usize); 36 | if s.get_at(2).is_ascii_digit() && s.get_at(3).is_ascii_digit() && !full { 37 | break; 38 | }; 39 | let cube = parse_cube::(&mut s); 40 | cubes.push(cube); 41 | state.push(is_on); 42 | } 43 | (cubes, state) 44 | } 45 | 46 | #[inline] 47 | fn volume(x: &Cube) -> T { 48 | (0..D).map(|i| x[i][1] - x[i][0]).product::() 49 | } 50 | 51 | #[inline] 52 | fn overlaps(a: &Cube, b: &Cube) -> bool { 53 | (0..D).all(|i| a[i][0].max(b[i][0]) < a[i][1].min(b[i][1])) 54 | } 55 | 56 | #[inline] 57 | fn intersect_unchecked(a: &Cube, b: &Cube) -> Cube { 58 | let mut out = [[T::default(); 2]; D]; 59 | for i in 0..D { 60 | out[i] = [a[i][0].max(b[i][0]), a[i][1].min(b[i][1])]; 61 | } 62 | out 63 | } 64 | 65 | fn find_total_volume( 66 | regions: &[Cube], is_on: &[bool], 67 | ) -> T 68 | where 69 | T: Integer + Neg, 70 | { 71 | // idea in using cliques taken from: 10.1109/ICDM.2019.00160 72 | 73 | let n = regions.len(); 74 | 75 | let mut queue = Vec::<(Cube, ArrayVec, bool)>::with_capacity(n * L); 76 | let mut neighbors = [[false; N]; N]; // for bigger problems, can use btreeset/hashset 77 | 78 | // build overlap matrix (the upper-right triangular part of it) and initialize the queue 79 | for i in 0..n - 1 { 80 | let a = ®ions[i]; 81 | let mut neighbors_list = ArrayVec::new(); 82 | for j in i + 1..n { 83 | let b = ®ions[j]; 84 | if overlaps(a, b) { 85 | neighbors[i][j] = true; 86 | neighbors_list.push(j); 87 | } 88 | } 89 | if is_on[i] { 90 | // this ^ is where the algorithm differs from the classic clique 91 | // enumeration algorithm; because we don't push cliques that start 92 | // with an 'off' node onto the queue, they will never be processed, 93 | // which essentially extends inclusion-exclusion principle to 94 | // support set subtraction and not just the union when it comes 95 | // to computing the total set cardinality. 96 | queue.push((regions[i], neighbors_list, true)); 97 | } 98 | } 99 | if is_on[n - 1] { 100 | queue.push((regions[n - 1], ArrayVec::new(), true)); 101 | } 102 | 103 | let mut total_volume = T::default(); 104 | for (region, common_neighbors, is_even) in queue.drain(..) { 105 | total_volume += enumerate_cliques_recursive::( 106 | ®ion, 107 | &common_neighbors, 108 | &neighbors, 109 | regions, 110 | is_even, 111 | ); 112 | } 113 | total_volume 114 | 115 | /* 116 | // this is a modified/sequential version of the networkx.clique.find_clique() algorithm 117 | while let Some((region, common_neighbors, is_even)) = queue.pop() { 118 | for (i, &u) in common_neighbors.iter().enumerate() { 119 | let region = intersect_unchecked(®ion, ®ions[u]); 120 | let is_even = !is_even; 121 | let common_neighbors = 122 | common_neighbors[i + 1..].iter().copied().filter(|&j| neighbors[u][j]).collect(); 123 | queue.push((region, common_neighbors, is_even)); 124 | } 125 | // we know that the first element is always 'on' because we have filtered it out 126 | // at the queue creation stage, so the normal inclusion/exclusion principle applies 127 | let v = volume(®ion); 128 | total_volume += if is_even { v } else { -v }; 129 | } 130 | total_volume 131 | */ 132 | } 133 | 134 | fn enumerate_cliques_recursive( 135 | region: &Cube, common_neighbors: &[usize], neighbors: &[[bool; N]; N], 136 | regions: &[Cube], is_even: bool, 137 | ) -> T 138 | where 139 | T: Integer + Neg, 140 | { 141 | // this is a modified/recursive version of the networkx.clique.find_clique() algorithm 142 | let mut total_volume = volume(region); 143 | // we know that the first element is always 'on' because we have filtered it out 144 | // at the queue creation stage, so the normal inclusion/exclusion principle applies 145 | if !is_even { 146 | total_volume = -total_volume; 147 | } 148 | if let Some(last) = common_neighbors.last().copied() { 149 | let mut cn = ArrayVec::::new(); 150 | let n = common_neighbors.len(); 151 | for i in 0..n - 1 { 152 | let u = common_neighbors[i]; 153 | cn.clear(); 154 | for j in i + 1..n { 155 | let v = common_neighbors[j]; 156 | if neighbors[u][v] { 157 | cn.push(v); 158 | } 159 | } 160 | total_volume += enumerate_cliques_recursive::( 161 | &intersect_unchecked(region, ®ions[u]), 162 | &cn, 163 | neighbors, 164 | regions, 165 | !is_even, 166 | ); 167 | } 168 | let mut v_last = volume(&intersect_unchecked(region, ®ions[last])); 169 | if is_even { 170 | v_last = -v_last; 171 | } 172 | total_volume += v_last; 173 | } 174 | total_volume 175 | } 176 | 177 | pub fn input() -> &'static [u8] { 178 | include_bytes!("input.txt") 179 | } 180 | 181 | pub fn part1(s: &[u8]) -> i64 { 182 | let (cubes, state) = parse_input(s, false); 183 | find_total_volume::<_, 3, 32, 16>(&cubes, &state) 184 | } 185 | 186 | pub fn part2(s: &[u8]) -> i64 { 187 | let (cubes, state) = parse_input(s, true); 188 | find_total_volume::<_, 3, 512, 32>(&cubes, &state) 189 | } 190 | 191 | #[test] 192 | fn test_day22_part1() { 193 | assert_eq!(part1(input()), 583641); 194 | } 195 | 196 | #[test] 197 | fn test_day22_part2() { 198 | assert_eq!(part2(input()), 1182153534186233); 199 | } 200 | -------------------------------------------------------------------------------- /src/day23/input.txt: -------------------------------------------------------------------------------- 1 | ############# 2 | #...........# 3 | ###B#A#B#C### 4 | #C#D#D#A# 5 | ######### 6 | -------------------------------------------------------------------------------- /src/day23/input_alt.txt: -------------------------------------------------------------------------------- 1 | ############# 2 | #...........# 3 | ###D#A#C#A### 4 | #D#C#B#B# 5 | ######### 6 | -------------------------------------------------------------------------------- /src/day23/input_hardest.txt: -------------------------------------------------------------------------------- 1 | ############# 2 | #...........# 3 | ###A#B#D#C### 4 | #C#D#A#B# 5 | ######### 6 | -------------------------------------------------------------------------------- /src/day24/input.txt: -------------------------------------------------------------------------------- 1 | inp w 2 | mul x 0 3 | add x z 4 | mod x 26 5 | div z 1 6 | add x 12 7 | eql x w 8 | eql x 0 9 | mul y 0 10 | add y 25 11 | mul y x 12 | add y 1 13 | mul z y 14 | mul y 0 15 | add y w 16 | add y 4 17 | mul y x 18 | add z y 19 | inp w 20 | mul x 0 21 | add x z 22 | mod x 26 23 | div z 1 24 | add x 11 25 | eql x w 26 | eql x 0 27 | mul y 0 28 | add y 25 29 | mul y x 30 | add y 1 31 | mul z y 32 | mul y 0 33 | add y w 34 | add y 10 35 | mul y x 36 | add z y 37 | inp w 38 | mul x 0 39 | add x z 40 | mod x 26 41 | div z 1 42 | add x 14 43 | eql x w 44 | eql x 0 45 | mul y 0 46 | add y 25 47 | mul y x 48 | add y 1 49 | mul z y 50 | mul y 0 51 | add y w 52 | add y 12 53 | mul y x 54 | add z y 55 | inp w 56 | mul x 0 57 | add x z 58 | mod x 26 59 | div z 26 60 | add x -6 61 | eql x w 62 | eql x 0 63 | mul y 0 64 | add y 25 65 | mul y x 66 | add y 1 67 | mul z y 68 | mul y 0 69 | add y w 70 | add y 14 71 | mul y x 72 | add z y 73 | inp w 74 | mul x 0 75 | add x z 76 | mod x 26 77 | div z 1 78 | add x 15 79 | eql x w 80 | eql x 0 81 | mul y 0 82 | add y 25 83 | mul y x 84 | add y 1 85 | mul z y 86 | mul y 0 87 | add y w 88 | add y 6 89 | mul y x 90 | add z y 91 | inp w 92 | mul x 0 93 | add x z 94 | mod x 26 95 | div z 1 96 | add x 12 97 | eql x w 98 | eql x 0 99 | mul y 0 100 | add y 25 101 | mul y x 102 | add y 1 103 | mul z y 104 | mul y 0 105 | add y w 106 | add y 16 107 | mul y x 108 | add z y 109 | inp w 110 | mul x 0 111 | add x z 112 | mod x 26 113 | div z 26 114 | add x -9 115 | eql x w 116 | eql x 0 117 | mul y 0 118 | add y 25 119 | mul y x 120 | add y 1 121 | mul z y 122 | mul y 0 123 | add y w 124 | add y 1 125 | mul y x 126 | add z y 127 | inp w 128 | mul x 0 129 | add x z 130 | mod x 26 131 | div z 1 132 | add x 14 133 | eql x w 134 | eql x 0 135 | mul y 0 136 | add y 25 137 | mul y x 138 | add y 1 139 | mul z y 140 | mul y 0 141 | add y w 142 | add y 7 143 | mul y x 144 | add z y 145 | inp w 146 | mul x 0 147 | add x z 148 | mod x 26 149 | div z 1 150 | add x 14 151 | eql x w 152 | eql x 0 153 | mul y 0 154 | add y 25 155 | mul y x 156 | add y 1 157 | mul z y 158 | mul y 0 159 | add y w 160 | add y 8 161 | mul y x 162 | add z y 163 | inp w 164 | mul x 0 165 | add x z 166 | mod x 26 167 | div z 26 168 | add x -5 169 | eql x w 170 | eql x 0 171 | mul y 0 172 | add y 25 173 | mul y x 174 | add y 1 175 | mul z y 176 | mul y 0 177 | add y w 178 | add y 11 179 | mul y x 180 | add z y 181 | inp w 182 | mul x 0 183 | add x z 184 | mod x 26 185 | div z 26 186 | add x -9 187 | eql x w 188 | eql x 0 189 | mul y 0 190 | add y 25 191 | mul y x 192 | add y 1 193 | mul z y 194 | mul y 0 195 | add y w 196 | add y 8 197 | mul y x 198 | add z y 199 | inp w 200 | mul x 0 201 | add x z 202 | mod x 26 203 | div z 26 204 | add x -5 205 | eql x w 206 | eql x 0 207 | mul y 0 208 | add y 25 209 | mul y x 210 | add y 1 211 | mul z y 212 | mul y 0 213 | add y w 214 | add y 3 215 | mul y x 216 | add z y 217 | inp w 218 | mul x 0 219 | add x z 220 | mod x 26 221 | div z 26 222 | add x -2 223 | eql x w 224 | eql x 0 225 | mul y 0 226 | add y 25 227 | mul y x 228 | add y 1 229 | mul z y 230 | mul y 0 231 | add y w 232 | add y 1 233 | mul y x 234 | add z y 235 | inp w 236 | mul x 0 237 | add x z 238 | mod x 26 239 | div z 26 240 | add x -7 241 | eql x w 242 | eql x 0 243 | mul y 0 244 | add y 25 245 | mul y x 246 | add y 1 247 | mul z y 248 | mul y 0 249 | add y w 250 | add y 8 251 | mul y x 252 | add z y 253 | -------------------------------------------------------------------------------- /src/day24/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::*; 2 | 3 | use arrayvec::ArrayVec; 4 | 5 | type D = i16; 6 | const N: usize = 14; 7 | 8 | /* 9 | The following pattern repeats 14 times: 10 | 11 | inp w 12 | mul x 0 13 | add x z 14 | mod x 26 15 | div z (a: in [1, 26]) 16 | add x (b: -16..=0 or 10..) 17 | eql x w 18 | eql x 0 19 | mul y 0 20 | add y 25 21 | mul y x 22 | add y 1 23 | mul z y 24 | mul y 0 25 | add y w 26 | add y (c: in 0..=16) 27 | mul y x 28 | add z y 29 | 30 | If we decode it: 31 | 32 | w = input() 33 | x = (z % 26 + b) != w 34 | z = z / a * (25 * x + 1) + (w + c) * x 35 | 36 | Or: 37 | 38 | w = input() 39 | if (z % 26 + b) == w: 40 | z = z / a 41 | else: 42 | z = (z / a) * 26 + (w + c) 43 | 44 | Since all div/mod operations are in base 26, z can be treated as a base-26 integer: 45 | - if a == 26, the last digit is removed; otherwise, no digits are removed 46 | - if x == 1, another digit is appended the end: (w + u); otherwise, no digits are added 47 | - removal of digits happens before appending 48 | - in order for this to always work, we need u to be in the range 0..=16 49 | - x checks the mod of the very last digit only before any removal or appending 50 | - in some cases x can be always 1 - specifically, if u > 9 51 | - in the beginning, z == 0 (no digits); at the end, it's also 0, so all digits are removed 52 | - the number and location of all pop operations is known, so we need to figure all the pop ops 53 | - note also that if a is 26, b is always negative - so if pop happens, push is always optional 54 | - also note that if a is 21, b is always >= 10 - if there's no pop, there's a definite push 55 | - in the input, # pushes equals # pops/pushes => need to make sure no pushes happen during pops 56 | */ 57 | 58 | #[derive(Debug, Copy, Clone)] 59 | enum Block { 60 | Pop(D), // b <= 0 61 | Push(D), // c 62 | } 63 | 64 | fn parse_blocks(mut s: &[u8]) -> [Block; N] { 65 | let mut out = [Block::Pop(0); N]; 66 | let (mut n_push, mut n_pop) = (0, 0); 67 | for block in out.iter_mut() { 68 | s = s.skip_past(b'v', 3); 69 | let a = parse_int_fast::(&mut s); 70 | assert!(a == 1 || a == 26); 71 | let is_pop = a == 26; 72 | s = s.skip_past(b'x', 1); 73 | let b = parse_int_fast_signed::(&mut s); 74 | s = s.skip_past(b'w', 1); 75 | s = s.skip_past(b'w', 7); 76 | let c = parse_int_fast::(&mut s); 77 | assert!((-16..=0).contains(&b) || b >= 10); 78 | assert!((0..=16).contains(&c)); 79 | *block = if is_pop { 80 | n_pop += 1; 81 | Block::Pop(b) 82 | } else { 83 | n_push += 1; 84 | Block::Push(c) 85 | }; 86 | assert!(n_push >= n_pop); 87 | } 88 | out 89 | } 90 | 91 | fn solve(blocks: &[Block; N], smallest: bool) -> u64 { 92 | let mut stack = ArrayVec::<_, N>::new(); 93 | let mut w = [0; N]; 94 | for (i, &block) in blocks.iter().enumerate() { 95 | match block { 96 | Block::Push(c) => stack.push((i, c)), 97 | Block::Pop(b) => { 98 | // we need to ensure that (w[j] + c) + b = w[i] (here b <= 0) 99 | // note that j < i; to get the smallest answer, we want smallest w[j] possible 100 | // (and vice versa if we want the biggest number) 101 | // also note that (i, j) pairs will be unique and will not repeat, 102 | // so we can solve it precisely, right here without further ado 103 | let (j, c) = stack.pop().unwrap(); 104 | let d = b + c; 105 | assert!((-8..=8).contains(&d)); // w[j] + d == w[i] 106 | w[j] = if smallest { (1 - d).max(1) } else { (9 - d).min(9) }; 107 | w[i] = w[j] + d; 108 | assert!((1..=9).contains(&w[i])); 109 | assert!((1..=9).contains(&w[j])); 110 | assert_eq!(w[j] + d, w[i]); 111 | } 112 | } 113 | } 114 | let mut out = 0; 115 | for digit in w { 116 | out = out * 10 + digit as u64; 117 | } 118 | out 119 | } 120 | 121 | pub fn input() -> &'static [u8] { 122 | include_bytes!("input.txt") 123 | } 124 | 125 | pub fn part1(s: &[u8]) -> u64 { 126 | solve(&parse_blocks(s), false) 127 | } 128 | 129 | pub fn part2(s: &[u8]) -> u64 { 130 | solve(&parse_blocks(s), true) 131 | } 132 | 133 | #[test] 134 | fn test_day24_part1() { 135 | assert_eq!(part1(input()), 91398299697996); 136 | } 137 | 138 | #[test] 139 | fn test_day24_part2() { 140 | assert_eq!(part2(input()), 41171183141291); 141 | } 142 | -------------------------------------------------------------------------------- /src/day24/pattern.txt: -------------------------------------------------------------------------------- 1 | inp w 2 | mul x 0 3 | add x z 4 | mod x 26 5 | div z (\d+) 6 | add x (\-?\d+) 7 | eql x w 8 | eql x 0 9 | mul y 0 10 | add y 25 11 | mul y x 12 | add y 1 13 | mul z y 14 | mul y 0 15 | add y w 16 | add y (\d+) 17 | mul y x 18 | add z y 19 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(portable_simd)] 2 | #![feature(array_windows)] 3 | #![feature(map_first_last)] 4 | 5 | pub mod day01; 6 | pub mod day02; 7 | pub mod day03; 8 | pub mod day04; 9 | pub mod day05; 10 | pub mod day06; 11 | pub mod day07; 12 | pub mod day08; 13 | pub mod day09; 14 | pub mod day10; 15 | pub mod day11; 16 | pub mod day12; 17 | pub mod day13; 18 | pub mod day14; 19 | pub mod day15; 20 | pub mod day16; 21 | pub mod day17; 22 | pub mod day18; 23 | pub mod day19; 24 | pub mod day20; 25 | pub mod day21; 26 | pub mod day22; 27 | pub mod day23; 28 | pub mod day24; 29 | pub mod day25; 30 | 31 | pub mod utils; 32 | -------------------------------------------------------------------------------- /src/runner.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | use std::time::{Duration, Instant}; 3 | 4 | use eyre::{ensure, Result}; 5 | use structopt::StructOpt; 6 | 7 | const N_DAYS: usize = 25; 8 | 9 | const W_DAY: usize = 10; 10 | const W_PART: usize = 10; 11 | 12 | fn black_box(dummy: T) -> T { 13 | unsafe { 14 | let ret = std::ptr::read_volatile(&dummy); 15 | std::mem::forget(dummy); 16 | ret 17 | } 18 | } 19 | 20 | #[derive(Debug, StructOpt)] 21 | struct Args { 22 | #[structopt(help = "Day: 1 to 25. If not selected, all days are used.")] 23 | pub day: Option, 24 | #[structopt(long, short, requires("day"), help = "Part of the day: 1 or 2.")] 25 | pub part: Option, 26 | #[structopt(long, short, help = "Print benchmark times instead of problem answers.")] 27 | pub bench: bool, 28 | #[structopt( 29 | long, 30 | short, 31 | requires("bench"), 32 | help = "Time in seconds allowed for timing each problem part. [default: 1.0]" 33 | )] 34 | pub seconds: Option, 35 | #[structopt( 36 | long, 37 | short, 38 | requires("bench"), 39 | help = "Fraction of time used for warmup before benching (0-0.5). [default: 0.2]" 40 | )] 41 | pub warmup: Option, 42 | } 43 | 44 | fn run_one_raw(day: u8, part: u8, times: usize) -> (Duration, String) { 45 | macro_rules! if_day { 46 | ($day:expr, $day_i:ident) => { 47 | if_day!($day, $day_i, 1, part1); 48 | if_day!($day, $day_i, 2, part2); 49 | }; 50 | ($day:expr, $day_i:ident, $part:expr, $part_i:ident) => { 51 | if day == $day && part == $part { 52 | let t0 = Instant::now(); 53 | let out = black_box(aoc2021::$day_i::$part_i(&aoc2021::$day_i::input())); 54 | for _ in 1..times { 55 | let _ = black_box(aoc2021::$day_i::$part_i(&aoc2021::$day_i::input())); 56 | } 57 | let t1 = Instant::now(); 58 | return (t1 - t0, out.to_string()); 59 | } 60 | }; 61 | } 62 | 63 | if_day!(1, day01); 64 | if_day!(2, day02); 65 | if_day!(3, day03); 66 | if_day!(4, day04); 67 | if_day!(5, day05); 68 | if_day!(6, day06); 69 | if_day!(7, day07); 70 | if_day!(8, day08); 71 | if_day!(9, day09); 72 | if_day!(10, day10); 73 | if_day!(11, day11); 74 | if_day!(12, day12); 75 | if_day!(13, day13); 76 | if_day!(14, day14); 77 | if_day!(15, day15); 78 | if_day!(16, day16); 79 | if_day!(17, day17); 80 | if_day!(18, day18); 81 | if_day!(19, day19); 82 | if_day!(20, day20); 83 | if_day!(21, day21); 84 | if_day!(22, day22); 85 | if_day!(23, day23); 86 | if_day!(24, day24); 87 | if_day!(25, day25); 88 | 89 | return Default::default(); 90 | } 91 | 92 | fn print_header(part: Option) { 93 | print!("{:)>) { 109 | let day = day_part.map(|x| x.0); 110 | let days = if let Some(day) = day { vec![day] } else { (1..=N_DAYS as u8).collect() }; 111 | let part = day_part.map(|x| x.1).unwrap_or_default(); 112 | let parts = if let Some(part) = part { vec![part] } else { vec![1, 2] }; 113 | print_header(part); 114 | 115 | for &day in &days { 116 | print_day(day); 117 | for &part in &parts { 118 | let out = run_one_raw(day, part, 1).1; 119 | print!("{: f64 { 126 | macro_rules! status { 127 | ($($arg:tt)*) => { 128 | print!("\r"); 129 | fmt_pre(); 130 | print!($($arg)*); 131 | } 132 | } 133 | 134 | const SPINNER: &'static str = &"↑↗→↘↓↙←↖"; 135 | const N_CYCLES: usize = 2; 136 | let n_spinner = SPINNER.chars().count(); 137 | let n_chunks = n_spinner * N_CYCLES; 138 | 139 | let (mut n_estimate, mut tm) = (1, 0.); 140 | while tm < 0.01 { 141 | tm = run_one_raw(day, part, n_estimate).0.as_secs_f64(); 142 | n_estimate *= 2; 143 | } 144 | let n_total = (seconds / tm * (n_estimate as f64)).ceil() as usize; 145 | let n_bench = (((n_total as f64) * (1. - warmup) / (n_chunks as f64)).ceil() as usize).max(1); 146 | 147 | // warmup 148 | let n_warmup = ((n_total as f64) * warmup).ceil().min((n_total as f64) - 1.) as usize; 149 | status!("."); 150 | let _ = run_one_raw(day, part, n_warmup); 151 | 152 | // bench 153 | let mut tm_total = Duration::default(); 154 | for i in 0..n_chunks { 155 | status!("{}", SPINNER.chars().skip(i % n_spinner).next().unwrap()); 156 | std::io::stdout().flush().unwrap(); 157 | tm_total += run_one_raw(day, part, n_bench).0; 158 | } 159 | 160 | // result 161 | print!("\r"); 162 | tm_total.as_secs_f64() / ((n_chunks * n_bench) as f64) 163 | } 164 | 165 | fn format_time(seconds: f64) -> String { 166 | let mics = seconds * 1e6; 167 | let prec = match mics { 168 | m if m < 10. => 2, 169 | m if m < 100. => 1, 170 | _ => 0, 171 | }; 172 | let mics_fmt = format!("{:.p$}", mics, p = prec); 173 | let units = "μs"; 174 | format!("{} {}", mics_fmt, units) 175 | } 176 | 177 | fn run_bench(day_part: Option<(u8, Option)>, seconds: f64, warmup: f64) { 178 | let day = day_part.map(|x| x.0); 179 | let days = if let Some(day) = day { vec![day] } else { (1..=N_DAYS as u8).collect() }; 180 | let part = day_part.map(|x| x.1).unwrap_or_default(); 181 | let parts = if let Some(part) = part { vec![part] } else { vec![1, 2] }; 182 | 183 | print_header(part); 184 | let mut tm_total = 0.; 185 | for &day in &days { 186 | let mut tms_day = vec![]; 187 | for &part in &parts { 188 | let tm = bench_one(day, part, seconds, warmup, || { 189 | print_day(day); 190 | if part == 2 && parts.len() == 2 { 191 | print!("{: Result<()> { 211 | let Args { day, part, bench, seconds, warmup } = StructOpt::from_args_safe()?; 212 | 213 | if let Some(day) = day { 214 | ensure!((1..=N_DAYS as u8).contains(&day), "day must be 1..={}", N_DAYS); 215 | } 216 | if let Some(part) = part { 217 | ensure!((1..=2).contains(&part), "part must be 1..=2"); 218 | } 219 | 220 | let day_part = day.map(|day| (day, part)); 221 | if bench { 222 | let seconds = seconds.unwrap_or(1.0); 223 | ensure!(seconds > 0., "seconds must be a positive number"); 224 | let warmup = warmup.unwrap_or(0.2); 225 | ensure!((0.0..=0.5).contains(&warmup), "warmup must be in [0.0; 0.5]"); 226 | run_bench(day_part, seconds, warmup); 227 | } else { 228 | run_output(day_part); 229 | } 230 | 231 | Ok(()) 232 | } 233 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use core::hint::unreachable_unchecked; 2 | use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; 3 | use core::slice; 4 | 5 | use std::iter; 6 | 7 | use memchr::{memchr, memchr2}; 8 | 9 | pub trait Integer: 10 | Copy 11 | + From 12 | + Add 13 | + AddAssign 14 | + Sub 15 | + SubAssign 16 | + Mul 17 | + MulAssign 18 | + Default 19 | + PartialEq 20 | + Eq 21 | + Ord 22 | + PartialOrd 23 | + iter::Sum 24 | + iter::Product 25 | { 26 | } 27 | 28 | impl Integer for u8 {} 29 | impl Integer for u16 {} 30 | impl Integer for u32 {} 31 | impl Integer for u64 {} 32 | impl Integer for i16 {} 33 | impl Integer for i32 {} 34 | impl Integer for i64 {} 35 | impl Integer for usize {} 36 | impl Integer for isize {} 37 | 38 | #[inline(always)] 39 | pub fn parse_int_fast_skip_custom< 40 | T: Integer, 41 | const MIN_DIGITS: usize, 42 | const MAX_DIGITS: usize, 43 | const SKIP: usize, 44 | >( 45 | s: &mut &[u8], 46 | ) -> T { 47 | let mut v = T::from(s.get_digit()); 48 | *s = s.advance(1); 49 | for _ in 1..MIN_DIGITS { 50 | let d = s.get_digit(); 51 | *s = s.advance(1); 52 | v = v * T::from(10u8) + T::from(d); 53 | } 54 | for _ in MIN_DIGITS..MAX_DIGITS { 55 | let d = s.get_digit(); 56 | if d < 10 { 57 | *s = s.advance(1); 58 | v = v * T::from(10u8) + T::from(d); 59 | } else { 60 | *s = s.advance(SKIP); 61 | return v; 62 | } 63 | } 64 | *s = s.advance(SKIP); 65 | v 66 | } 67 | 68 | #[inline(always)] 69 | pub fn parse_int_fast( 70 | s: &mut &[u8], 71 | ) -> T { 72 | parse_int_fast_skip_custom::(s) 73 | } 74 | 75 | #[inline(always)] 76 | pub fn parse_int_fast_signed_skip_custom< 77 | T: Integer + Neg, 78 | const MIN_DIGITS: usize, 79 | const MAX_DIGITS: usize, 80 | const SKIP: usize, 81 | >( 82 | s: &mut &[u8], 83 | ) -> T { 84 | let neg = s.get_first() == b'-'; 85 | if neg { 86 | *s = s.advance(1); 87 | } 88 | let num = parse_int_fast_skip_custom::(s); 89 | if neg { 90 | -num 91 | } else { 92 | num 93 | } 94 | } 95 | 96 | #[inline(always)] 97 | pub fn parse_int_fast_signed< 98 | T: Integer + Neg, 99 | const MIN_DIGITS: usize, 100 | const MAX_DIGITS: usize, 101 | >( 102 | s: &mut &[u8], 103 | ) -> T { 104 | parse_int_fast_signed_skip_custom::(s) 105 | } 106 | 107 | pub trait SliceExt { 108 | fn get_len(&self) -> usize; 109 | fn get_at(&self, i: usize) -> T; 110 | fn get_ref_at(&self, i: usize) -> &T; 111 | fn get_mut_at(&mut self, i: usize) -> &mut T; 112 | fn set_at(&mut self, i: usize, v: T); 113 | fn advance(&self, n: usize) -> &Self; 114 | 115 | #[inline] 116 | fn get_first(&self) -> T { 117 | self.get_at(0) 118 | } 119 | 120 | #[inline] 121 | fn get_last(&self) -> T { 122 | self.get_at(self.get_len() - 1) 123 | } 124 | 125 | #[inline] 126 | fn get_last_mut(&mut self) -> &mut T { 127 | self.get_mut_at(self.get_len() - 1) 128 | } 129 | 130 | #[inline] 131 | fn set_last(&mut self, value: T) { 132 | self.set_at(self.get_len(), value) 133 | } 134 | } 135 | 136 | impl SliceExt for [T] { 137 | #[inline] 138 | fn get_len(&self) -> usize { 139 | self.len() 140 | } 141 | 142 | #[inline] 143 | fn get_at(&self, i: usize) -> T { 144 | unsafe { *self.get_unchecked(i) } 145 | } 146 | 147 | #[inline] 148 | fn get_ref_at(&self, i: usize) -> &T { 149 | unsafe { &(*self.get_unchecked(i)) } 150 | } 151 | 152 | #[inline] 153 | fn get_mut_at(&mut self, i: usize) -> &mut T { 154 | unsafe { self.get_unchecked_mut(i) } 155 | } 156 | 157 | #[inline] 158 | fn set_at(&mut self, i: usize, v: T) { 159 | unsafe { *self.get_unchecked_mut(i) = v }; 160 | } 161 | 162 | #[inline] 163 | fn advance(&self, n: usize) -> &Self { 164 | unsafe { slice::from_raw_parts(self.as_ptr().add(n), self.len().saturating_sub(n)) } 165 | } 166 | } 167 | 168 | pub trait SliceExtNumeric { 169 | fn add_at(&mut self, i: usize, v: T); 170 | } 171 | 172 | impl + AddAssign> SliceExtNumeric for [T] { 173 | #[inline] 174 | fn add_at(&mut self, i: usize, v: T) { 175 | unsafe { *self.get_unchecked_mut(i) += v }; 176 | } 177 | } 178 | 179 | pub trait ByteSliceExt: SliceExt { 180 | fn memchr(&self, c: u8) -> usize; 181 | fn memchr2(&self, c1: u8, c2: u8) -> usize; 182 | fn get_u16_ne(&self) -> u16; 183 | 184 | #[inline] 185 | fn get_digit(&self) -> u8 { 186 | self.get_first().wrapping_sub(b'0') 187 | } 188 | 189 | #[inline] 190 | fn get_digit_at(&self, i: usize) -> u8 { 191 | self.get_at(i).wrapping_sub(b'0') 192 | } 193 | 194 | #[inline] 195 | fn skip_past(&self, c: u8, i: usize) -> &Self { 196 | self.advance(1 + i + self.memchr(c)) 197 | } 198 | } 199 | 200 | impl ByteSliceExt for [u8] { 201 | #[inline] 202 | fn memchr(&self, c: u8) -> usize { 203 | memchr(c, self).unwrap_or_else(|| unsafe { unreachable_unchecked() }) 204 | } 205 | 206 | #[inline] 207 | fn memchr2(&self, c1: u8, c2: u8) -> usize { 208 | memchr2(c1, c2, self).unwrap_or_else(|| unsafe { unreachable_unchecked() }) 209 | } 210 | 211 | #[inline] 212 | fn get_u16_ne(&self) -> u16 { 213 | let mut a = [0; 2]; 214 | a.copy_from_slice(&self[..2]); 215 | u16::from_ne_bytes(a) 216 | } 217 | } 218 | 219 | #[derive(Debug)] 220 | pub struct UnsafeStack<'a, T> { 221 | stack: &'a mut [T], 222 | ptr: *mut T, 223 | } 224 | 225 | impl<'a, T: Copy> UnsafeStack<'a, T> { 226 | pub fn new(stack: &'a mut [T]) -> Self { 227 | let ptr = stack.as_mut_ptr(); 228 | Self { stack, ptr } 229 | } 230 | 231 | #[inline] 232 | pub fn len(&self) -> usize { 233 | unsafe { self.ptr.offset_from(self.stack.as_ptr()) as usize } 234 | } 235 | 236 | #[inline] 237 | pub fn is_empty(&self) -> bool { 238 | self.len() == 0 239 | } 240 | 241 | #[inline] 242 | pub fn into_slice(self) -> &'a [T] { 243 | &self.stack[..self.len()] 244 | } 245 | 246 | #[inline] 247 | pub fn push(&mut self, v: T) { 248 | unsafe { 249 | (*self.ptr) = v; 250 | self.ptr = self.ptr.add(1); 251 | } 252 | } 253 | 254 | #[inline] 255 | pub fn pop(&mut self) -> T { 256 | unsafe { 257 | self.ptr = self.ptr.sub(1); 258 | *self.ptr 259 | } 260 | } 261 | } 262 | --------------------------------------------------------------------------------