135 Commits

Author SHA1 Message Date
24430cf1da Implement 2023 day 18 part 2
This was not at all the twist I expected, but I like it.
2023-12-18 20:52:05 +01:00
8faabf1220 Prepare for part 2 2023-12-18 20:32:38 +01:00
f15c8fbec3 Implement 2023 day 18 part 1 2023-12-18 20:26:01 +01:00
353e551f66 Implement 2023 day 17 part 2 2023-12-17 19:41:45 +01:00
717417eaf0 Implement 2023 day 17 part 1 2023-12-17 19:04:01 +01:00
d78d74c92d Implement 2023 day 16 part 2 2023-12-16 12:03:08 +01:00
c2389e93af Implement 2023 day 16 part 1 2023-12-16 11:38:50 +01:00
682e6f06b8 Flatten DP buffers
Going from 2d to 1d arrays improves cache locality and vectorization,
resulting in a roughly 40% speedup for part 2.
2023-12-15 17:39:59 +01:00
673e8184ed Zero init > 1 init 2023-12-15 09:03:06 +01:00
6657519179 Why have many hash map when few do trick 2023-12-15 08:54:02 +01:00
f898ffd216 Implement 2023 day 15 part 1 2023-12-15 08:45:19 +01:00
862ef3840c Implement 2023 day 15 part 1 2023-12-15 08:06:19 +01:00
44a1bcdc62 Merge owned and non-owned grids
Through the power of generics. Should've been easier if it was possible
to be generic over mutable and non-mutable, but AsRef/AsMut is close
enough
2023-12-14 21:33:09 +01:00
b7baebd050 Very clunky implementation of 2023 day 14 part 2 2023-12-14 20:05:25 +01:00
4f67ce4891 mplement 2023 day 14 part 1 2023-12-14 08:37:07 +01:00
975a1f8faf Misc fixes 2023-12-13 18:41:15 +01:00
0c4430ad01 Implement 2023 day 13 part 2 2023-12-13 18:33:09 +01:00
0838646973 Implement 2023 day 13 part 1 2023-12-13 18:21:19 +01:00
e449672487 Reduce dimensions of DP memo
We don't actually need all days, we just need the previous to build the
next
2023-12-12 18:14:32 +01:00
83d14af4f3 Missing sample 2023-12-12 12:20:13 +01:00
ec80523cac Implement 2023 day 12 2023-12-12 12:16:03 +01:00
06894b3455 Implement 2023 day 11 part 2 2023-12-11 08:54:33 +01:00
fb7e6d0a92 Implement 2023 day 11 part 1 2023-12-11 08:48:37 +01:00
43bf260887 Implement 2023 day 10 part 2 2023-12-10 11:45:18 +01:00
f1b23b0116 Implement 2023 day 10 part 1 2023-12-10 10:38:16 +01:00
126eeb7587 Move grid code to common 2023-12-10 09:59:19 +01:00
ee2ff35609 Remove most allocations from the code path 2023-12-09 19:42:20 +01:00
92c985cbd4 Unify part 1 and 2 better 2023-12-09 19:10:01 +01:00
de440ef10e Implement 2023 day 9 2023-12-09 10:52:23 +01:00
cfea20bed3 Implement 2023 day 8 part 2 2023-12-08 08:11:04 +01:00
8f6937ae42 Implement 2023 day 8 part 1 2023-12-08 07:14:36 +01:00
2d2be463d1 Avoid unnecessary floor 2023-12-07 21:52:37 +01:00
e1c23385c9 Replace binary search with maths 2023-12-07 21:45:20 +01:00
f5ca9af74b Clarify order of operations 2023-12-07 21:08:05 +01:00
de24e8b489 Replace sort with counting sort 2023-12-07 21:03:41 +01:00
64f10ff04d Fixed 2023 day 7 2023-12-07 20:48:22 +01:00
cb5af961bc Incorrect 2023 day 7 part 2
But it passes the tests, so I might as well push it.
2023-12-07 09:25:03 +01:00
164383efb7 Implement 2023 day 7 part 1 2023-12-07 09:04:45 +01:00
d2e1ad50d2 Off by one 2023-12-06 13:34:25 +01:00
bfed992b7d Binary search is best search 2023-12-06 08:53:55 +01:00
b3ccfb7a7d Implement 2023 day 6 part 2 2023-12-06 08:45:49 +01:00
4183f4a242 Implement 2023 day 6 part 1 2023-12-06 08:29:41 +01:00
018d41e753 Proper implementation for 2023 day 5 part 2 2023-12-05 19:15:41 +01:00
63c1024d22 Brute force day 2023 day 5 part 2 2023-12-05 09:10:16 +01:00
b7797c40aa Implement 2023 day 5 part 1 2023-12-05 09:01:00 +01:00
f92261c6b9 Unused import 2023-12-05 08:20:06 +01:00
1a45edd3ff Implement 2023 day 4 2023-12-04 08:11:27 +01:00
6e6713bfc3 Forgot to add sample, simplyfiy match 2023-12-03 19:48:17 +01:00
af3ee23050 Implement 2023 day 3 2023-12-03 19:45:48 +01:00
4ee6a82056 Now with fewer branches 2023-12-02 14:11:18 +01:00
5517662ae2 Replace regex with aho-corasick 2023-12-02 13:44:07 +01:00
2a419bb468 Unused imports 2023-12-02 10:46:36 +01:00
bf953b7980 Implement 2023 day 2 part 2 2023-12-02 10:40:33 +01:00
033625f041 Implement 2023 day 2 part 1 2023-12-02 10:32:53 +01:00
524527dbd1 Now with more iterators and 10% perf gain 2023-12-01 12:40:15 +01:00
1541b82c11 Implement 2023 day 1 part 2 2023-12-01 11:30:36 +01:00
28178c8a73 Slightly more natural part 1 2023-12-01 10:22:26 +01:00
98559e2010 Day 1 2023 part 1 2023-12-01 10:19:55 +01:00
de2ffae641 Years 2023-12-01 10:04:14 +01:00
e57d775414 Merge pull request #5 from bertptrs/setup-2023 2023-12-01 10:02:09 +01:00
4785d71e0c Update CI for 2023
No clippy warnings right now because everything is unsed anyway
2023-11-26 14:46:37 +01:00
0a22995055 Add skeletons for all days 2023-11-26 14:40:16 +01:00
ce008e47da 100% fewer suppresed clippy warnings 2023-11-12 14:59:55 +01:00
542a8143e2 Painfully implement day 22 part 2 2023-11-12 14:32:22 +01:00
10174a2915 Formatting for let else now exists 2023-11-12 14:32:07 +01:00
3522b38394 Try to normalize the cube a little 2023-11-10 08:47:39 +01:00
8c2c3be40c Sanity check transition diagram and fix inconsistencies 2023-11-02 22:56:46 +01:00
983bc6af26 Some work on brute forcing 2023-11-02 22:28:10 +01:00
aacbc0e94a Update deps 2023-10-29 20:48:45 +01:00
722f5205ff Stop manually impl'ing slice::from_ref 2023-07-01 18:00:35 +02:00
01300de076 Avoid sorting the entire list
Or materializing the list for that matter, since we only need to compare
each entry against both markers
2023-07-01 17:35:35 +02:00
d5d9b1c192 Bunch of clippy fixes 2023-01-28 22:52:46 +01:00
e914c17f81 Codegen optimization is my passion 2023-01-28 22:33:48 +01:00
c35858239f Also prune while queueing 2023-01-28 22:21:33 +01:00
5ea0f6fa6f Use correct early cut-off bound 2023-01-28 22:00:12 +01:00
5045f83df8 Slightly more efficient search 2023-01-28 13:45:58 +01:00
787e215f84 Horrible brute force part 2 2023-01-28 12:22:35 +01:00
286fc3dd7f Terribly inefficient part 1 2023-01-27 19:57:58 +01:00
4044af4d8d Implement 2022 day 24 part 2 2023-01-02 22:18:33 +01:00
93c1d8f957 Implement 2022 day 24 part 1 2023-01-02 18:56:47 +01:00
dcc387ef2c Implement 2022 day 25 2022-12-25 20:34:52 +01:00
2d3f55097c Simple type to help clippy 2022-12-23 19:12:20 +01:00
72504d71ef Implement 2022 day 23 part 2 2022-12-23 18:16:32 +01:00
45e0cd6273 Implement 2022 day 23 part 1 2022-12-23 18:03:57 +01:00
a8752ad7a4 Implement 2022 day 22 part 1 2022-12-23 09:03:26 +01:00
06a61ab62c Implement 2022 day 21 part 2 2022-12-21 21:13:22 +01:00
6c58a3ba69 Implement 2022 day 21 part 1 2022-12-21 08:47:47 +01:00
b1d9314bc7 Remove useless code 2022-12-20 22:48:17 +01:00
abde2ae548 Always walk the short way around the circle 2022-12-20 22:42:17 +01:00
24c03ae241 Implement 2022 day 20 2022-12-20 22:27:12 +01:00
a3f9edd48d Disturbingly simple optimization 2022-12-18 22:57:19 +01:00
483aeb7e4d Finally implement 2022 day 17 part 2 2022-12-18 22:40:15 +01:00
0c183b316e Refactor common code out 2022-12-18 21:31:02 +01:00
594226320d Implement 2022 day 17 part 1 2022-12-18 21:21:14 +01:00
a713d8690a Implement 2022 day 18 part 2 2022-12-18 20:21:16 +01:00
f8fcc8ebba Implement 20220 day 18 part 1
Very inefficient and with too much hashset, but it works
2022-12-18 17:19:34 +01:00
1f9915e79d Simplify algorithm by unsimplifying graph 2022-12-17 12:38:44 +01:00
96c411126c Implement 2022 day 16 2022-12-17 11:57:42 +01:00
9aad6fe511 Non-functional implementation of 2022 day 16 part 1 2022-12-17 11:04:46 +01:00
84110350ff Implement 2022 day 15 part 2 2022-12-16 08:28:06 +01:00
0f64ec4e8f Implement 2022 day 15 part 1 2022-12-15 18:16:49 +01:00
065fa9cda8 Move Vec2 to common utilities 2022-12-15 09:16:46 +01:00
7de23c3b24 Satiate clippy 2022-12-15 09:09:30 +01:00
c66fb86ef9 Implement 2022 day 14 part 2 2022-12-14 22:27:12 +01:00
64757031fb Implement 2022 day 14 part 1 2022-12-14 21:47:11 +01:00
f48a02c81c Stream to reduce peak allocations 2022-12-13 18:22:26 +01:00
4b18a733c9 Implement 2022 day 13 2022-12-13 18:15:12 +01:00
796c638300 Document optimization journey 2022-12-12 22:58:56 +01:00
f8c6f4e01f Refactor out common code 2022-12-12 22:46:30 +01:00
e2d1ec8c91 Bugfix that probably won't affect any actual input 2022-12-12 22:32:41 +01:00
d92e77cb88 Reinstroduce the humble index set 2022-12-12 21:52:11 +01:00
a4b5390f80 Implement 2022 day 12 2022-12-12 18:39:44 +01:00
6d9defce42 Discover the magic of nom::combinator::value 2022-12-11 22:27:25 +01:00
92db6e56c9 Use multiplication and shift for mod 2022-12-11 22:03:47 +01:00
6a51f123ab Implement 2022 day 11 part 2 2022-12-11 21:13:09 +01:00
9a63adc355 Implement 2022 day 11 part 1 2022-12-11 20:34:47 +01:00
a7188186c3 Actually test part two, why not 2022-12-10 22:21:04 +01:00
a79eb70581 Cleaner but slightly slower implementation 2022-12-10 22:00:56 +01:00
fbfcfa65fb Implement 2022 day 10 2022-12-10 21:50:31 +01:00
20b2fe7684 Remove useless lifetime 2022-12-09 12:00:22 +01:00
e45aaad1c4 Faster hash set 2022-12-09 11:43:33 +01:00
a44420cbe7 Implement 2022 day 9 2022-12-09 11:22:24 +01:00
44b7b6b1b2 Incorrect implementation for 2022 day 9 2022-12-09 11:09:36 +01:00
79387b5f14 Slightly more efficient O(kn) implementation 2022-12-08 22:40:39 +01:00
a05dc588db Implement 2022 day 8 part 2 2022-12-08 12:09:04 +01:00
b080859356 Replace todo with error, bench everything 2022-12-08 11:06:59 +01:00
fead587b2a Implement 2022 day 8 part 1 2022-12-08 11:01:48 +01:00
eec886b5e2 Slightly cleaner parser 2022-12-07 16:01:09 +01:00
45a6c78d77 Remove most allocations 2022-12-07 15:27:30 +01:00
e80b5bde68 Implement 2022 day 7 2022-12-07 10:27:06 +01:00
1cd5579bf6 Use iterators instead of explicit indexing 2022-12-06 18:37:38 +01:00
7c7c69255d Replace indirect indexing
230 byte overhead is worth it to avoid conversions and potential
indexing errors
2022-12-06 18:23:43 +01:00
391bba24c5 Use enumerate combinator 2022-12-06 18:19:42 +01:00
e887a8ad0d Implement 2022 day 6 2022-12-06 08:29:26 +01:00
38a024d095 Implement 2022 day 5 2022-12-05 11:14:36 +01:00
124 changed files with 22860 additions and 115 deletions

View File

@@ -1,7 +1,7 @@
on:
- push
name: Advent of Code 2022
name: Advent of Code 2023
jobs:
ci:
@@ -20,33 +20,33 @@ jobs:
continue-on-error: ${{ matrix.experimental }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install toolchain
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
override: true
components: rustfmt, clippy
components: rustfmt
- name: Set up caching
uses: Swatinem/rust-cache@v2
with:
workspaces: >
2022 -> target
2023 -> target
- name: Build binaries
working-directory: 2022
working-directory: 2023
run: >
cargo build --all-targets
- name: Run tests
working-directory: 2022
working-directory: 2023
run: >
cargo test
- name: Run clippy
working-directory: 2022
- name: Check formatting
working-directory: 2023
run: >
cargo clippy -- --deny warnings
cargo fmt --check

3
.gitignore vendored
View File

@@ -64,3 +64,6 @@ target/
perf.data
perf.data.old
flamegraph.svg
# Ignore saved inputs
inputs/

View File

@@ -6,13 +6,16 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ahash = "0.8.2"
anyhow = "1.0.66"
clap = { version = "4.0.19", features = ["derive"] }
itertools = "0.10.5"
itertools = "0.11"
ndarray = "0.15.6"
nom = "7.1.1"
strength_reduce = "0.2.4"
[dev-dependencies]
criterion = "0.4.0"
criterion = "0.5.0"
[profile.release]
# Keep debug information in release for better flamegraphs

View File

@@ -8,36 +8,33 @@ use criterion::BenchmarkId;
use criterion::Criterion;
/// Number of days we have an implementation to benchmark
const DAYS_IMPLEMENTED: u8 = 4;
const DAYS_IMPLEMENTED: u8 = 25;
fn read_input(day: u8) -> Vec<u8> {
let input_path = format!("inputs/{:02}.txt", day);
fn read_input(day: u8) -> std::io::Result<Vec<u8>> {
let input_path = format!("inputs/{day:02}.txt");
let mut buffer = Vec::new();
File::open(input_path)
.expect("Failed to open input file")
.read_to_end(&mut buffer)
.expect("Failed to read input file");
File::open(input_path)?.read_to_end(&mut buffer)?;
buffer
Ok(buffer)
}
pub fn benchmark_days(c: &mut Criterion) {
for day in 1..=DAYS_IMPLEMENTED {
let input = read_input(day);
if let Ok(input) = read_input(day) {
let part1 = get_implementation(day, false).unwrap();
let part1 = get_implementation(day, false).unwrap();
c.bench_with_input(BenchmarkId::new("part1", day), &input, |b, i| {
b.iter(|| part1(i));
});
if day < 25 {
let part2 = get_implementation(day, true).unwrap();
c.bench_with_input(BenchmarkId::new("part2", day), &input, |b, i| {
b.iter(|| part2(i));
c.bench_with_input(BenchmarkId::new("part1", day), &input, |b, i| {
b.iter(|| part1(i));
});
if day < 25 {
let part2 = get_implementation(day, true).unwrap();
c.bench_with_input(BenchmarkId::new("part2", day), &input, |b, i| {
b.iter(|| part2(i));
});
}
}
}
}

514
2022/inputs/05.txt Normal file
View File

@@ -0,0 +1,514 @@
[G] [D] [Q]
[P] [T] [L] [M] [Z]
[Z] [Z] [C] [Z] [G] [W]
[M] [B] [F] [P] [C] [H] [N]
[T] [S] [R] [H] [W] [R] [L] [W]
[R] [T] [Q] [Z] [R] [S] [Z] [F] [P]
[C] [N] [H] [R] [N] [H] [D] [J] [Q]
[N] [D] [M] [G] [Z] [F] [W] [S] [S]
1 2 3 4 5 6 7 8 9
move 7 from 6 to 8
move 5 from 2 to 6
move 2 from 4 to 1
move 1 from 4 to 5
move 5 from 7 to 6
move 7 from 6 to 3
move 5 from 9 to 2
move 6 from 2 to 3
move 2 from 7 to 9
move 20 from 3 to 1
move 11 from 1 to 6
move 1 from 9 to 8
move 3 from 8 to 2
move 8 from 1 to 5
move 10 from 8 to 4
move 7 from 6 to 4
move 1 from 8 to 3
move 8 from 1 to 7
move 16 from 4 to 8
move 1 from 9 to 8
move 1 from 5 to 2
move 4 from 7 to 4
move 5 from 6 to 7
move 1 from 6 to 1
move 8 from 7 to 4
move 1 from 6 to 9
move 12 from 4 to 5
move 3 from 2 to 5
move 1 from 6 to 2
move 1 from 3 to 7
move 1 from 3 to 2
move 1 from 9 to 3
move 1 from 7 to 8
move 1 from 7 to 5
move 1 from 3 to 2
move 4 from 5 to 7
move 5 from 5 to 7
move 1 from 4 to 3
move 1 from 3 to 9
move 3 from 1 to 8
move 1 from 9 to 1
move 2 from 2 to 1
move 2 from 2 to 7
move 8 from 8 to 1
move 3 from 5 to 2
move 8 from 7 to 5
move 7 from 1 to 3
move 3 from 1 to 7
move 1 from 1 to 5
move 1 from 3 to 7
move 7 from 5 to 8
move 2 from 2 to 8
move 1 from 3 to 2
move 1 from 2 to 4
move 1 from 4 to 8
move 13 from 8 to 1
move 13 from 5 to 9
move 2 from 5 to 2
move 7 from 9 to 3
move 12 from 8 to 3
move 4 from 9 to 3
move 1 from 3 to 4
move 2 from 2 to 3
move 1 from 1 to 6
move 1 from 2 to 3
move 1 from 5 to 9
move 7 from 7 to 4
move 10 from 1 to 8
move 1 from 1 to 4
move 1 from 9 to 5
move 2 from 5 to 1
move 1 from 6 to 5
move 3 from 8 to 9
move 5 from 4 to 3
move 4 from 4 to 1
move 7 from 1 to 6
move 2 from 5 to 7
move 35 from 3 to 4
move 4 from 9 to 1
move 19 from 4 to 8
move 1 from 7 to 6
move 1 from 9 to 2
move 10 from 4 to 5
move 2 from 4 to 7
move 3 from 4 to 3
move 1 from 2 to 8
move 1 from 1 to 9
move 3 from 3 to 6
move 4 from 8 to 6
move 4 from 5 to 2
move 2 from 8 to 3
move 3 from 5 to 9
move 12 from 6 to 1
move 8 from 8 to 6
move 2 from 9 to 1
move 1 from 4 to 1
move 1 from 3 to 8
move 3 from 7 to 8
move 2 from 9 to 7
move 1 from 6 to 7
move 10 from 6 to 8
move 4 from 2 to 5
move 1 from 3 to 7
move 7 from 5 to 7
move 13 from 8 to 1
move 29 from 1 to 4
move 8 from 7 to 8
move 1 from 1 to 3
move 3 from 7 to 6
move 1 from 1 to 9
move 15 from 4 to 1
move 1 from 3 to 6
move 10 from 1 to 6
move 10 from 6 to 7
move 1 from 4 to 9
move 1 from 9 to 1
move 1 from 9 to 7
move 6 from 7 to 8
move 1 from 1 to 6
move 5 from 6 to 5
move 21 from 8 to 9
move 5 from 1 to 9
move 2 from 9 to 5
move 3 from 5 to 6
move 3 from 7 to 9
move 4 from 4 to 6
move 6 from 8 to 7
move 6 from 6 to 3
move 2 from 7 to 9
move 1 from 7 to 2
move 6 from 3 to 2
move 1 from 6 to 4
move 4 from 5 to 9
move 1 from 4 to 5
move 9 from 4 to 6
move 7 from 6 to 4
move 10 from 9 to 2
move 5 from 7 to 5
move 10 from 2 to 7
move 2 from 5 to 4
move 2 from 5 to 9
move 4 from 9 to 4
move 1 from 8 to 6
move 7 from 7 to 2
move 1 from 5 to 4
move 2 from 7 to 1
move 1 from 5 to 7
move 3 from 6 to 2
move 4 from 4 to 5
move 1 from 2 to 7
move 10 from 4 to 7
move 3 from 7 to 3
move 17 from 9 to 4
move 1 from 1 to 4
move 1 from 1 to 5
move 5 from 2 to 7
move 1 from 9 to 2
move 5 from 4 to 8
move 2 from 9 to 7
move 4 from 8 to 1
move 3 from 4 to 8
move 1 from 2 to 5
move 1 from 9 to 2
move 6 from 4 to 8
move 3 from 7 to 5
move 1 from 4 to 9
move 1 from 9 to 1
move 3 from 1 to 9
move 4 from 8 to 5
move 2 from 9 to 8
move 4 from 2 to 5
move 8 from 7 to 2
move 5 from 8 to 5
move 2 from 7 to 8
move 1 from 3 to 5
move 1 from 1 to 2
move 1 from 1 to 6
move 2 from 3 to 6
move 5 from 2 to 8
move 4 from 7 to 1
move 7 from 8 to 5
move 1 from 1 to 5
move 3 from 8 to 3
move 1 from 9 to 3
move 7 from 2 to 3
move 2 from 2 to 8
move 2 from 4 to 8
move 1 from 8 to 5
move 1 from 1 to 4
move 2 from 4 to 7
move 2 from 7 to 1
move 3 from 2 to 3
move 3 from 5 to 2
move 1 from 8 to 3
move 3 from 3 to 2
move 5 from 2 to 1
move 17 from 5 to 8
move 9 from 8 to 1
move 11 from 3 to 5
move 8 from 8 to 5
move 2 from 8 to 5
move 16 from 1 to 4
move 13 from 4 to 7
move 6 from 5 to 2
move 2 from 4 to 8
move 5 from 7 to 9
move 2 from 1 to 2
move 7 from 7 to 1
move 1 from 1 to 4
move 1 from 9 to 8
move 7 from 2 to 8
move 1 from 4 to 7
move 2 from 9 to 4
move 1 from 4 to 1
move 1 from 3 to 5
move 2 from 9 to 8
move 11 from 8 to 7
move 2 from 6 to 5
move 1 from 6 to 9
move 1 from 1 to 9
move 1 from 9 to 1
move 4 from 1 to 4
move 2 from 1 to 8
move 1 from 1 to 2
move 1 from 9 to 5
move 2 from 4 to 3
move 2 from 2 to 7
move 2 from 3 to 9
move 1 from 9 to 1
move 1 from 9 to 1
move 5 from 5 to 1
move 19 from 5 to 6
move 5 from 1 to 4
move 1 from 2 to 9
move 1 from 1 to 3
move 7 from 5 to 8
move 1 from 3 to 6
move 8 from 7 to 3
move 7 from 4 to 8
move 3 from 8 to 5
move 1 from 4 to 1
move 1 from 9 to 4
move 1 from 4 to 9
move 1 from 5 to 2
move 2 from 5 to 6
move 2 from 8 to 2
move 7 from 8 to 1
move 1 from 1 to 7
move 3 from 6 to 9
move 2 from 3 to 2
move 1 from 2 to 1
move 1 from 8 to 7
move 2 from 9 to 6
move 2 from 9 to 5
move 1 from 5 to 6
move 1 from 2 to 8
move 2 from 1 to 7
move 1 from 4 to 3
move 3 from 2 to 5
move 7 from 1 to 3
move 10 from 3 to 4
move 3 from 5 to 4
move 1 from 3 to 8
move 3 from 3 to 2
move 1 from 8 to 1
move 1 from 1 to 3
move 3 from 8 to 3
move 5 from 4 to 6
move 1 from 2 to 3
move 4 from 6 to 4
move 1 from 5 to 7
move 4 from 3 to 4
move 1 from 2 to 8
move 12 from 7 to 6
move 1 from 8 to 2
move 2 from 2 to 7
move 1 from 8 to 4
move 23 from 6 to 3
move 14 from 3 to 6
move 15 from 4 to 6
move 1 from 8 to 6
move 10 from 3 to 7
move 2 from 4 to 2
move 11 from 7 to 8
move 2 from 2 to 6
move 44 from 6 to 9
move 21 from 9 to 3
move 12 from 3 to 6
move 1 from 7 to 4
move 1 from 4 to 7
move 9 from 3 to 2
move 2 from 8 to 6
move 3 from 2 to 4
move 17 from 9 to 1
move 3 from 4 to 6
move 2 from 2 to 9
move 4 from 9 to 2
move 10 from 6 to 9
move 1 from 7 to 6
move 4 from 9 to 5
move 4 from 2 to 4
move 14 from 1 to 5
move 4 from 4 to 3
move 3 from 2 to 9
move 9 from 9 to 7
move 1 from 2 to 5
move 9 from 8 to 5
move 8 from 7 to 2
move 4 from 3 to 8
move 5 from 6 to 2
move 3 from 1 to 6
move 1 from 7 to 1
move 4 from 2 to 4
move 3 from 6 to 4
move 3 from 8 to 3
move 13 from 5 to 2
move 2 from 3 to 5
move 12 from 5 to 9
move 1 from 3 to 5
move 1 from 5 to 9
move 1 from 8 to 3
move 4 from 9 to 5
move 6 from 4 to 5
move 12 from 9 to 7
move 1 from 9 to 3
move 1 from 3 to 2
move 12 from 5 to 6
move 12 from 7 to 2
move 1 from 3 to 7
move 1 from 4 to 8
move 33 from 2 to 8
move 1 from 7 to 5
move 1 from 1 to 2
move 4 from 5 to 4
move 3 from 2 to 5
move 34 from 8 to 6
move 1 from 4 to 3
move 1 from 5 to 7
move 1 from 7 to 5
move 3 from 4 to 9
move 2 from 9 to 7
move 1 from 9 to 4
move 1 from 3 to 7
move 1 from 5 to 8
move 1 from 5 to 1
move 1 from 5 to 7
move 1 from 4 to 8
move 1 from 1 to 4
move 1 from 4 to 2
move 3 from 7 to 5
move 2 from 8 to 5
move 1 from 2 to 8
move 4 from 6 to 2
move 1 from 8 to 6
move 1 from 7 to 9
move 29 from 6 to 7
move 4 from 2 to 3
move 2 from 5 to 8
move 1 from 9 to 5
move 2 from 8 to 1
move 23 from 7 to 5
move 2 from 6 to 1
move 23 from 5 to 6
move 1 from 3 to 6
move 4 from 5 to 9
move 2 from 1 to 3
move 5 from 3 to 8
move 2 from 6 to 5
move 2 from 1 to 4
move 1 from 9 to 8
move 1 from 9 to 1
move 1 from 4 to 6
move 2 from 5 to 6
move 6 from 7 to 8
move 2 from 9 to 2
move 18 from 6 to 5
move 21 from 6 to 4
move 1 from 1 to 6
move 2 from 6 to 7
move 2 from 7 to 9
move 2 from 2 to 8
move 7 from 4 to 3
move 12 from 5 to 3
move 1 from 9 to 5
move 1 from 9 to 4
move 6 from 5 to 2
move 17 from 3 to 4
move 3 from 4 to 3
move 1 from 2 to 4
move 5 from 2 to 8
move 1 from 5 to 8
move 19 from 8 to 7
move 1 from 3 to 6
move 1 from 8 to 4
move 1 from 6 to 1
move 15 from 4 to 6
move 1 from 1 to 4
move 3 from 3 to 5
move 4 from 6 to 7
move 1 from 4 to 7
move 10 from 6 to 7
move 16 from 4 to 5
move 24 from 7 to 2
move 8 from 7 to 8
move 1 from 4 to 2
move 6 from 8 to 7
move 1 from 8 to 7
move 1 from 6 to 9
move 14 from 5 to 4
move 9 from 7 to 8
move 4 from 5 to 1
move 2 from 1 to 5
move 3 from 8 to 6
move 2 from 6 to 9
move 2 from 2 to 8
move 6 from 2 to 7
move 3 from 4 to 6
move 1 from 3 to 4
move 3 from 5 to 7
move 1 from 6 to 9
move 5 from 7 to 2
move 4 from 9 to 1
move 1 from 7 to 9
move 9 from 8 to 4
move 5 from 1 to 2
move 2 from 6 to 1
move 6 from 4 to 7
move 1 from 7 to 3
move 1 from 3 to 9
move 1 from 9 to 7
move 1 from 6 to 7
move 9 from 4 to 5
move 7 from 7 to 9
move 3 from 7 to 5
move 1 from 9 to 2
move 6 from 9 to 8
move 4 from 4 to 5
move 1 from 4 to 2
move 1 from 4 to 2
move 2 from 1 to 2
move 1 from 9 to 8
move 10 from 2 to 4
move 8 from 2 to 7
move 12 from 2 to 9
move 6 from 7 to 4
move 1 from 1 to 2
move 8 from 9 to 8
move 7 from 5 to 1
move 9 from 4 to 3
move 14 from 8 to 4
move 1 from 8 to 4
move 1 from 1 to 5
move 1 from 5 to 2
move 3 from 2 to 4
move 1 from 7 to 1
move 1 from 7 to 3
move 2 from 1 to 7
move 3 from 5 to 7
move 2 from 7 to 6
move 1 from 6 to 5
move 3 from 7 to 1
move 1 from 6 to 8
move 1 from 8 to 7
move 1 from 3 to 6
move 1 from 7 to 1
move 4 from 1 to 4
move 6 from 3 to 2
move 3 from 1 to 2
move 3 from 3 to 6
move 3 from 2 to 6
move 6 from 6 to 5
move 1 from 1 to 4
move 1 from 9 to 6
move 5 from 2 to 1
move 3 from 1 to 2
move 2 from 9 to 8
move 3 from 1 to 5
move 1 from 9 to 7
move 25 from 4 to 1
move 1 from 1 to 7
move 2 from 8 to 3
move 13 from 1 to 9
move 2 from 3 to 5
move 8 from 5 to 9
move 4 from 2 to 1
move 2 from 6 to 7
move 10 from 5 to 9
move 4 from 7 to 2
move 2 from 2 to 3
move 9 from 9 to 2
move 4 from 4 to 5
move 4 from 5 to 4
move 5 from 1 to 4
move 10 from 4 to 5
move 22 from 9 to 1
move 2 from 2 to 7
move 3 from 2 to 1
move 6 from 2 to 6
move 1 from 7 to 1
move 10 from 5 to 7
move 15 from 1 to 4
move 13 from 1 to 5
move 3 from 6 to 8
move 1 from 8 to 9

1
2022/inputs/06.txt Normal file
View File

@@ -0,0 +1 @@
grvrnvrnnjljbjqjpqjjvhhzwwrbwwbblrltrrpbbbbqnnqbbbbsvbvmbvmbbrsrqrzrllwbbbqzqrqnqrnrjnnjccdggwqqhrrjcjmjmllgrlglhlclmlvlvsshwwsggmfmdfddgdfftrrczrcczhzppgdgrdggghmmdwwqgggslglfgfcgccmjcjwjrwjrjcrjjsgjjvddpwpgpbbgwbgwwhnhfftbffhpfphhfqfrqfrfnfpprvrsrhrfrllfhhrsrhssvfsvsnvsnsswtwtlthllrjjwddtggzczgcchwcwppfbbdvdrdzrdrvrwwsbsfbssqfsfjsjcscttlztllgjjlbbdsdtssvvvwlvlqqnhqqtdqtddjcdcjjpbphhgtgtqtzqqzhqqtgtvtmvtvrvqrvvfmfmppzzbwwnddzttfpfrrlddbppfqppnwnswwdhwdwjjqljqqthtnhnddgmgcmgcmgcmmfmfttrzzfdzztllmjlllgcgbbcqcvccpnndbdjbjmmzbztzptzpprpddptpprhhvlvmlmpmmljjnnjsjfjjvgjjvzzfgfzfbftbftttgstgstgtpggflfcfqqtctltgltldlzdlzzmmlddnvddzfddppmnpptzptpvttwstwswvwrvvbfbjjjbmjjdvdvrvdddrwrhrzrqqhghhrwhwhrrmppsgpsgszzdfdfwwmtwtvwvgvffmqqqtqntqnnjcncbnbwnnzggrdrqqjbqjjwjqqqwlqwlwzlljhhfsfsqsrqqhwqqwbbqbvvlflrrlglbbjhhjmhjjcmcjcgczcfcgcqqczcnnvjnnlddmpmcppgvgjgddvrrnsnmnqmqgmmnppwgwcgwgssbddgtdgdgmdgmgvvmjmvmjmvvsfssdgdghdggbfbqbdbjbsbmmrpmrprggbllwrwpwtppzvppzsssdnsdnnvnhvvvzvfzfqqnnmlnltldtdvdbdblddsmmlccmlmvlmvmmcsctctrtsrstsbsrshsddlmddmppgsscttnrtrqqcvcwwlnlznnnvcnvvtnvnbnmbmvmppjgjdjtddmpdmdvvmgvvdqdlqlhhzccsggjdjsdsttctjctjtfjttppdzpzzbjbwwmwbblslzslzszlzrrcbrrfggvcczjjtbbdnnggbwblwlbwlwqqfvfqfddrrfccvlllhmhhhrthrthrrnbnzbbpzplphprrrnbbghhnshnhbblqqqvwwffnmnmhhtccpqpvqvbvnvvfnfsnffdjdllwffcddgcgrgjrggchcpcddtbbdtdmtdmmhhtphtpppclcpcvcjvcjjfqfzqqphpnhnrnhhpdhhtfhhbbmqmfmsmvssgqqfssqgglnnqmnmbnmbbllrdrgdrdvrdvdsvvnddgtgddcdqdsqdqbqqlhhwdhdgdcgcdchchrchhpvvpgvgrrfggwfwgmpddbhfngtrwswfszgsggnpsntjpslrpjqsffzrlnbnzdtqpqtjzwlhhgrsrbvnccnsjmzcbqgcbtbqlzhnpnhhrrvqwjwzzvrlcrmjhcscrqhpqmfzbnvcwwqhcjjlnggmpbwztzfswmsbjshnsgfmdlzvzczhrdwgwbghszpnbfpctrshbfhspsczcqcrrqcpwwpfzhjqtpqgjbztrpzrlgfdjbmlwdvlvnfmdzbwsbbhlbszvwcpztlchjrqbmsftltmqpfgdpmdgjvwqqtjsqlfqrwmsnlqgsbqfwsdnfvzthmbplvszfcmlptlcjpnfpjsphsmmjplwjqphgvzbtbjtpttqhlwtgnrjvmvsfsztmsqszzlhqqhfslsvhzgtsssfctzgsqbgdzlpwbsmpcnjqshhhcwqdsdzdhnjfqzqnqdlrpddcgrgldgqbjmdtwgppdczzrjvmcfqjbpjzbtjmgdphlbwnsnpfdqlhwvvmpwzsrztnwvtlbphljmjwsgbphgmwhdmfhpvsmvsjccjhfvqtvfmmlnggncltvtrgmbtfqsvfnlvcmjnjwzcrpjnsgntvhjbtdlptshbhhchqmsprhqzdnfpjqccdfvnzjtlbsmmwvzlwlvmsbrnhqctvtvbfhntdctjnrbcrrlmsnwbbjbcbbgrrhfqwzwwfgvsvgbwnttghtgpspzwzfhffsqjvwwttntnvlwftsfvtttgnprzrzsghvjrdtsfdvzswhmrfcdqsgvrlhzbnvbmjlqrftnnbtwqtvlvwznfbslhdqjbntdgpprfqchjvgvzjssdztjlzwfljjmfvzrbbtczggzqwrnqqgzzcbqjcpfqfrbwtdjrrvbszsjdjcpdfjscsvnltcgwvqsgnhbfgnfnddnpmbzbptrmvqzpvbdpfdvtlmgnnjwflgdbfnmvsdnmlvgcpwflwvdbtbfwtfpsmqsplnzwlwgvbjrhghwrnrswsggbqpdjcjrgbgnsqdvwzzwftvjqgjzzcdvpbbjzpphmbcqmrjvgqwfgrsnqvhwflmhgrlvbpwdcsrlqwfrwppqbrdhwqtvczpclpsbsjcptgblbbsqmbhjjgzwvlcnhnzcttmpjsgchmppgphqlzlcsqcgbbjgtjjvmttdztfdptzgvmpnqrcmpmcdlpnbztllvqbggqbqhlqvdwsrwzsjwfrqvcbvsgfdptmrzpvdfblmhlzrvpmsljlqqzrhlnmwncpfhvqlsbtrjbfcrnfvjvddrhdbbczjdsrdvzlbqrccssdzcpmdsqbprjppfzdwfdswptgzcmjqfhcwsqfqhvrslffqfbcvhdzljzrmtwmfdwzdhhjcmbjtvjhzzwfqhrcslztdbnlwmmhbbbgdscjcdzftnchqfnflnsdqjscfrqpnfbftpzvtmrwncqfqqflschpfnjsjlqcjdjgtwpqhgcnjdmnnvmmpwdspmnrgqrptqwcvbtdwpqlbtwpqgwgfrzlrhtvrvzhmhmwhfdsrhpcczqfltsgtgrfwcvlcvtlhqqwnrqgzpnzbfmzbdwqwbsfvbshrgzqdbgvrhzhzlbqsfzttmsnmrqmwgtzbvdqdrbgcpclzjrhdbjtpcdbbznjgtbwbqrnpvffdmwtrbhhstcmnjcwbbnmpbvmjprtzgcptmtrffwhvfgdljnrbbrblbfbgdwtjrtgqgrpvpgjqrjzczvvlspgdbzftqgqvgdqlglbgvgjdcztznszcwfqhmwbrbjcfstzdcmdsssqfhtzpdgmzjscvbdzgbhhgdqgvfwrzmhdrhlsvlzjjzbzdljcbhncppwrtptjgszlqsrqpzqcsgvdvzmgvwgsncnbffttslphcstqvfwbwzbflmshcbnhpljgqwmmwwzlgpbcqnrtqlwcjcrclfdrnnmvtbfdztdfvtqrsgdptfcfpzpsldhzmrngggfvdqggtlfqqwsldprcffsstnnpmsbbvghdbpprqbssnprdbqclzqtgsrczwcvqwrrfmmfwsndvtvqljwwglrgbphdvvwgctbbmtrbpzqtspgrlhmnhjcdwhwvssgspzjbcfjttjqbdpdmptfzzjcfqljpqddfssmffqprvbptfvdshsdmfmdtmlbnmbmjjjsgmlmwmgcwhbrbgchrstptvdlqgddfzddlzhwjmsvvcjwvqtzjtsctfmzchlbrvlgdzbvdlbfpvhptpltrdmcgjghcpwvwqqnrzdtnmgdncplhdpsgpnbprbgshffwwsdhpgqsbmwdtpnhhltlcqfrjtswcchzvlhdgrmjwhgwppdjqlgmdhwbllqvzrchgclmqdlghjsvmwlflmhhmdzbfjhjnvwphnjbclmdpgflqgtfsmsjslntfcmtbphnrgpdcqtjzjttdtgjmvhzsrfnrjqssvwpcslpfstbpfsrsntmftmdgsqrrsnddqfmchrhtlhmqndvvllnvltdzfphjqnvmcdsgfpcmjftgdpntjzplqljhtthvnbzbzwvfnqsjvnfwhmtbsspjslgfjvdgfjpwrsgqwntntjcqtdgnhnsfwhhqfwbwhdrftj

983
2022/inputs/07.txt Normal file
View File

@@ -0,0 +1,983 @@
$ cd /
$ ls
dir gqcclj
dir lmtpm
dir nhqwt
dir qcq
dir vwqwlqrt
$ cd gqcclj
$ ls
62425 dqp.gjm
174181 hrtw.qsd
273712 pflp.mdw
169404 zlthnlhf.mtn
180878 zprprf
$ cd ..
$ cd lmtpm
$ ls
dir clffsvcw
163587 cvcl.jqh
dir dcqnblb
dir dtpwln
dir fvt
dir hrcrw
dir jdqzmqn
236754 nrdmlj
205959 pflp.mdw
dir qcq
dir rsn
129926 vdgcqdn.sqd
dir zprprf
$ cd clffsvcw
$ ls
6997 dcqnblb.wbh
145711 dqp
159225 pflp.mdw
$ cd ..
$ cd dcqnblb
$ ls
dir dcqnblb
dir gfn
dir lpswsp
dir lvt
dir zprprf
$ cd dcqnblb
$ ls
2020 grpdmd.ggz
dir zpswzfvg
$ cd zpswzfvg
$ ls
206998 zprprf.gnw
$ cd ..
$ cd ..
$ cd gfn
$ ls
277530 rhbvtblc.mvw
$ cd ..
$ cd lpswsp
$ ls
173180 dcqnblb
$ cd ..
$ cd lvt
$ ls
dir hjllwsvl
dir ptbt
$ cd hjllwsvl
$ ls
dir wqnc
$ cd wqnc
$ ls
64695 grpdmd.ggz
$ cd ..
$ cd ..
$ cd ptbt
$ ls
150880 vvbt.gtp
$ cd ..
$ cd ..
$ cd zprprf
$ ls
dir ldzslndn
dir qftt
$ cd ldzslndn
$ ls
dir bwqqsbhg
129454 vbn
$ cd bwqqsbhg
$ ls
108701 zprprf.gss
$ cd ..
$ cd ..
$ cd qftt
$ ls
64268 cvcl.jqh
$ cd ..
$ cd ..
$ cd ..
$ cd dtpwln
$ ls
196215 cvcl.jqh
dir dpwg
dir ldzslndn
dir znnsqqh
$ cd dpwg
$ ls
192388 gmh
47754 grgzh.qdl
99449 hqsh
dir pbmf
50061 pflp.mdw
192902 qcq.pgg
dir rmpvj
dir scgc
$ cd pbmf
$ ls
210083 wpfnwbl.mgf
$ cd ..
$ cd rmpvj
$ ls
125738 nmlnbvrd
226214 zprprf.jnp
114257 zprprf.srs
$ cd ..
$ cd scgc
$ ls
182115 rrc.rcc
$ cd ..
$ cd ..
$ cd ldzslndn
$ ls
201992 qcrm.cpd
$ cd ..
$ cd znnsqqh
$ ls
85635 cvcl.jqh
$ cd ..
$ cd ..
$ cd fvt
$ ls
dir dcqnblb
dir gnc
75864 vfn
$ cd dcqnblb
$ ls
dir dcqnblb
dir lbnflwsh
$ cd dcqnblb
$ ls
269901 cvcl.jqh
$ cd ..
$ cd lbnflwsh
$ ls
33336 grpdmd.ggz
42861 phg.wmc
$ cd ..
$ cd ..
$ cd gnc
$ ls
dir jhjbjsp
dir jjppr
$ cd jhjbjsp
$ ls
96177 ldzslndn
$ cd ..
$ cd jjppr
$ ls
181016 dqp
$ cd ..
$ cd ..
$ cd ..
$ cd hrcrw
$ ls
261376 dtjfpppr.dww
54658 vsrgvw.pfn
$ cd ..
$ cd jdqzmqn
$ ls
52342 dcpndc.vlg
171946 gggpchh.tbb
dir ldzslndn
11156 nbfrfvv.gzw
$ cd ldzslndn
$ ls
107873 cvcl.jqh
216034 gfdjrbz
68844 pqllfrrh.jcf
$ cd ..
$ cd ..
$ cd qcq
$ ls
152886 ldzslndn.ltn
105125 vwplh.vbf
$ cd ..
$ cd rsn
$ ls
15385 hqcmjdgv.jjv
105735 qcq.bzg
58805 snczcsp
26668 vbn
$ cd ..
$ cd zprprf
$ ls
dir chbmq
dir dcqnblb
dir dqp
dir nfspb
89506 zprprf.hnt
$ cd chbmq
$ ls
dir cnjvw
dir dqp
151434 frsvrdnt
dir msztjvcb
240689 qcq.jlh
dir sjzrcg
97312 vnr.zfr
dir zprprf
$ cd cnjvw
$ ls
dir bpbs
252403 cqhtshc
dir djmjhn
10935 fhqmswr
6582 pdwml.ldd
dir qcq
219282 rfmd
$ cd bpbs
$ ls
147582 bnhwsnsj.gdm
61362 cvcl.jqh
152857 vdgcqdn.sqd
$ cd ..
$ cd djmjhn
$ ls
dir bjdbcjbb
dir dcqnblb
dir dqp
dir lgdwtt
$ cd bjdbcjbb
$ ls
110710 cvcl.jqh
252792 hmshctr.lgz
dir mjhtmbj
189745 shsswcgr
dir tfnhp
194940 vbn
dir zprprf
$ cd mjhtmbj
$ ls
dir dqp
dir hbthpcmb
$ cd dqp
$ ls
200832 sbcrz.qgw
$ cd ..
$ cd hbthpcmb
$ ls
55191 ffcntg
$ cd ..
$ cd ..
$ cd tfnhp
$ ls
276825 dqp
161538 gqmr.wgb
$ cd ..
$ cd zprprf
$ ls
287638 dcqnblb.ssp
41274 hgmrvj.mwf
249118 sbb.gsf
105141 wwrg.gqz
$ cd ..
$ cd ..
$ cd dcqnblb
$ ls
1957 btmmc
32386 dtzbzg.dhm
dir mmrbj
98283 ntmhfgtl.pmf
dir zprprf
$ cd mmrbj
$ ls
273194 wnsq
251527 zprprf
$ cd ..
$ cd zprprf
$ ls
27678 ldzslndn.rrl
62866 ljf.fdj
148502 qcq.dlg
dir rvgqvm
179231 tllnmhn.pjp
64033 vbn
dir zcdrj
$ cd rvgqvm
$ ls
dir ntbv
262324 prhgj.szz
dir qbvdh
$ cd ntbv
$ ls
116608 cgv.fvj
175200 swpswq.twt
$ cd ..
$ cd qbvdh
$ ls
160353 sdhfrb.wjn
$ cd ..
$ cd ..
$ cd zcdrj
$ ls
283262 ctl
$ cd ..
$ cd ..
$ cd ..
$ cd dqp
$ ls
dir jfzm
111438 rdrgb.mjf
64194 wgtmqrq
dir zprprf
$ cd jfzm
$ ls
158774 pflp.mdw
$ cd ..
$ cd zprprf
$ ls
215264 sgsstcp
$ cd ..
$ cd ..
$ cd lgdwtt
$ ls
dir qcq
$ cd qcq
$ ls
165461 ldzslndn.vvb
$ cd ..
$ cd ..
$ cd ..
$ cd qcq
$ ls
dir dpd
165044 grpdmd.ggz
82343 ldzslndn
dir mwg
176689 psjcwp.wct
44404 qcq.zwd
$ cd dpd
$ ls
84087 dqp
227386 zprprf.gfs
$ cd ..
$ cd mwg
$ ls
214086 pflp.mdw
dir sjjsdn
225859 wcdt
158892 zprprf.frs
$ cd sjjsdn
$ ls
260121 gplgp.dfn
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd dqp
$ ls
dir hcrwclpg
dir zphd
$ cd hcrwclpg
$ ls
dir cmqntjj
16393 ldzslndn.qbm
91152 qqdtc.zdq
$ cd cmqntjj
$ ls
272266 ldzslndn.pll
$ cd ..
$ cd ..
$ cd zphd
$ ls
165711 chftwcsw.fqw
256871 cvcl.jqh
251168 zprprf.gfv
$ cd ..
$ cd ..
$ cd msztjvcb
$ ls
206231 brzn.lmn
dir dcqnblb
21571 dqp
dir fmn
45779 mlfctz.cjr
288827 pflp.mdw
220578 qcq.fqf
$ cd dcqnblb
$ ls
198121 ghbwgs
93681 nmqhl.vpq
$ cd ..
$ cd fmn
$ ls
29407 mdfws.qvs
$ cd ..
$ cd ..
$ cd sjzrcg
$ ls
155120 ddclvsjr.rpq
136029 ldzslndn.dcm
dir vhzh
$ cd vhzh
$ ls
212446 vbn
$ cd ..
$ cd ..
$ cd zprprf
$ ls
240335 crt.gqh
185363 gnmm.qgh
dir ldzslndn
dir nwl
dir qll
277043 vbn
217796 vtvgpdl.vtm
$ cd ldzslndn
$ ls
273570 cvcl.jqh
68510 fgdmz.hrc
dir npq
dir swjrzzrm
$ cd npq
$ ls
97923 dzcjsqwt
$ cd ..
$ cd swjrzzrm
$ ls
180599 tmpgn.bjf
$ cd ..
$ cd ..
$ cd nwl
$ ls
171833 dlwrfhh.qgn
$ cd ..
$ cd qll
$ ls
219926 dcqnblb.bvn
$ cd ..
$ cd ..
$ cd ..
$ cd dcqnblb
$ ls
dir lvpb
276198 tbgcm.qct
$ cd lvpb
$ ls
142590 bvhjlld
268259 gnjfg.sgb
dir qcq
206220 qcq.zsg
258137 rrsw.dnb
dir tmr
215549 vbn
$ cd qcq
$ ls
dir mmpgd
dir tdsz
dir tmfvsjwc
$ cd mmpgd
$ ls
70793 jwbnpwnn
$ cd ..
$ cd tdsz
$ ls
246310 tdvrhhg.bzq
$ cd ..
$ cd tmfvsjwc
$ ls
103899 grpdmd.ggz
287850 ldzslndn
125930 llhr
$ cd ..
$ cd ..
$ cd tmr
$ ls
83344 fbtfcg.hqp
$ cd ..
$ cd ..
$ cd ..
$ cd dqp
$ ls
dir lbgmcbv
dir nbg
$ cd lbgmcbv
$ ls
81776 wzdzzdp
$ cd ..
$ cd nbg
$ ls
dir mfsgjp
155574 pflp.mdw
$ cd mfsgjp
$ ls
199400 vdgcqdn.sqd
$ cd ..
$ cd ..
$ cd ..
$ cd nfspb
$ ls
262412 csrdtbs
73867 vbn
136389 zqps.hjt
$ cd ..
$ cd ..
$ cd ..
$ cd nhqwt
$ ls
123766 cvcl.jqh
dir dhrtvctp
222086 grpdmd.ggz
dir gzg
26005 lhpmz.tgz
dir mcnjwwfr
117122 msn.gst
$ cd dhrtvctp
$ ls
224079 vdgcqdn.sqd
$ cd ..
$ cd gzg
$ ls
124395 dqp
dir wqdbtqm
$ cd wqdbtqm
$ ls
237354 pflp.mdw
212019 vdgcqdn.sqd
$ cd ..
$ cd ..
$ cd mcnjwwfr
$ ls
92504 cshdztf
dir dctl
dir dqp
dir flcrmhlj
161879 grpdmd.ggz
dir gtt
dir hlbnhchz
220093 mdtdsgvm.zgg
dir twntr
287192 vbn
$ cd dctl
$ ls
dir bbhch
155396 hrrj.jzm
164971 pblqmwj.vdb
dir wnlgfpvf
$ cd bbhch
$ ls
dir dpqtp
dir jvdrcw
$ cd dpqtp
$ ls
174135 gwb.qrb
$ cd ..
$ cd jvdrcw
$ ls
215993 dcqnblb.cqp
200800 stjttf.ngc
$ cd ..
$ cd ..
$ cd wnlgfpvf
$ ls
135978 cvcl.jqh
dir dqp
54018 lbrfmt
$ cd dqp
$ ls
270516 dcqnblb.jqw
dir dqp
144626 grpdmd.ggz
157731 hvcv.rhp
133773 lnnt
76250 vdgcqdn.sqd
$ cd dqp
$ ls
41504 zprprf.cmc
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd dqp
$ ls
dir dqp
dir ldzslndn
236737 mqzcvm.fjh
239746 nhcdz.ncj
dir rpchqq
248824 vdgcqdn.sqd
250937 zrchht.mwg
$ cd dqp
$ ls
203381 qcq.djm
$ cd ..
$ cd ldzslndn
$ ls
dir dqp
dir fptnzlv
dir gmbnpm
dir vhvblt
$ cd dqp
$ ls
19579 qcq.lhg
$ cd ..
$ cd fptnzlv
$ ls
209930 dcqnblb
$ cd ..
$ cd gmbnpm
$ ls
dir ldzslndn
dir qcq
$ cd ldzslndn
$ ls
11075 pflp.mdw
$ cd ..
$ cd qcq
$ ls
dir tdp
$ cd tdp
$ ls
40741 vdgcqdn.sqd
$ cd ..
$ cd ..
$ cd ..
$ cd vhvblt
$ ls
dir lzr
$ cd lzr
$ ls
62245 gbnj.llg
$ cd ..
$ cd ..
$ cd ..
$ cd rpchqq
$ ls
dir bcs
dir dcqnblb
dir fvjzn
dir lrphzrv
$ cd bcs
$ ls
179794 bbn.dzb
242069 cmjdmzjf.zgf
1703 cvcl.jqh
dir gnmhwj
dir ldzslndn
152520 qltpsz.jsj
dir sqqjfps
$ cd gnmhwj
$ ls
dir gvs
201600 hptn.ftf
dir hzrnb
dir qcq
dir sqhl
$ cd gvs
$ ls
152358 zprprf.mlh
$ cd ..
$ cd hzrnb
$ ls
94290 gplsfd
$ cd ..
$ cd qcq
$ ls
91909 vmqd.bmg
$ cd ..
$ cd sqhl
$ ls
238673 vdgcqdn.sqd
262885 zmdvr.nfg
$ cd ..
$ cd ..
$ cd ldzslndn
$ ls
240461 mdz
84303 qtj
$ cd ..
$ cd sqqjfps
$ ls
88753 fwn.tff
$ cd ..
$ cd ..
$ cd dcqnblb
$ ls
dir dqp
189996 dqp.pvp
$ cd dqp
$ ls
dir qvfjz
196506 vbn
$ cd qvfjz
$ ls
209316 pflp.mdw
107459 rwpbh.vpt
$ cd ..
$ cd ..
$ cd ..
$ cd fvjzn
$ ls
241464 cvcl.jqh
dir dqp
dir ldzslndn
dir msp
125 pflp.mdw
131895 vbn
$ cd dqp
$ ls
34019 pflp.mdw
202957 vbn
$ cd ..
$ cd ldzslndn
$ ls
147492 cvcl.jqh
248719 spc.rfv
$ cd ..
$ cd msp
$ ls
184407 cvcl.jqh
$ cd ..
$ cd ..
$ cd lrphzrv
$ ls
dir bbwqmbg
81858 cvcl.jqh
dir dqp
248670 gqqsww.tsn
199141 grpdmd.ggz
dir ldzslndn
34514 ldzslndn.ctw
dir tln
214615 zprprf.fwm
$ cd bbwqmbg
$ ls
129750 flf
dir pvlw
dir qcq
126 sqcqphz.tbm
$ cd pvlw
$ ls
198005 jfvj.hdv
$ cd ..
$ cd qcq
$ ls
dir wgdzws
$ cd wgdzws
$ ls
253522 ldzslndn.qwt
$ cd ..
$ cd ..
$ cd ..
$ cd dqp
$ ls
281993 cvcl.jqh
dir hwqjlwcb
50532 msccz.qgm
102187 trv.tnq
111 wplnmj.bfl
$ cd hwqjlwcb
$ ls
267580 dhjqb.dsb
153195 ldzslndn.jqv
41526 mvwcwc.zsc
$ cd ..
$ cd ..
$ cd ldzslndn
$ ls
58666 cvcl.jqh
79950 dqp.tmc
242217 hns.lrb
dir njswzh
240692 vdgcqdn.sqd
dir zvmjvcdm
52909 zzh
$ cd njswzh
$ ls
149732 cvcl.jqh
dir rnmfd
$ cd rnmfd
$ ls
75368 dqp.hmv
14350 vbn
$ cd ..
$ cd ..
$ cd zvmjvcdm
$ ls
dir jgczt
$ cd jgczt
$ ls
dir qcq
95941 qzvvwshv.jwc
$ cd qcq
$ ls
273942 pflp.mdw
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd tln
$ ls
dir bmcng
1518 lrg
dir vnjfrhp
$ cd bmcng
$ ls
38917 fqcrt
$ cd ..
$ cd vnjfrhp
$ ls
dir dcqnblb
dir dqp
247186 grpdmd.ggz
dir ldzslndn
169216 pflp.mdw
206487 vdgcqdn.sqd
16976 vlsrzjmb.mmc
257938 wjl
$ cd dcqnblb
$ ls
dir dqp
$ cd dqp
$ ls
184133 qcq
$ cd ..
$ cd ..
$ cd dqp
$ ls
dir dcqnblb
31612 dqp.pnt
212283 ldzslndn
61600 vdbfc.ddj
197189 wpv.wff
$ cd dcqnblb
$ ls
62412 tfzllmrj
dir zprprf
$ cd zprprf
$ ls
dir bqnpsl
dir dszrvpzc
$ cd bqnpsl
$ ls
261548 spbsbbsw.cmn
$ cd ..
$ cd dszrvpzc
$ ls
188232 sggpqslr.smn
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ldzslndn
$ ls
dir bgnhd
dir pgvcdzwz
dir qgzhm
$ cd bgnhd
$ ls
56989 cvcl.jqh
$ cd ..
$ cd pgvcdzwz
$ ls
110034 qhgnndv
$ cd ..
$ cd qgzhm
$ ls
247232 grpdmd.ggz
269292 ldzslndn
153843 tpz
dir vnschqwr
162392 wnq.btb
$ cd vnschqwr
$ ls
43005 fvtvzfqm.jvc
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd flcrmhlj
$ ls
245668 dcqnblb.sdj
dir lffj
229909 pflp.mdw
280176 vbn
$ cd lffj
$ ls
116451 jmzz.jdd
dir pjlwb
162815 pmhlqq.snr
226183 zffth
$ cd pjlwb
$ ls
67518 qcq.hjq
$ cd ..
$ cd ..
$ cd ..
$ cd gtt
$ ls
52105 grpdmd.ggz
126869 zprprf.fgj
$ cd ..
$ cd hlbnhchz
$ ls
3064 dqp.lrw
278756 grpdmd.ggz
177208 ldzslndn.wlv
141685 vbn
$ cd ..
$ cd twntr
$ ls
63747 cvcl.jqh
$ cd ..
$ cd ..
$ cd ..
$ cd qcq
$ ls
226858 cwblp.zgp
dir jjqsmfhr
dir rjbqtrq
dir vwmpnbts
141715 wdbhdch
286381 zprprf
$ cd jjqsmfhr
$ ls
dir btmm
dir fqndtlgq
$ cd btmm
$ ls
4031 dqp.lrr
dir fzdd
$ cd fzdd
$ ls
dir vnwpn
$ cd vnwpn
$ ls
dir bzlgsl
dir ztvzrrbv
$ cd bzlgsl
$ ls
9294 ldzslndn.sqr
$ cd ..
$ cd ztvzrrbv
$ ls
256017 cvcl.jqh
$ cd ..
$ cd ..
$ cd ..
$ cd ..
$ cd fqndtlgq
$ ls
271528 ccbmgp.bwd
$ cd ..
$ cd ..
$ cd rjbqtrq
$ ls
122150 ldzslndn
46467 tpdvp.pjf
$ cd ..
$ cd vwmpnbts
$ ls
47518 fcrwfzvm
263343 gmc.lrt
212764 qcq
$ cd ..
$ cd ..
$ cd vwqwlqrt
$ ls
dir psrs
$ cd psrs
$ ls
281998 zprprf.hml

99
2022/inputs/08.txt Normal file
View File

@@ -0,0 +1,99 @@
133120320210233440424211425033311533112110111336536142004454550513525522325223123404213204010312200
201131111014211324423255354022022243226445013613610423653614522135534505055120330313403031333103010
312033232323231244025301315245341424106564334260061464515142114141551050411122254121204214442432210
101223224313414001513045124413405604251532415616200623342234245060512030200002055453441222043022132
302000022010423415300513533001221654231646352603366222420353100303160621313144421120541324031322221
022041343104313414435021243154525050055065506466215004364316065443031303052541012204020300331224312
103341401201343234101335152026143021665443260024145323023321363412215203352344024010350241320230403
113420142141151035404302242616255522460104100534576523546245441245051223305614204355454223220120301
141313120334140413444311032422155464031057323373712672513175353623531154646460010504312302300002224
222122233241135333145102102244620325637577115357373355166254434732406430504542404102101335430322111
303334221050505214133200215501142243567431213624743475716112467711442460620524310041114411011423020
314200333004550151023253063621162447552734266222424315622125733562141045411643325165010440012411104
002041023423222500521530364652321342767176666734452465675417573276212213343035032650010252311440041
424112310115314154624123026322722176144615437667237551164455332134452657635041110204303331153310423
403331525242111322464321027125164326531546671615634451453753666614652523355664316050035035431040223
043240150545010061116502263626227235517673287377662722735257631252161774623714640414211242003124031
120153432445266666010553121747235535567222344854553227754373283562766712275433030145041514430322020
130205252451225625553367153422361135376345652238658565468884466665635712475577163231554521534443142
111112125502543266131422234726554665525278247588365447865236325776254766323137341434403365242323513
303144132003506154604725457356146262354554756268227328243768455722852644644163423635454133132303535
355321430425362320027571672735837582654822875282477453446323242873743335342262324741355251635040132
134315335666154514547724226424352647855667536237263286847676436882327536177762242121655513144251300
540433012152253201644772517187257277883368828477658659796427367852347254442546347411045431414354124
123440236041532033152645165666552487887293658447738333978367787858534683322123676621510536503333401
513523462114216537146475772264724378429935336847846348444575554346687726237537112655265045664650022
152254463440132245722174776775434287876777476649865634494799993998688326736773121545343121065304241
250224151321236513227671833576566739347663376834388478944395578563955424353347453672417622666244155
515223301360505722213752783545553644495694566664938776366634393433784855746658113613537562051065554
554241245610333147211334537367835857366454575934899676895788946595666473766285253431355325406031452
100314521636253352672223432738853968767459797559486648888395749643933624738538781345525612342532041
341462234622615555235573736647638675877393747847457878744844899855446378852378466172227414636330202
345125124225634624432677378235488673587578945954767695474694483979633396738646725252521775306550112
413420352557414334236458423883348897736674897485778466695756868398399557654674634472471146623221025
251143521254271126368347667353953675589776644454498798849645686658369675764886773874127564444411365
221413142252611772737673846553885549867478965666795885777985495763559573589863845361134756354652555
243065641366675316826485533843887969469458797465896675796454946875597936434758642384462157714462066
520553502161266638252882759578566955579648578498775589886979787578896857766344736358531725733564135
424035430516117723442423478595343855468789497988556567558494878666699996375768427758374271236421335
252313015177661777278432468494855844559656687766987679695575558744879656544795683583262246546564621
066230444571526644743382974447835556985988567697575656976987588986595376466888728567376162756500435
466346066733165454546438886894789699679455689766757985688888664759568963398874674733715475614334101
325014552177542688745486585579599747867559596676796865787567755944786444539663262282351475561402534
241163303516225237353826934978454869995779765759887659668665685578986859343646684568651136735352562
450361264326612736655359595445797648876877955597997887987765775498545883744548752574473726565411112
554605215356217343577344399893857478777797855566878769757669857854854856357865565536552164136515351
526446641376374684266375494495458695869978975788699978669887967564769488567376982882762633361324360
131314671231526545866684867949989786895865986986978678997899677764988874736369482822342624761635224
623254034413371684428636874768586849979569867987768799666579796798469744978968758623884477174221325
451620621666445477562568544366499474968796999686779676678989576768596484478933764745243527321126622
454130052341168772645439448775675586969558878998779766779998798589986885955369648636673756137543515
052463667567627485865289577459895546659595768687867979887989666587865576357344373227477771625616331
460630633631764266522893997758984967975685969969798677679989558694657986684466928784764257141450213
624130637644652532575536775488944945689777797679988979876565896659695947897698966634635115577122034
312106635521463635433584476586795448766769568869779667989675669974989668369378542526764316562641343
162151455625714643563689555468449898859656786796979798687579985864586658783373657585741615177725655
522113305657225658843435489885646557577988797667968888669868768989959977879557377455733555272325032
304510566333111422674633384687874565587979787768979689685867565897484896499888736286384551117254613
501463041455354857783745556844585568845776985978966685877875599798784456633539465754543114144204310
033044042511137887672349889484876755578886688778959586777755687684946795536886522746575472552603266
506221035322726455557224463853355996897775558969955685797667999588974556935495475632746634441041151
433136161743725565262636565676447685475989796568778598958657768879849778786859753335661722543205305
265454361556653132263478888989675487694888975877759959776785674478666588788563747772733262666414514
052441631644734262283652379957577654769979687765967795697668686969788694345962866843241632716655446
236003436545632166356247457495793686988694668988898785686844466844799668333966735544674562633412352
521460600027621624875854349394389587767654998655578976768847769685597639387383648267451531624063352
342222114334344716267243334967869638699594976567878976765649455495834476654882454551336614731204621
033566313156263553885434364795389663465876465857797479766958478858465479967473865454116236530266023
312652012603144155543338267594667756579949844587785799854455597889659839838335338227724422251205254
300006533237512225736566526838475448787546947968579975977675656694697397732838257677271224106345603
133143326544516157647526755363599347754745759889457964588954897669586537634253625642342472416641244
154255220262671713413357272553997888597745494647794956965689397737688378433337485552276212554465555
100240040401314462336283253854484757937369955476776566463546476496874852334852883176722554655020500
114224164252562264455188387248845988369836588899857935337746669656565572827235667727764740332042104
210035410165643165676172383567428973379998596753776399638478657839665546428878531777515004325230423
210124643010215635561443542385838474565467799589387569934754637575772733563765332372676641151131504
302221012422133674231332744234367852633548864367379437949776375866557752335873376756770315423300102
332125266633066263556242566636554222886478446383395355568773939525563625678526672212234343222625410
025325451166410144267526457225543863563576656495967865696633785745578788783545643421165350000423343
002055431510265615765734547166486528454663847694453963495886284323368575223225414276066312104153401
355245141260142612771253626632378444477523462347872628387736452238277834561572523626005254261254042
203545210065351052363237141625823577635472367448676276452678742864237273162112414622640501555430121
335510044411666505051763342712375473385677658477545568853568734655885763312211631300144242225254322
420503535251235101224431771412136627846753333256668624663675776462422374227471570160056336045543305
311442220344522144201454355125161416822475756464544562823568565277363143626236634605524051151344323
221042430004563020306242752654674353744234455564453257548654537765566764222366445225313642034222311
410315020300414623613025143245525766347157877736466252545465214236744364172443246502214503112203230
342304354225251006345461616171626576425171512572743837515273314522745717111151266035240243530314400
101402542354002125435251304674647534521162334775342133371111747561164265140621412560624450505304430
011211315525203435452400223603127166746242764515517634515312173434163762164444142306041434112503201
312201041521122523410120106532007714457744313215145447526753371116262403622123305243410143403304001
420143230433241404304622552610552657576751252637557577175144676122663421114064036341501055504120312
321114124142324224151525015553652243236362311234247651266113535462142056365353412114023231401141232
144010233331150422332523034411415500511027722375253755262514425243333354512150011301540445044301243
321223141143321313415515024451144622413543514327723454716501265226013550620005111202312303242203422
220312222242043544521300416060642531526303363025212311016020154415132623214322110011054242222314401
120043213410140522500232142235034335033562221102412305131143065020436150033340525535242031300403012
333011210021031104353104420453564321600565055235040060414452305642301521213234000231332120021102311
213000422032423433105500120521112552552162045443040565055142555024614151234210022135411312102303010
311113213314300134505043355233124354500023350433035532626242646113034040102425400244311432332422101

2000
2022/inputs/09.txt Normal file

File diff suppressed because it is too large Load Diff

140
2022/inputs/10.txt Normal file
View File

@@ -0,0 +1,140 @@
noop
addx 5
noop
noop
noop
addx 1
addx 2
addx 5
addx 2
addx 5
noop
noop
noop
noop
noop
addx -12
addx 18
addx -1
noop
addx 3
addx 5
addx -5
addx 7
noop
addx -36
addx 18
addx -16
noop
noop
noop
addx 5
addx 2
addx 5
addx 2
addx 13
addx -6
addx -4
addx 5
addx 2
addx 4
addx -3
addx 2
noop
addx 3
addx 2
addx 5
addx -40
addx 25
addx -22
addx 25
addx -21
addx 5
addx 3
noop
addx 2
addx 19
addx -10
addx -4
noop
addx -4
addx 7
noop
addx 3
addx 2
addx 5
addx 2
addx -26
addx 27
addx -36
noop
noop
noop
noop
addx 4
addx 6
noop
addx 12
addx -11
addx 2
noop
noop
noop
addx 5
addx 5
addx 2
noop
noop
addx 1
addx 2
addx 5
addx 2
addx 1
noop
noop
addx -38
noop
addx 9
addx -4
noop
noop
addx 7
addx 10
addx -9
addx 2
noop
addx -9
addx 14
addx 5
addx 2
addx -24
addx 25
addx 2
addx 5
addx 2
addx -30
addx 31
addx -38
addx 7
noop
noop
noop
addx 1
addx 21
addx -16
addx 8
addx -4
addx 2
addx 3
noop
noop
addx 5
addx -2
addx 5
addx 3
addx -1
addx -1
addx 4
addx 5
addx -38
noop

55
2022/inputs/11.txt Normal file
View File

@@ -0,0 +1,55 @@
Monkey 0:
Starting items: 84, 66, 62, 69, 88, 91, 91
Operation: new = old * 11
Test: divisible by 2
If true: throw to monkey 4
If false: throw to monkey 7
Monkey 1:
Starting items: 98, 50, 76, 99
Operation: new = old * old
Test: divisible by 7
If true: throw to monkey 3
If false: throw to monkey 6
Monkey 2:
Starting items: 72, 56, 94
Operation: new = old + 1
Test: divisible by 13
If true: throw to monkey 4
If false: throw to monkey 0
Monkey 3:
Starting items: 55, 88, 90, 77, 60, 67
Operation: new = old + 2
Test: divisible by 3
If true: throw to monkey 6
If false: throw to monkey 5
Monkey 4:
Starting items: 69, 72, 63, 60, 72, 52, 63, 78
Operation: new = old * 13
Test: divisible by 19
If true: throw to monkey 1
If false: throw to monkey 7
Monkey 5:
Starting items: 89, 73
Operation: new = old + 5
Test: divisible by 17
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 6:
Starting items: 78, 68, 98, 88, 66
Operation: new = old + 6
Test: divisible by 11
If true: throw to monkey 2
If false: throw to monkey 5
Monkey 7:
Starting items: 70
Operation: new = old + 7
Test: divisible by 5
If true: throw to monkey 1
If false: throw to monkey 3

41
2022/inputs/12.txt Normal file
View File

@@ -0,0 +1,41 @@
abcccccccaaaaaccccaaaaaaaccccccccccccccccccccccccccccccccccccaaaaa
abaacccaaaaaaccccccaaaaaaaaaaaaaccccccccccccccccccccccccccccaaaaaa
abaacccaaaaaaaccccaaaaaaaaaaaaaacccccccccccccaacccccccccccccaaaaaa
abaacccccaaaaaacaaaaaaaaaaaaaaaacccccccccccccaacccccccccccccacacaa
abaccccccaaccaacaaaaaaaaaacccaacccccccccccccaaacccccccccccccccccaa
abcccccccaaaacccaaaaaaaaacccccccccccccaaacccaaacccccccccccccccccaa
abccccccccaaaccccccccaaaacccccccccccccaaaaacaaaccacacccccccccccccc
abccccccccaaacaaacccccaaacccccccccccccaaaaaaajjjjjkkkcccccaacccccc
abcccccaaaaaaaaaacccccaaccccccccccciiiiiijjjjjjjjjkkkcaaaaaacccccc
abcccccaaaaaaaaacccccccccccccccccciiiiiiijjjjjjjrrkkkkaaaaaaaacccc
abcccccccaaaaaccccccccccccccccccciiiiiiiijjjjrrrrrppkkkaaaaaaacccc
abcccaaccaaaaaacccccccccccaacaaciiiiqqqqqrrrrrrrrpppkkkaaaaaaacccc
abccaaaaaaaaaaaaccccacccccaaaaaciiiqqqqqqrrrrrruuppppkkaaaaacccccc
abcccaaaaaaacaaaacaaacccccaaaaaahiiqqqqtttrrruuuuupppkkaaaaacccccc
abcaaaaaaaccccaaaaaaacccccaaaaaahhqqqtttttuuuuuuuuuppkkkccaacccccc
abcaaaaaaaaccccaaaaaacccccaaaaaahhqqqtttttuuuuxxuuuppkklcccccccccc
abcaaaaaaaacaaaaaaaaaaacccccaaachhhqqtttxxxuuxxyyuuppllllccccccccc
abcccaaacaccaaaaaaaaaaaccccccccchhhqqtttxxxxxxxyuupppplllccccccccc
abaacaacccccaaaaaaaaaaaccccccccchhhqqtttxxxxxxyyvvvpppplllcccccccc
abaacccccccccaaaaaaacccccccccccchhhpppttxxxxxyyyvvvvpqqqlllccccccc
SbaaccccccaaaaaaaaaaccccccccccchhhppptttxxxEzzyyyyvvvqqqlllccccccc
abaaaaccccaaaaaaaaacccccccccccchhhpppsssxxxyyyyyyyyvvvqqqlllcccccc
abaaaacccccaaaaaaaacccccccccccgggpppsssxxyyyyyyyyyvvvvqqqlllcccccc
abaaacccaaaacaaaaaaaccccccccccgggpppsswwwwwwyyyvvvvvvqqqllllcccccc
abaaccccaaaacaaccaaaacccccccccgggppssswwwwwwyyywvvvvqqqqmmmccccccc
abaaccccaaaacaaccaaaaccaaaccccggpppssssswwswwyywvqqqqqqmmmmccccccc
abcccccccaaacccccaaacccaaacaccgggpppssssssswwwwwwrqqmmmmmccccccccc
abcccccccccccccccccccaacaaaaacgggppooosssssrwwwwrrrmmmmmcccccccccc
abcccccccccccccccccccaaaaaaaacggggoooooooorrrwwwrrnmmmdddccaaccccc
abaccccccccccccaacccccaaaaaccccggggoooooooorrrrrrrnmmddddcaaaccccc
abaccccccccaaaaaaccccccaaaaaccccggfffffooooorrrrrnnndddddaaaaccccc
abaacccccccaaaaaacccccaaaaaacccccffffffffoonrrrrrnnndddaaaaaaacccc
abaaccccccccaaaaaaaccacaaaacccccccccffffffonnnnnnnndddaaaaaaaacccc
abccccccccccaaaaaaaaaaaaaaaccccccccccccfffennnnnnnddddccaaaccccccc
abcccccccccaaaaaaacaaaaaaaaaacccccccccccffeennnnnedddccccaaccccccc
abcccccccccaaaaaaccaaaaaaaaaaaccccccccccaeeeeeeeeeedcccccccccccccc
abccccccccccccaaaccaaaaaaaaaaaccccccccccaaaeeeeeeeecccccccccccccaa
abcccccccaaccccccccaaaaaaaacccccccccccccaaaceeeeecccccccccccccccaa
abaaccaaaaaaccccccccaaaaaaaacccccccccccccaccccaaacccccccccccaaacaa
abaaccaaaaacccccaaaaaaaaaaacccccccccccccccccccccacccccccccccaaaaaa
abaccaaaaaaaaccaaaaaaaaaaaaaacccccccccccccccccccccccccccccccaaaaaa

449
2022/inputs/13.txt Normal file
View File

@@ -0,0 +1,449 @@
[[[],[],8,3],[10]]
[[[[7],[0,4,6,1]],[[2,1,5,3,6],[]],[3,[10,9,1],2,[10,6,10],7],2,7],[5,[3],7,10,[8,[4,7,1,7,8],[],1,[8,6]]],[5,7,[[5,5,7,2,10],[8,7,10,4,7],[9,4,9,9,1]],[[8],8,5,[7,3,4,6,1],1]]]
[[[5,5,[0,7,6,6,0]],[],0,9],[[[0,7,3,10,5],5],7],[10,[],1,[],5]]
[[4],[2,[10,[5,7,8,7,0]],[4,8,[1,2],[5]],3,9],[[[3,3,3,5,4],5,[],7,[7,3,10,4,0]],9,[3]],[2,0,6,[9,5],8],[[4,[9,8,6],[],5],3,[7,7,[3,3,6],7,[9,4,0,10,6]],10,[]]]
[[2],[3,[[],[1]],[],[0,[10,7]]],[[]],[7,[6],8,[9,0],[2]]]
[[[[],7,8]]]
[[],[[],8,5],[4,9,[[8,4,7,6,9],[4]],3,[[0,3,4,3,1]]],[3,5,[[0,6,4],5,[1,5,6],6,[8,7,1,7]]],[1]]
[[8]]
[[],[[3,3,[7,0,9],1],3],[[[10,7,6],8,0,0],10],[[3,4],[0,10,[1,6,1,5,1],[]]],[[[10,10],[9,7,3]],2]]
[[10,0,4,[1,1,[4,10,5,7],10]],[[],[3,5,[5,5],[],[1,0,4,9]],0],[[]]]
[[[[10,7,1],0],[7,[4,9,3],[0],[]],[],8],[[[6,3,2],[4,6,0]],[4,2,[0,2]]],[[],1,6,2,[2,[10,10,4,9],0,[7,1,0,7,6]]],[9,3]]
[[[[4,4,2,2],[5,0]]],[5]]
[[],[[5,6,[],[7]]],[7]]
[[10,6,9],[[9,4],[5,4,4,[2,2,8],5],10,[[]],9],[]]
[[[],[2,6,[],[4],[0,5,6,7,4]],4,9,3],[],[[[6],7,9],[],9],[[[1,5,0,4],4,[2,9,3,3,7]],1],[10,2,2,[[0,6,8,4],[9,3,8,5],3,5,3]]]
[[],[3],[[[],[],[10,1,2],[],[1]],0,9,[]]]
[[0,[6,[10,0,0,4],[6,6]],[],7,[8,[2,6,8,6,10],5,7,0]]]
[[[6,[7,6,9]],8,[4,1,[4,7,2]]],[[],8],[[2,[0],0,8],1,8,[6,4,1,[3,3],6],[[9,8,4,1],[5,7],9]],[[[3],5],2,5],[9,[[8],3]]]
[[],[2,[4,[6,2,10,7,7],[]]],[7,[7,[1,7]],[[9,2,8,10,8]]],[5,[[0,10,10]],[1],1,[[],10,0,[]]]]
[[[[1],[7,10]],5,9,[[],[1,8,7],0,[2],6]],[],[[7,[],6,[],6],[[1],8,0],[[3,0],[0,7],[2,0,3,6],[9,6,0]],[[0,1,7]]],[0,[7,[1],1],4,10]]
[[7,7,[[],[7]],1,[0,10]],[10,4,8,6,5],[7],[[[2,4,8,7]],[[10,1,6],[6],[5,5,6,8],7,[0,5,2,3,4]]]]
[[[8],[[4,7],[8,10,0,10,8]],0,8,3],[[9],[8],[[1,2],5,0,[7,0],[1,3,10,8]],[0,4,[3,10,0]],[10,[],[]]]]
[[],[8,[9],9,3,7]]
[[6,8,[5,4,[],[8],3]],[],[8,[4,[9,3,7,1],[7,1,9,5,7],[7,4,5],2],[9]]]
[[[[0,7],1,2,[7],10]],[6,7,6,[[3,7,2,7],[10]],[2,[9,9,5,7],[0,4,4],[5,8,2]]],[2,2,8,2],[[]]]
[[],[10,[[0,10,1],7,0,9],6],[[4,6,[1,7,9],7,[5,3]]],[2,[[10,10],[8,0,3,8,2],[6]],2,7],[[6,3,4,1,[4,7,7,2]],0,[[1,3]],[[0,9,3,6],0,[5,6,6,0],10]]]
[[[3],0],[1,1,4]]
[[6,[8,[2,5,2],[6],2],[1,8]],[3,3,7,[[2,10,1,5],[]],1],[[9,[8,6,7,3],[9,9,6]]],[[[],[9],9,6,2],1,[8,10,2],[],3]]
[[[[1],[3],7,[8,0,7],6],3],[],[8]]
[[6,7,[4,[8,2,1,5],8]]]
[[8,[[],9,[4,6]]],[9,[10,[8,7,4,1,2],[3,3,2,10,7]]],[4,[[4,5,2],8,3,[3,4,10,5]],10,10,[[1,10,4,10]]],[[8],[[5],[6,1,0],2,10,2],3]]
[[[10,5],[[0],[7,9,3],[2,7,5,2]],[7,10,[8],6],[[6,6,4,5,9],[3],4]]]
[[3,6],[1,[],3,9,[]]]
[[9,[],6,[],[[3,8],[6],7]],[[],[0,9,5,[9,1,9]]],[[9,10,[8,3,7]]]]
[[],[1]]
[[0,[],[5,[],5],[[]],2],[5,7,9],[1]]
[[[[9,9,2,9],[0,6,4,5,2],[8,2,2]],[0,7,4]],[5,9,[0]],[[10,[9,5,10,4],5,0]]]
[[[[9,6]],[],[[9],10,7,4,[9,0]],5]]
[[[[7,2,1,6,6],9,[1,7,8],8],[5,[3,8,8]],[[5,0],[2,1],[3,0],5,[7,7]],[[],[4,6],[4,6,5,4]]]]
[[7,7]]
[[9,1,[[5,10,6,7],[4,6,5,10,1]],[[4,7,9],5,[6]]],[4,[2,[2,2,5,3]]],[[3,[4]],[],2]]
[[7,[0,8,0,[10,8,10]],[1],5]]
[[3,6,6,5],[8,[[4,5,6],5,[8,3,0,1],[10,5,2],[5,0,7]],[],4,[[0],[]]],[2,[4,[6,5,6,9,0],[],[3,0,2,9,8],[10,4,9,5,1]],7],[[[7,3,5,2,7],[2,2,5,6,9],[6],0],[8,8,7,[2,1,3,9]]]]
[[[8,7,[7,4,8]],[]],[],[],[],[2,[[1,8,5,0]]]]
[3,3,5,9]
[3,3,5,9,6]
[[],[[[],[3,4,0],9,[],1],0,2,[0,[5,2,6,8],[9,4,8,8]]],[[[10,6],[5,6,4,3],[],5,[4]]],[0],[]]
[[[5,9,7],2,[[2,0,7],[2]],10],[[[9,6],[3],4,[],[9]],0,[[9,5]]],[1,[[10,4,6,9],5,3],1,[10,[9,7,0],[8]]],[[0,[9,7,5,10,4]],0,0,2],[[[]],7,2]]
[[[1,6,2,5,4],7,[8,8,9,9,[6]],[[],7,[],[10]]],[[[1,0,0,5,5],8,5],[[],1]]]
[[5],[],[[[7,4,8],9,8],2],[10]]
[[10,1],[[[0]],[]],[[5,[9,1,0],[],8,4],1]]
[[[[10,0],6,[8,6,7],1,2]],[[[7,3,8],[],[],3,[4,0,6]],[10,[6],9],[[9,1],[],[5,1,3],[],2]],[[1,[2,8,6,6],[6,9],[3,8],[4,10,8]]]]
[[[4,10,8,6],5],[8,[[3,4],[2,0,1,10,9],6,[4,10,10,8]],[9,[2,9,7]],[7,[0,9,6,1,0],6,5]],[]]
[[3,[[1,10,1,1,8],8,[7,6,0],[6,10,5,3],[2,3,2,2,6]]],[]]
[[[],[[1,6,3,8,9],[7,0,2,4,3],[4,5,3,6],3,[2,2,10,9,0]],3]]
[[],[[[8,8,10],[10,2,7,8],[1,0,7,4],[2,8,8,2],9],8,10,10,1],[[[3,2,6],[0,2,9,9,10]],[6,[],4,0,[5,4]],[[4,1],0,[],3,5],7,2],[]]
[[[0,[7,1,6,4],[2,3,4]],[],[]],[[1,[8,4,2,9],8,9],6,[8,10]],[5,[[3,10]],5,[]]]
[[0,10,[],1],[],[4,8],[],[]]
[[[5,3,[0,10,1,1],[],[]]],[6,8,[]],[4,2,[2,0,[1],1]],[],[[[4,8,0],[0,7,9,8,6]],[[0,0],[9,10,3]],[[2,4,2],0,2,10],6,[5,[4],[4,2],[2,4,4,0,10]]]]
[[[[1,9],[10,2,9,2,3],[8,7,4,8,4]],2,[7],[[0,1,5,2],5,5,10,10]],[[1,10,4]],[5,[],[[3,1,3,6],[7,1,9,1],[0,3,8],6,3]]]
[[2,[]],[[[9,0],[3,9,6,10,9],3,3,5]]]
[[[0,1,[3,9],9]],[[7,[1,10,3,3,3],2,5],2,8],[10,10,[[0,3,8,0],10,[2,4,0,4],3],[[2,6,4,3,1],4,[8,9],[]],[[],[1,5]]]]
[[[],9]]
[[],[0,5],[[4,8,[10],3,[8,9,4,4,4]]]]
[[[6,[3,1,1,4]]],[0,[9,[9],6],[[],9,[],0,[6]]],[8,[0,9],[2,10],9],[[8,[1,10],[9,0],[6],9],[4,[],[10,10]],[[4,2,8,8,10]]],[[7,[4],[3,8,0,3,0]],1,[8,[2,8,5,2],[0]],[10,[2,0,2,4,6],2],[1]]]
[[[7,[],5,[8,8,10]],4,[1]],[[7,10,0],3,[7,[3,10],[3,8,5,0,7]]],[6,[[2,5],8,10,[2,8,5,1],[4,7,2,4,0]],2]]
[[4,0,10,1,[[1,6],2,9,10]],[[[3],[3,0,8,9,7],[5,6]],[[4,2,10,8],[1,9,10,6],6],6,[[5],4,[],[],1]]]
[[4,[],[8,3],9],[[],[0,8,[6,9,6],[10,6]],4]]
[[5,9],[1,5,6]]
[[3,[8,[0,5,7,4,2],[4,4],[7,10,3,1]],0,4],[[7,[0,8,6]],[[3],[7,9],[],[3,6,4]],2,4]]
[[10,[]]]
[[],[7,[[0],[10,4,0,1]],3,[[7,0],[1,3],8,[6,0,3,1],1],[10,5,10,9,[]]],[3,6,4,5,3]]
[[],[[[2,8,1,9,8],[7,0,1,10],[9,0,4,7,6],5],4,[]],[]]
[[0,5,5],[2],[[]],[7,[[1,0],[4,9],5]]]
[[10,5],[],[4,[],3,0],[3,3,9,[]],[]]
[[],[[[8],[1],7],4,2,[1]],[1,10,5,[2,3]],[[8],[[5,6,6,3,0],[2,1]],3],[2,7,[10,[],[0]]]]
[[[3,5,[5],[8,8,3,7],9]],[],[0,[],0,3,7],[1]]
[[2],[[[9,9],[0,7],8,[]],5]]
[[4,8,6],[[5,10],[[2],8,[],4],[[10,7,6,5,10],[3,8,7],[3,1,0,2],[8,8,7,1,5],8]],[6,8,0,[[8],4,[1,0,0],2],[[2,7,6,10,1]]],[1,[0,5]],[2,[],[],4,[[4,5,9],[5],4,[1,1,9]]]]
[[[4,8,4,[5,0,8],10],0,[[10,2]],4,0],[[5],4,5,[[2],[5,6],[1,2],5,6]],[[[3,5,2,8],[7]],[3,[6],[1,4,6,5],[3,0,6,8,2]],9,2,7]]
[[],[],[7,2],[[]]]
[[6,[[8,6,4,9,0]]],[[5,[9,6,2,4],[],2],5,7,[[1],10,[0],[8,5,4]]]]
[[],[[[7,8,4,9]],[2,[10,5]]]]
[[0,2,2],[[[8,6,0,9],[],6,8,[6,1,5]],4,4]]
[[7,7,[4,[2,7,6,8,4],[5,9],8,[6]],[1,1,0,2],1]]
[[[6,1],[],[]],[[5,9,[0]],[[2,7,6],4,[5,10,1,5],[],7]],[[2,[9,0,9,10]]],[6]]
[[3,[3,3,6,[8,0],[6,4]],2,0,[[5,0,4,1],1,[0,7,6,6,7]]]]
[[],[5]]
[[[[1,10,1,5],[2,1,0,4,10],[4]],[[0,6,3],[4,1,6],9,7],[[7],[5,6,8],5,4,[10]],1,[0,[9,4],9]]]
[[],[3,[],5],[]]
[[],[[],[3,5,0,7],[1],2,10],[3,[],0,[[9,0],[0,0,2,5,9],[1,6,2,6]]]]
[[5,[7,7,[1]],[[],3,[2,8,7],[3,9,6]]],[0,[[7,10,1,3,8],5,[5,4,3,1,9],[2]],2,[[5,10]]]]
[[[[10,3,8],8,3,2,[7]],2,[[5,5,2,4],7],6],[7,0,[6,[4,9,9,5],[3,1,6,2,6],5],[1,4,2,9],[8,8,[10,4,10,9],[3],[2]]],[]]
[[],[[4,6,[7,6]],[],[]],[[[],0,2,[7,4,0,9],[4]],[],0],[]]
[[5,6,[10,[8,10],[],10,[10,0]],[1,[8,4,6,2]]],[],[[[8,10,10,1]],[],[4,[10,9,7],10]],[[],[[1,10,4,0],[]],[6,9,[4,2,4],7,0],[7,[4],[8,0,7,8,4],[3,5,5,3]]]]
[[[],[[10,0,3,2]],7]]
[[[[],1,[8,5,9]],2,[[1],[9,3,1,2,2],5,2,[]],9,[3,[],[2,1,7],8,[0,1]]],[[[1,6,1,6,5],[2,10,2,1,7],[0,6,0,4,2]],[],3],[8,10],[[[10,2,7],2,7,[]],5],[[6,1],[8,[],[3],[4]],6,8]]
[[[],10,6,7,[4,9,[9],6]],[[]],[[],[6],8,0],[[[10],[8,8,3,8],8],[7,[]],[]]]
[[[[10,0,8,1],[7,6,6],[6,9,9,0,10],[7,4,3]],[[9,10,3,4]]],[[1,[0,3]]],[5,1,2,[9,[],[0,4,10,10]],9],[[9]],[7,6,8,0]]
[[[[4],3,2,[]],[9,[],4,6,[5,1]],2,[]],[[6,[6,10],[],[],[6,6,10]],7,[5,7],[[9],4,[6,10,0,3],[]]],[[2,[1,8]],3,[9,[0,6,10]],[],3]]
[[7],[7,[[7,8],[0,7,1,4]]],[10],[10]]
[[],[],[[[9,3,4,2],[4,5],1,[8,0,7,8,4]],6]]
[[[4,[],[0,0,3,6],2],9,[],7,0],[[],9,[],[],[0,0,1,1,[5,5]]],[3,10,[8],2,[5,[],5,[2,3],5]],[[[10,4,9],[10,9,10,0],[4,7],[10,2]],3,[0,2],10,1]]
[[[],6,[],[2,5]],[[[7],[6,6],0,5],[4,4,[8],2,[0]],8,[4],1],[],[8,1,9,[10,[9,7,2,0]],[]],[10]]
[[8,[],2],[[[3,9,5,9,2],[2,3,10,6]],[5,[6,5,10,1],[7,9],[2,10,3,7,10],[4,0,9]],9,0],[1,[[7,6,1,4]],10,9],[],[[[3,8,7,7,6],[2,9,4,5],[10,1,5]],3,[6,8]]]
[[5]]
[[8,0,3],[[[],[2,5,7],3,7,[5,10]],[8,5],0],[7,[[3],[9],0,9],[],[[],8]]]
[[8,[4,[2,6],2]],[],[[[5,3,7,8,6],[2,9],2,[],[9,4,8]],5],[9,[[7,10,3,10,1]],10,9,0],[[3,7,[0,5],3,3],0]]
[[],[],[1]]
[[[2,[9,8,0,1,7]],[9,10]],[10,[[],[9,5],10],7,2,1]]
[[4,[7,8,7,[5,5,1,1],0]],[[1,[9],[0,3,0,8],[5,2],1],1],[[[4,5,3],[3,10,3]],5,5,[[8,0]]],[[[],5,[0],3,7]],[[2,[5,4,1,3],[0,7,4,10,2],1,7]]]
[[0,[[4,0,8,0]],[[2,2,9,4,2],[],[5,4,3,1],6]],[],[8,8,10,10,3],[[2]],[[9,4,10]]]
[[5,[2,0],10],[9,7,[[],8,[8,1,2]]],[[],[[5,10,7,4],[3,1],[7]],7],[7,8,10,2],[[],[]]]
[[[7,2],10,2]]
[[1],[[5,2],[[10,3,3,8,7],[],2,5]],[],[[[7,4,8],0,[1],8,6]]]
[[7,10,[9,[0,5],0,[8],0],4,[[6],0]],[],[],[[0,2,[7,4,9]],[3,6,8,[1]],10]]
[[[6,3],[[7],[1,6,3,5],3,[]],[[10,1,1,5],3,[]]],[[[3,4,6,0],[1],[1,10,4]],[],5]]
[[],[[],[5],[[]],3,6]]
[[4,[1,0],[[10,2],4,[6,1,0],[4,4,3]],[[10,9,4],4,4,[1,9],[7,0,0]],[]],[[8,3,[8,10],4]],[[1,[],0,9,4],3,5,[]]]
[[[[7,10,0],8],5,[4]],[],[[6,[10],[6,10,7,5,9],7]],[]]
[[],[2,7,[5,[5,7],[3,8,4,3,7],[]]]]
[[],[7,9]]
[[3,[],[[5,9,7,2,3]],3,3],[[],9,[4,[7,6,9,5,8],7],9,2],[],[[7,[8,9,7,5],3,[5,2,5,9,1],[7,4,3,10]]]]
[[[[8,5,6,0,0],[9,7],9],[[1],3,1,4,0]]]
[[2],[0,1,0,4,[10,[1,8,7,5],[2,9,3],5]],[0]]
[[],[[[9,2,9,0,0],[2,9,1,9],[8,4,4]],[[6,5,8],0,[0]],[10,8,[9,9,4,6],8]]]
[[[4]],[5,[9,[6],[0,2],[],0],[[3,4],[3,6],[7,3]],[[9,7,4,7,6],[8,4,1],[8]],[]],[],[6,2,[[5],9,10],8,0]]
[[7],[5]]
[[5],[[[8,4,7,2,8],[8,7,3],6,[],6],1,[5,[6,5]],7,7],[[10],[],7,[8],[0]]]
[[[]],[6],[[],8,7,[3],[4]]]
[]
[[],[[[6,8,0,8],[],8],[[5,1],7,8],1,10,[8]],[3,5,[[9,6,3]]],[[2],3,[[4,9],3,6,2,[1,0,8,5,4]],7]]
[[[8,[7,9,7,4],4],3,[7]],[[[10,2]],4,4,[4,[7,4],[4],1],5]]
[[[],[[8,3,5,2,7]],[[],5],[],[9,2]],[5,[5,5,[5]],[]],[0,9,9,[]],[[5,4]],[]]
[[0,1,[1],10,4],[[[10,1,8]],9,0],[3,[0,2],0],[9,0,10],[]]
[[[[2,1,0,0,4],[],0]],[],[0]]
[[7,7,10,[]],[3,[],[[6,10,7,4],0,9,[0]],[[10,2,7,6],[9],8,4,[3,5,6,0]]]]
[[],[4,[9,6,6,[0,3,1]]]]
[[0,4,[[0,8,6,4],4,7,10],[8,[10],2,8],2],[6,[[6,3,6]],4,10],[2,6],[],[[],[[2,7,1,1],[10,4,7,1],[6,10,4,0]],6]]
[[[2]],[[[9,4,5,2],5,7,[],[]]],[10,8],[3,8,[6,[0,10,10,0,2]],[[5,6,6,10],7]]]
[[8,[[7,6],[8,1,7]],[],5,2]]
[[6,7,[2,7,[7,1,8,5,1],1,5],9]]
[[1,[],1],[],[7,[[2,10],8,[8],[10,1,9,4,10],[1,9,5]],[[9,4,9],[2,2,1,3,4],0,[8,3]],7]]
[[[4,[10,9,9,2],3,9,4],[1,10,4,8,4],6,4],[7,1,[3,3,9]]]
[[[[2],[6,7,4,1],[9,3],1,[5,0,9,4]]],[[[2,5,0,0,1],[3,3],[9,1],9,1],9]]
[[],[[1,[3,6,7,4,10],[7,2,6,0,6],[7],6],5,5],[[[5]],2],[[[3,9,4,9,4]]]]
[[[3,[3,0,9],9],[[10,9,1,8]],[6,8,[6,7,5,10,4]]],[[[],2,[],[9,3,8],8],[5,0,2,[],[0,9,4,3]],[[],1,8,1,0],[]],[[[4,7,8,6,2],6,9,[1]]],[4]]
[[[[],8,10,[6,6]],0,0,[10,[],[0,2,8,3,7],[7,5]],[[0,4,0],3,10,2]],[4,[],0,[],6],[[[7,8,0],[7,5,7],[10,4,3],[1,5,2],9]]]
[[],[[[6,10],7,1,0,[]],[[9],[8,9,9,10,8],0,8],2]]
[[10,0,4,[[0,2,10],[9,2,4,7,7],[5],[9]],[[3,2],[2,9,10],[3]]],[2,1],[10,[5,[2,8,2,4],6,4],4]]
[[8,[[4],[2,9,10,6],0,4,6],[[7,5,3,0],[9],4,[7,5,10,10]],[]],[]]
[[[[]],1,[[],[10,7,2,1],[6]],6]]
[[[[1,6,7,3],3],[1,[7,0,6],7,4,[7]],[2,5],0],[[],[[4,5,3,4],5],[7]]]
[[5],[[],[],5,[[8,3,3]],[[],3,8,9]],[[0,[0,2,9],[2]],[[8],4],[[0,3]],[[6,4,4,3,2]],[[0],[],[0,9,10,1],8,8]],[2,[[],[7,7,0]],[[5,7],[8,2,8,1,5]],[[9,2,6],[1,5,9,1]]],[[[2],[]],[8,7,5,[2]],[[2,1,8,1],5,4,6,[0,5,6]]]]
[[],[1,6,10,1],[[8,9,[3,8]],10,7,[[0,8,6,7,10],[7],[1,0],2],9],[[[4,1,0,10],1,4,[8]],0,[4,10,9]],[8]]
[[[[4,8,9,3],6],5,[],5],[]]
[[[10]],[[],8],[[[6],7,9,[6,6],10],[8,4]]]
[[8,5,3,[],2],[8,[8,[0,0],5]]]
[[[1,0,[],[8,8,3,2],0],2,2,[10,[7],[2],7]],[10]]
[[1],[0,[[6,7],[1,10,7,6],[1,8,7,4],10,5],5],[[4,0,[7,0],[8,3,8,6]],[[2,4,10,8,6],3],8,[]],[[4,[9],[7,4,10],[4]],[3,[6,6],[],5],9,[]],[[[6],[2,1,1,3,5],[2,9,3]],6,[[1],[5,7,5]],[[4,3],[8,2,6,4,6],0,5,[5,8]]]]
[[],[[6,[1,0,0,9],1,6],[[4,9],0,1,7,[2,2,10,7,3]],1]]
[[],[[[4],1,10],[],4,[[9,4],0],[[9],[10,1,10],10,2]],[8,7]]
[[[],7,[[8,4,9,2],[2],4,9]],[[[0],5,[],10,[]],[3,[1,9,9,2],[9,10,0,0]],[7,9,[8,7],2],[9]],[9,[[9,4,6,8,10],8]],[[[0],5],10]]
[[7],[0,6,[[6],[],3,[3,8,6,2,8],6]],[9,6,0]]
[[[[4,4,7],[6,7,2,2],[]],1,[[],7,0]],[[5],[2,2,[3]],[6,2,4,[]],[[3,8],1,[8,6,0,10,5],[8,10,6,1]],3],[8]]
[[0],[[10,[],[10,4,7,3,10]],[[5,9],7,5,8],9],[9,0,5,1],[]]
[[0,0,[[6,10,1,5],[8,0,4],10,[10,9,1,5]]],[[4,[2,1,1,5,4],[5],[]]],[3,7,0,[],10]]
[[3],[4,5],[6,[4,5,[]],5,4]]
[[[[6],6],10],[]]
[[[],7,[[4,3],[7,3],1],[4,[7,6,6,3,9],[2,2,0,8],2]],[1,5,[[5]],[[0,2,5,2]]],[[[4,8,10,0,3],[6,1,8,1,4]]],[],[1,[[],[],2]]]
[[9,[]],[7,[[3,0,2],[],10,6,[10,7,8,4,6]]]]
[[7,6]]
[[8],[2],[6,1],[6,[4],[],[4,8,[5,2],5]]]
[[],[[[1,9,0,1]],3,5,[6,[3,4,3],5,[6,3,7],[2]]],[5,[[3],0],5,[],5],[7,[[9],10],4,9],[]]
[[[9,[8,5,4,8]]],[3,[7,[6],3],2,[5]],[[[1,8],[6,6,5]],6]]
[[2,[[2]]],[10,6,3],[[[10,4],0],[],[5],[],[0,[10],[1],[1,2,7]]]]
[[[[],[],6,[10]],[],7],[3,[10,9,2,[]]],[5,[[10,10,2,7,0],6,[]],[8,[0,7]],[[0],1,[9,10],4,2],[]],[]]
[[[9,[5,4,6,9,5],[10]],[[5,9],0,6,5,10],[5,[2],[4,9,4,9,0],[5,4],[0,1,3,6]],3,[[3,9,7],[6,10,0,0]]],[[7,8,10]]]
[[[3,[4,0,0,9,8]],2,0,[6,[5,7]]],[[9],[],4,0],[6,2,[9],[10,[5,4,9,10],6,4]],[9],[6,6,[[7],[6]],[[8,0],5,10]]]
[[],[8,1,0],[5],[9,5,[6,[6,10,6]]],[]]
[[8,7,[5,1,[4,1,3],[8,1,0,8,2]],3,0],[[[0,1,3,1,1],[9,7,2,4],4,6,4]],[10,5,7,4]]
[[7,[]]]
[[0,7],[],[],[0,2],[0,2,[5,5,[4,6,3,10,0],0],[[5,1],[8,0],[5,7,5,0],2,4],[8,[],[10,2,3,4,8]]]]
[[[8],[2,10,6],9,2,[5,[],5,[6,0,4,5,7],5]],[7,1]]
[[[],[[9,7,1,3],[6,3,2,7,6]],[7,[6,9,5,0,9],3],5,[]],[],[[[3],[0,7,1,7]],[0,[10,6,2,10,4],[5,8,0,6,7],0,[]],6,9],[[[4,6,0,0,2],7,[9,7,7,7,0],8],6,[[],[0,3]],8],[[9,[1,10],2],4,[[0,4,10],[4,7,8]],[[2,0,0,9,8],[4,2,9],[5,10],1,[8,4]],3]]
[[]]
[[[[6]],4,8,[],6]]
[[],[1,9,[[],9,[10,7,10,9,9],6,[0,10,1,4]]],[3,[8],2,9],[5,[4,7],[4,[8]],5,6],[[0],[10],[]]]
[[[[5,1,10,5],[2,10,6],1,0,1],[[1],3,[],2,7],4,4,6]]
[[3,[[7,3,0,6],7,[1,4,5]],[[4,7],[0,6,10,2,9],[],[4,2,1,9,7]],[9,10,[10],1,9],[]],[8,[],[3]],[[[3,2,6,1,0],4,[4,9],[3,1],3],[],[[0,4],[4,2]]]]
[[7,5,1,10],[2],[]]
[[],[[],7,[],9,[[0,9,4],[8,0]]]]
[[3,9,0],[[[9,0,7,4],[1,6],9],10,[3],9,[0,[4,7,4]]]]
[[5,3,[1,[8],0,9],1],[[[8],8,8,8,[6,7]],4,0,[4,0,9,[3,8,8,8],10]],[[[],7,[8,8,1,5]],8,3,4]]
[[[9,[8],[10,3,10],7],4,3,6,[8]],[[]],[8,[10,10,[]],[4,[6,9,3,10,6],8,10,2]]]
[[[[3],[5,0,9],[],2,[4,1]],[7,8,3],[10,[1,4]],[[0,7],[6,4],7,[10,0,0,1]]],[[[5,2],1,[10],10,[3,5,6]],[[],[0,6,2],[0,10,0,1,3]],[[],[1,7]],[1]],[],[],[9,[7],2,[[4,5,4,0],[8,1,1]]]]
[[[],3],[3,[],4],[5,4,6,[]]]
[[2,[8,2,[4]],5,[5,[9,1],[10,6,10]],9],[10,[5,8,[],[5],[]]],[[],1,[1,[7,6,5,0,4],[6],[5,5,10,5,2]],0]]
[3,9,10,6,3]
[3,9,10,6]
[[1]]
[[[[],[],[10,8,6]]]]
[[[5],[10,[3,10,4,1],7],5,[3],[]]]
[[],[[7],[[7,8,5],[6,10,4],9,[0,10,6]]],[[[8]],[5,[],[2],[6,5,0]],[[10,1],10,[],[9,1]],[5,4,[4],[],10],[5,[7],[10],[2,10]]]]
[[2,9,[[9,7],[],[4,6,3],[0,6,10,2,10]],[[6,1,1,1,4]]],[10,4]]
[[[],[6,8,1]],[[[7]],5,6,[0,2,2,6],[]],[3],[[4],4,5],[1,[[9,10],[1,5],4,[6,7]],0,6]]
[[[7,9],5],[2,[5,9,7,[7,2,9]],[9,[8,7]]],[3,[[],10,4,[7],3]],[1,[[],5,0],5],[[],[[],5,0,4],2]]
[[[[4,3,0,10,3],[6,1,10],4,8],[8,[],[8,0],10,[]]],[],[1,9,4],[10,8,[5,[9,8]],3]]
[[6,8,[[1,4,10],0,7,[10,5,10]],[[10,8,9]]],[9,[9]],[9,[3,1,[],[1,1],8],7]]
[[],[5,8],[7,[7],[[3,6,2],6,0,[2,7],[6]],[10,[2,10,8,6],[2],[],[8,10,10,3,4]],[[8,5,8,8,10],7,1,[10,10,8],[3,5,4,3,3]]],[[[],5,10,[1]],4]]
[[4],[10,6]]
[[0,10,4,[9,10]],[],[1,8],[9,7,[2,[5,4],[10],[7,1]],0]]
[[[],[5,[4,10,2],4,[10,8,10]],[]],[],[4,[4,6]],[[],[2]]]
[[1,5,[[4,2,5],[],[1,9,4,7],[10,6,2,3]],[[9,2,0]],0]]
[[2,[8,7,[9,0,0,9],[0,8]]],[],[[3,6],[[1,8,0,5,6],5,2],0,6]]
[[[3],[[1,6,1,10,0],[7],[9,2,0,5,9],[1,10,5,8],[8,6,2,6,5]],5,1],[]]
[[[1],8,3,7,10]]
[[[[1],[9,2,0,6],6,[5,4,7],[1,9,4]],7,0,[]],[2,4],[[9,9,[10,5,5],6],3,0,[[1,8],[],10,0],10]]
[[10,4,[8,[3,6,1,1],7,10],[],[[2,6,6]]]]
[[2,4],[[[2,0,8],[2,0,6,8,3]]],[[[5,1],9,[0,4,6,4,4],8,1],[1],9,[],5],[6,4,[[1,5,7],3],[[9]]],[]]
[[],[[[],4,[9,2,9]],[[4,6,3,6]],[1,8,2],7],[[[3,1,5,5],[]],9,6],[0,4,1,6,0]]
[[[[0,10,1],[2]],2]]
[[[3],[[],4],1,8,2],[[2,[6,10,1,8,0]],0,[8,[],[10,9,7],[]],2],[[[4,4,2,6],[],7],3,8,10,3],[]]
[[1,[6,3,[8,6,4,4],7],[7,8,[3]],1,2]]
[[2,[0,8],9],[[[0,3,0,4,8],[2],[10,4,1,4]],[],[5],8,5],[0,[6],10,2,[1]]]
[[9,10,2,[[0,7,5,0],2,[2,10,9,8]],[[6]]]]
[[[4,3]]]
[[[[8,9,3,3],[],[10,1,3,1,8],8,7]]]
[[[9,[0,1,7,3,4],9,9],[],[8]],[[0,[9],[3,6,3,0],7],[9,4,0,[8,1,2,8],8],[2,8,[4,5]],[8,0,[9,9,7]]],[[0,[8,6,7,7,4],2],[7,[1,2,7],[7]],9,[[4,3,4,2],[1,7,3,1],9],[7,[5],[9,5,10]]],[]]
[[8,[0,[3,0],4],6,[[8,6,5,3],[4,7],0]],[[3,[7,0,7,2,6]],[[0,0],[],[0,5,0,9,8]]],[]]
[[4,7,[7],6,[8,[]]],[]]
[[],[[9,[10]],[10]],[9,1,5,[0,7],[9,6,[6,0,4],[10]]],[[[4],[1,0],1],9,3],[[[9],1,[],[7,0],2],3,[[5,10,9],0,3,[7,9,10,5,0],6],[6,3,[],6,[3,3,6]],[[9],[2,1,7]]]]
[[[[0,5,8,5],[5,5,6,3,6],[]]],[5,4,[],[],[[6,4,3,4]]],[[[9,3],[]]],[]]
[[[7,[3,6,3,8,2]],6,7,9],[6]]
[[5,[[1],[7,4,10,4],4,[8,3,0,2],[]],5,[9,[8,2,10,4,3],5,6,3],6],[[],[3,7,[5,1,2,1]]],[[[2,3,8,5],[0,4,4],10],2,[[1,4,2],5,8,2,3]]]
[[[[8,6,8,2],[1,8,4,4],7,[5,4,10,7,4]],[[7,2,5]]],[3,10,[6,[1],[]]],[6,[],3],[[[7,0,0],9,4,3]],[0,[1,[],8],7,3]]
[[[1,6,[7,1,3]],[[8],[8,8,9,1,1]],[[6,6,1,3],[2]]],[[],8,[],3],[],[6],[6]]
[[[[],[],7],[[9,8,7],3],4]]
[[],[9]]
[[10,[[10,9,9,1,9]],[[5,5,7,0,4]],9,1],[],[[],5,[6,[3],[1],[1,8],[6,3,3,6]],2],[[[3,1,4,3,2]]],[3,[2,[10]]]]
[[1],[[[0,0,10],[9,1,1,1,4],[7,0,5,3],[2,2],8],[[0,4,6,9,5],8],[6,[6,8],7,[],[8,0,6]],[],[[],7]]]
[[],[[[6,1,9,8,5]],[[1,0,1,4],2,[],3]],[0,2,0,[[8,5,7,4,6],[5],4,[6,5,6,2,0]],10],[6,7]]
[[[],3,6,[4,1,[5,0,5,3],[3,0],5],[1,1,2]],[3,2,[[1,3,7,9],[5]],6],[6,[],5,2],[3]]
[[[[0,4,5,0],9,3,10,3],[[4,3,4,9,10],[6,1],[8,10,10,4,3],0]]]
[[3,6,4,7],[5,8,0,[[0,6]]],[],[]]
[[[[],[3,1,0,7,2],3,[10,3,0,2,8]],3],[0,9,0],[[[8,8,0,9,0],[6,0,5]],[[3,4,9],7]],[],[0]]
[[],[[0,1,[4,1,4,2],[6,5,3],[]],1,[9,3,[10,4,5,0,4]],[[5,7],2],[[8,7]]],[8,4,9]]
[[8,[7,[10],[2,8,10,9,3],[6,5],3]],[5,5,[[3],[]],6,[1,0,7,8]],[7,[6,5]],[],[10,5,4,[2,0,4,[6,10,4,4],[3,3]],8]]
[[[6],[10,[0,2,5,10,9],2],[[],[0],9,[1,0,5,8]]],[3,[[4],[3],3,[1,4,2,0,0],[]],[[8,3,6,10,7],1],[2,2,5,[6],[0,7]]]]
[[7],[1,3,[1,2,2],2,3],[5]]
[[[[]],0,[[4,6,4]],0],[],[3,[],[1],[10]],[[1,[2,5]],[[7],[6,10,6,6,6],6],[[0,8,5],[4,0,9]]]]
[[5,8,2,[0,3]],[6,[[6,4],[7,10,9,10,3],2],2,6],[1,[9,[6,4,1,2],8,[10,2,5,9,8],[]],[]],[],[[[8,2,3],9,[5,6,3,3],4,[4,10]],7]]
[[8,[2,0],[10],2,3],[[3]],[[9,[10,9,9,5,7],2],[[],9,[6,8,5]],[10],8,[]]]
[[7,10,[2,[0,6,4,0,5]],[4]],[[],[],4],[7,[5,10,2,[0,7,3,9,7]],[[7,2,1,3,5],[7,5,3,1,6],3]],[[[1],6]]]
[[],[[7,[],[5,7]],1,7]]
[[7,5,4,9],[[5],[[8,2],[1,5],3,4,1],[7,10,4,[],0]]]
[[[8,6,[6,3]]],[9,[],[[5,6,0]],[2,[1,10,10,6]]]]
[[0,0,[[1,1,10,1,3],2,[7,0,6],3]],[],[0,2],[[3],3,5]]
[[[4,7,[10]],[1,4]],[[2,[4,1,6,0,4]],2,[[],[]],9],[6],[[],[9],7,5],[9,10,[7,[6,0,5,1,3]],2,[]]]
[[4,[],[[5,4],[6,2,3,4],8,[4,3],7],[9,3,3,0],[[],1,6,2,9]]]
[[5],[6,[]],[]]
[[],[[1,5,[7,0],[2,7,6,1],10]],[]]
[[5,10,3]]
[[[7,1],[1,[7,5,9,7]],[0,[7,1,7,9,1],[9,2,9,9,1],5,[9]],[[]],[]],[0,[[9,0,3],[3],1,[1],1],9,[10,6,[],[10,9,1,10,10],[2,2,8]]],[[1,7,4],6]]
[[],[]]
[[[[6,3,9],[5,5,8,10,4],[7,4,9,1,3]],1,6],[[[8,2,4,5],[],[1,7,7]],0]]
[[0,10,[[4,0],4]],[9,[],[4,9,[10,5,8]],7],[10,[]]]
[[],[[],7]]
[[[6,5],2,8,7,[[6,2,10,1],1,[2,5,10,7],1,[2,10,7,5]]],[6,9,8],[4,[],[[1,8]],1,[7,[1,0,6,8],[8]]],[[],6,1,[7,[],0,[6,7,8,10,5]]],[[],[],[7,9,[5,10,6,3],[2,10,3],8],7,[9,[0,10],[8,2,6,0,1],[10,1]]]]
[[[9,[0,9,10,7,4]],6,[6,[8,5,9,6,8],[4,10,6],4,[]],[4,9,7,2,7]],[4],[[],[[4,2,5]],[4,[7],[9,5,8,7,7],[],[10,9,6]]],[10,[],10,[4]],[6,1,3,[[2,1],[1,9,7,3],5,[2,3,5,4,9],6],1]]
[[6],[8,5,[4,[1,10]]]]
[[1,7,5,9],[],[],[0,9,1],[0,[2,6,10,[10,7,3,5,3]]]]
[[3],[1],[]]
[[0],[8,[[6,7,6],3,7,[4,5,6,10,1],0]],[[[4],[6,0],0,[8],[8,1]],[[1],4,8]],[8]]
[[[[2,3],5],[[4,2,4,10,3],[4,0,9,4,2],4],[2,[1,5,2,6,7],8,[0,5,1,4,8]],[[3,6,7,10],[6,7,4,7],[9,4,10]],[[9],[4,2]]],[]]
[[[7,8,[8,2,10,2],[],[2]],3,9,0,1],[[[5]],0,7,[[7],2]],[[2,[],[8,5,4,1],9],5,6,[[1,2,8,0],4],[]],[2,[9,[],[10,10],8,[]],1]]
[[],[],[[[5],[9],5,7],5,[]],[[3,[1,2,6,3],9,[3,2,7],0]],[[[5,9],5,[8,1,7]],[1,1,[7,7,8,10]]]]
[[[[10,0],[0,7,2]],3,[0,3,2,[7,1,9]],[[10],0,[5]],[[2,8,0,5],[7,3],4,10]],[9,[[]],[[],[1,4,4],7,[0,1,6,7,2],[6,9,0,4,4]],[9,[9]],[6,[4,5,0,8],1,[8,3,1,10],[9]]],[7,[[]],[5,[1,9,6]]]]
[[4]]
[[5],[[2,[10,7,10,9,10],0]]]
[[[],[[1,8,6,1,6],[3,2,1],2,[10,3,7,1,4],0],3,[3]],[9]]
[[],[],[[8],[[],5,[1,8,7],9,1],[[7,1,2,4,3],7,[5,7,1,6,6],8,2],10],[4,[6,[8,8,6,7]],1,[[],[5,10,3,2,7]]],[1,[],[1,[0],7,[9,0]]]]
[[8],[2,[[9,2,9,9,10],[3,5,3,4]]],[10,[[10,7,10,0]],10,[[2,6],[4,9,6],[3,4,5,0,2],[]],7]]
[[4],[3],[],[10]]
[[[[0],7,[1,1,10,2,0]],2,[[10,5,10]]],[[[6],[4,4,6]],[3,[]],9,[[8,3,3],[6],[9,5,7,7],8],10],[]]
[[6],[[[3,10]],[]],[8,10,[],9]]
[[5,5,[],9]]
[[[[5,6,6,3]],2,[[4],0,7,2]],[[],[[10,5],[],[5],[8,1,0,3,2],3],[[7,3,0],5,0,4,[9,1]]]]
[[],[[2],7,4],[2,9,10],[[[],[7,4,4,7,3]],[]]]
[[9],[]]
[[[10,5,4,1,8],7,[5],[8]]]
[[0,10,[]],[],[0,6,[7,[4],[],[9]]],[4]]
[[[8],[10],9,9]]
[[3,[[1,0,5,1,5]]]]
[[[4,5,10],[7,[10,3,1],[2,6],10],[[6,0,8,9,6],4,[]],[]],[9,[],10]]
[[],[7],[10,10,[6]],[[[2,4],[6,2,2],0],6],[[[2,3,0,0,2],[6,5,7,2],2,4],6,6]]
[[1],[[]],[[[9,1,9,5],[6],[9,3,5,2,6],9,[]],6,[],[[2],9,[8,3,1,3,1],[3,10,6]],[[0,9,1,8,2]]]]
[[[8],[[7],[7],5],5,5],[4,[[5,9,10],[]],[[4,7,5,1]],[[10,1,7]],4],[5,[[4,8,4],7,0],[2],[],[8,0,[5,8],[8,5,7,2,8],4]]]
[[[0,[3,3,10],[],[0,9],5]],[[4,[],[7,2,5],[0,7],[0,10]]],[],[[[1,8]],[[9,7]],5,[[9,1,0,1],5,5,5,[10]],[[9,4,6,6],4,4,[2,6,9,4,7]]],[4]]
[[[[10,8,4,0],[9,10,1]],[],[],[[9,8,4,6],2,9],4],[[2,[6,7,8],10,[],[10,4,3,9]],[5,[9]],5,[6,[10],[7,3,6]],[]],[],[[[5,7],[9,7,7,6,9],[9,10,5],8],[[],3,[0,5,0]],3,6,6],[9,[7]]]

147
2022/inputs/14.txt Normal file
View File

@@ -0,0 +1,147 @@
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
541,165 -> 541,166 -> 551,166 -> 551,165
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
541,165 -> 541,166 -> 551,166 -> 551,165
565,161 -> 569,161
483,51 -> 483,52 -> 500,52 -> 500,51
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
506,84 -> 510,84
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
512,80 -> 516,80
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
512,84 -> 516,84
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
509,82 -> 513,82
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
553,161 -> 557,161
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
554,133 -> 558,133
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
551,136 -> 555,136
563,136 -> 567,136
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
517,95 -> 522,95
503,86 -> 507,86
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
559,155 -> 563,155
521,86 -> 525,86
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
519,98 -> 519,99 -> 529,99 -> 529,98
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
483,51 -> 483,52 -> 500,52 -> 500,51
515,86 -> 519,86
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
483,51 -> 483,52 -> 500,52 -> 500,51
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
519,98 -> 519,99 -> 529,99 -> 529,98
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
519,98 -> 519,99 -> 529,99 -> 529,98
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
557,130 -> 561,130
518,84 -> 522,84
545,127 -> 558,127
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
556,152 -> 560,152
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
559,161 -> 563,161
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
541,165 -> 541,166 -> 551,166 -> 551,165
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
509,86 -> 513,86
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
484,48 -> 484,43 -> 484,48 -> 486,48 -> 486,38 -> 486,48 -> 488,48 -> 488,43 -> 488,48 -> 490,48 -> 490,45 -> 490,48 -> 492,48 -> 492,40 -> 492,48
520,92 -> 525,92
556,158 -> 560,158
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
553,155 -> 557,155
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
562,158 -> 566,158
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
550,158 -> 554,158
515,82 -> 519,82
557,136 -> 561,136
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
547,161 -> 551,161
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
531,95 -> 536,95
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
527,92 -> 532,92
523,89 -> 528,89
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
499,13 -> 499,15 -> 495,15 -> 495,22 -> 506,22 -> 506,15 -> 501,15 -> 501,13
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
541,149 -> 541,141 -> 541,149 -> 543,149 -> 543,144 -> 543,149 -> 545,149 -> 545,144 -> 545,149 -> 547,149 -> 547,148 -> 547,149 -> 549,149 -> 549,144 -> 549,149 -> 551,149 -> 551,141 -> 551,149 -> 553,149 -> 553,147 -> 553,149 -> 555,149 -> 555,146 -> 555,149 -> 557,149 -> 557,147 -> 557,149
527,102 -> 527,106 -> 523,106 -> 523,111 -> 540,111 -> 540,106 -> 533,106 -> 533,102
490,35 -> 490,31 -> 490,35 -> 492,35 -> 492,31 -> 492,35 -> 494,35 -> 494,29 -> 494,35 -> 496,35 -> 496,26 -> 496,35
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65
560,133 -> 564,133
506,68 -> 506,70 -> 502,70 -> 502,77 -> 513,77 -> 513,70 -> 512,70 -> 512,68
538,114 -> 538,116 -> 536,116 -> 536,122 -> 552,122 -> 552,116 -> 544,116 -> 544,114
524,95 -> 529,95
492,65 -> 492,64 -> 492,65 -> 494,65 -> 494,59 -> 494,65 -> 496,65 -> 496,64 -> 496,65 -> 498,65 -> 498,62 -> 498,65 -> 500,65 -> 500,63 -> 500,65 -> 502,65 -> 502,59 -> 502,65 -> 504,65 -> 504,64 -> 504,65 -> 506,65 -> 506,63 -> 506,65 -> 508,65 -> 508,63 -> 508,65

24
2022/inputs/15.txt Normal file
View File

@@ -0,0 +1,24 @@
Sensor at x=3988693, y=3986119: closest beacon is at x=3979063, y=3856315
Sensor at x=1129181, y=241785: closest beacon is at x=1973630, y=-98830
Sensor at x=2761889, y=2453622: closest beacon is at x=2803715, y=2643139
Sensor at x=3805407, y=3099635: closest beacon is at x=3744251, y=2600851
Sensor at x=3835655, y=3999745: closest beacon is at x=3979063, y=3856315
Sensor at x=3468377, y=3661078: closest beacon is at x=3979063, y=3856315
Sensor at x=1807102, y=3829998: closest beacon is at x=2445544, y=3467698
Sensor at x=2774374, y=551040: closest beacon is at x=1973630, y=-98830
Sensor at x=2004588, y=2577348: closest beacon is at x=2803715, y=2643139
Sensor at x=2949255, y=3611925: closest beacon is at x=2445544, y=3467698
Sensor at x=2645982, y=3991988: closest beacon is at x=2445544, y=3467698
Sensor at x=3444780, y=2880445: closest beacon is at x=3744251, y=2600851
Sensor at x=3926452, y=2231046: closest beacon is at x=3744251, y=2600851
Sensor at x=3052632, y=2882560: closest beacon is at x=2803715, y=2643139
Sensor at x=3994992, y=2720288: closest beacon is at x=3744251, y=2600851
Sensor at x=3368581, y=1443706: closest beacon is at x=3744251, y=2600851
Sensor at x=2161363, y=1856161: closest beacon is at x=1163688, y=2000000
Sensor at x=3994153, y=3414445: closest beacon is at x=3979063, y=3856315
Sensor at x=2541906, y=2965730: closest beacon is at x=2803715, y=2643139
Sensor at x=600169, y=3131140: closest beacon is at x=1163688, y=2000000
Sensor at x=163617, y=1082438: closest beacon is at x=1163688, y=2000000
Sensor at x=3728368, y=140105: closest beacon is at x=3732654, y=-724773
Sensor at x=1187681, y=2105247: closest beacon is at x=1163688, y=2000000
Sensor at x=2327144, y=3342616: closest beacon is at x=2445544, y=3467698

50
2022/inputs/16.txt Normal file
View File

@@ -0,0 +1,50 @@
Valve QJ has flow rate=11; tunnels lead to valves HB, GL
Valve VZ has flow rate=10; tunnel leads to valve NE
Valve TX has flow rate=19; tunnels lead to valves MG, OQ, HM
Valve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR
Valve IH has flow rate=0; tunnels lead to valves YB, QS
Valve QS has flow rate=22; tunnel leads to valve IH
Valve QB has flow rate=0; tunnels lead to valves QX, ES
Valve NX has flow rate=0; tunnels lead to valves UH, OP
Valve PJ has flow rate=0; tunnels lead to valves OC, UH
Valve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD
Valve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ
Valve UC has flow rate=0; tunnels lead to valves AA, BY
Valve QX has flow rate=0; tunnels lead to valves AA, QB
Valve IZ has flow rate=0; tunnels lead to valves OC, SX
Valve AG has flow rate=13; tunnels lead to valves NW, GL, SM
Valve ON has flow rate=0; tunnels lead to valves MO, ZI
Valve XT has flow rate=18; tunnels lead to valves QZ, PG
Valve AX has flow rate=0; tunnels lead to valves UH, MO
Valve JD has flow rate=0; tunnels lead to valves OR, SM
Valve HM has flow rate=0; tunnels lead to valves TX, QH
Valve LF has flow rate=0; tunnels lead to valves ZI, UH
Valve QH has flow rate=0; tunnels lead to valves OR, HM
Valve RT has flow rate=21; tunnel leads to valve PG
Valve NE has flow rate=0; tunnels lead to valves VZ, TA
Valve OQ has flow rate=0; tunnels lead to valves TX, GE
Valve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH
Valve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF
Valve GE has flow rate=0; tunnels lead to valves YB, OQ
Valve EH has flow rate=0; tunnels lead to valves AA, MO
Valve MG has flow rate=0; tunnels lead to valves TX, NW
Valve YB has flow rate=20; tunnels lead to valves IH, GE, XG
Valve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB
Valve JR has flow rate=0; tunnels lead to valves ZI, OC
Valve GL has flow rate=0; tunnels lead to valves AG, QJ
Valve SM has flow rate=0; tunnels lead to valves JD, AG
Valve HB has flow rate=0; tunnels lead to valves OR, QJ
Valve TA has flow rate=0; tunnels lead to valves OC, NE
Valve PG has flow rate=0; tunnels lead to valves RT, XT
Valve XG has flow rate=0; tunnels lead to valves CB, YB
Valve ES has flow rate=9; tunnels lead to valves QB, FL
Valve BH has flow rate=0; tunnels lead to valves RU, OR
Valve FL has flow rate=0; tunnels lead to valves SX, ES
Valve CB has flow rate=0; tunnels lead to valves MO, XG
Valve QZ has flow rate=0; tunnels lead to valves AA, XT
Valve BY has flow rate=0; tunnels lead to valves UC, ZI
Valve ZH has flow rate=0; tunnels lead to valves MO, OC
Valve OP has flow rate=0; tunnels lead to valves NX, AA
Valve NW has flow rate=0; tunnels lead to valves MG, AG
Valve RU has flow rate=0; tunnels lead to valves ZI, BH
Valve SX has flow rate=16; tunnels lead to valves IZ, FL

1
2022/inputs/17.txt Normal file

File diff suppressed because one or more lines are too long

2893
2022/inputs/18.txt Normal file

File diff suppressed because it is too large Load Diff

30
2022/inputs/19.txt Normal file
View File

@@ -0,0 +1,30 @@
Blueprint 1: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian.
Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian.
Blueprint 3: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 3 ore and 8 obsidian.
Blueprint 4: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 2 ore and 13 obsidian.
Blueprint 5: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 12 clay. Each geode robot costs 3 ore and 15 obsidian.
Blueprint 6: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 11 clay. Each geode robot costs 2 ore and 16 obsidian.
Blueprint 7: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 2 ore and 15 obsidian.
Blueprint 8: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 10 obsidian.
Blueprint 9: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 9 obsidian.
Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 8 obsidian.
Blueprint 11: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 12 obsidian.
Blueprint 12: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 7 clay. Each geode robot costs 4 ore and 20 obsidian.
Blueprint 13: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian.
Blueprint 14: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 8 obsidian.
Blueprint 15: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 10 clay. Each geode robot costs 2 ore and 7 obsidian.
Blueprint 16: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 9 clay. Each geode robot costs 2 ore and 20 obsidian.
Blueprint 17: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 17 clay. Each geode robot costs 2 ore and 13 obsidian.
Blueprint 18: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 4 ore and 16 obsidian.
Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 4 ore and 13 obsidian.
Blueprint 20: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 14 clay. Each geode robot costs 3 ore and 17 obsidian.
Blueprint 21: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 3 ore and 19 obsidian.
Blueprint 22: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 7 clay. Each geode robot costs 2 ore and 16 obsidian.
Blueprint 23: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 3 ore and 17 obsidian.
Blueprint 24: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 20 obsidian.
Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 14 clay. Each geode robot costs 3 ore and 16 obsidian.
Blueprint 26: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 5 clay. Each geode robot costs 3 ore and 18 obsidian.
Blueprint 27: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 2 ore and 12 obsidian.
Blueprint 28: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 2 ore and 20 obsidian.
Blueprint 29: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 10 obsidian.
Blueprint 30: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 7 clay. Each geode robot costs 3 ore and 9 obsidian.

5000
2022/inputs/20.txt Normal file

File diff suppressed because it is too large Load Diff

2755
2022/inputs/21.txt Normal file

File diff suppressed because it is too large Load Diff

202
2022/inputs/22.txt Normal file

File diff suppressed because one or more lines are too long

73
2022/inputs/23.txt Normal file
View File

@@ -0,0 +1,73 @@
#.##.##...####..#.##.##....###....##...#..#####..#.##.##.#...###.##..#.##
.#....#..#.##..#.#.#...#..#..####..#.#.##.#.#..#.#..#.#..##.#..........#.
##.#####.###.#...######..###.#.#..##.#.##.#......#..##.....###.#.##.##.##
..#######.####.#..###...####..####....#.####.#.#..#.#.###.##.###.##..#...
.#..#.##...#...####.....##.#.#..#...###.....##..#.##..#.#.#.##.##.#.#.#..
####.#...#.#..##..###.####.#######.....#.##.#..#.#...#.##.#....#.........
..#.#.####...###.##.#..#.....#.##...#.#.####.....#..##....#..#####...##..
#####..##.....#.##..#.####....#.#....#.##....#.#....##.#####.#...####..##
#.#..#####.###..####..#.##..#######....##..#.###.#.#....##.#..##.##..#..#
..##.#.##.....###..#..#..#.####....#..####..##.###...#..#..#...##..##..##
#.###.##.#...##.##.#.##..####.##.#.#.###...##.#....#.#.#.##.##...#.##.#.#
.#####..###.#.###.###....#..#..#....#.##.#.###.#.####..###.#####.#.#####.
...#..##.##.#.#.###.#######.##.#...##..##...#......#..####.#.#...#.#####.
.#..###..######..#.#.##.##.#.##....##.#...#...#..#.#.##.#...#.#..#...#.##
##..#.#...#.###.#..#..#.###.###..###.#.......#####.##.####..#...#..#....#
...#..###...#...###.#.....#.###.##.###.####.##.....##..##.#.##.#.#...#.##
####.#......#..###..#.#...##.#.##..#...#.###...#..##.#..#.....####.##.###
##....#..#####..#####....##.#####.##.###..#.#####..###.##..#.#..###.#.###
##.##...##.###.#.#..#####...#..#...#....#..#.#.#.......##..#...#..######.
......#.###.#.##..####..#..##..##.###.#..##...#...#...#...#.###.#.#.##.##
....##..#...##.##.#.#.#..#..#.#...####.#.....#.#.#.##.#.....##.#...#.#.##
..#..###.#..###.####..#.#....#..##.#.##..###...#.##.#.####.##.#.#.#.#...#
...###.....####.######...####.....#.#.#.#...#..##.##...#.###..###.#.#####
#.##..#.##.#......#####..#...####.#...###...###.##...##.##...###.###.##.#
###....#..#.###..#.####.##.#...##..#..#..#....###...#......#..#..##.#.###
.####.#.###..#########...#.##############.##...#.##.##.#..#.#.##.#.#.###.
.#.##...#...###..#..#.#.#..#.#.#.#.##........#.##.#.#.##.##.#.#.##.######
##.#.#.###..###.###.#.#.....#.###..####.#.#..##.#.##..#.####..#.......##.
.#.#####.#..###..##.#..#...#.#.##..#..#..#..##.####.##.#..###.#......#...
.##..##..#..#.#..###...#.#.##.###..#..#...#.##.#.##..#.#.##..#....#...#..
..#......###..###..##...##.###..##.#.....#.###...##.##..#...#..#.#..#....
.#.#.#.#.#...###.#######..#..###...#.###.#.###.##....#...#.##......####..
#...#.##.#...#.#.#.###.#..#.#..##.###.######.#.#....###.##...#....#....#.
.###....#..####.#..#....##.#..##..#..#.#####.#.#...##.##...####.###.##..#
#...#.#...#...##.#####.#.#...##..#..##.#...#...###....##.######.#..#.##.#
#...##...##..#......####.#.#.##.##.#.......####...####...#..#..#.#..#.##.
.###....#.####..##.###..#....#...##.###..#...#.##.#...#####.###..#..#..##
##.#..##..###.#..#..####...#.##.##..#......####....#....#.###..##......##
##.##....#####.##.###.######..#..####..##.#.####.#..####.##...##....#####
.##.#..##..#.##..###.....#..#.##..####...#.##...#.#.#.#..##.###.....##...
.##.#...#...####..##.#....##...#..###.#.#..#....##.######.#...##.###..##.
##.##.###..#.##.#..#....#.##.#.##..#...#..##.#.####..##.##...#..##.##..##
.#..###.#.#.##..#..#.####.#.##.#..##.#....#.###.##..#.###...#..#....###..
####..#.#..###..#...##.##.###.##...#.##.##...##..#.##.##...#.#..#.#.#.#..
..###...#..#...........#.###.##..#..###..##.#.##.#...#.#..#.....##..#####
.....##....###..###.###..#..#...##..#......#.##..#.#.#..##..#.###.....#.#
..####.#......#...#.#.#.#..#..##....##..#.#...##.##.##.###.###...###...#.
##..#.#.#.##.###########.#.###....####.##.#.#...####..#.##.#...##...#....
##...#..#...####.#.####....#.########.######..###....###..##..#...#.###..
##.###.####..#.##.#.#####.##.###..#.#.#.##.##.##.####.##.#...#..#..##....
.#..#.#.##..##...#....#.#....#....###..#..##..###.##.####.##.####.##.#...
##.#.##.##...#.#..#.#...##...#...#..#......#.###......###.....#.#.#####.#
..#.##.##.###....#.#..###..#..##.####.###.##..##.##....#...##.#..#..##.##
#####.#...#..##..##.#.#.....##..#..##.##.##.####..#####.#..###..#.##..##.
####.##..........###.###.#####.#.#..##...##.....#..###..##..#.####..#.##.
#.....##.####...#..##.##..#..#....##..#...#..#.#.....#..#...#.###.##.#..#
#.#.##..###.#...##.#...###.#......#....##..##.##.###.#.#.#..#.##.####..##
##..###.#.#......##.##.##.#.#####.#.#.###...###.##.#......#.##########..#
.####....#..#...###.#..##.#.####..#.#..######.#.####..##....###..##..#..#
#..##.#.#...##.#.#.########.....#.##...#....#.####.###.########.#.##.#...
#.#######..#.##.#.#.#..####..##.#..###.####.#..#########....####....###..
..##.#...##...#..###.#..##.#..#...##.####.######.####.#..##.#...#.#..###.
.#..##.#.##..#......##.#.#.##.#####.#.###....#...###...#....#.###.....###
#......#.#..##....##.########.#..#..##.##......#.#..######..##.##..##.###
..##...#...#.#..#.#########..##..#####..#..#..##.#....##...#.#....##.#.#.
.##..###.####.#..#####.###..###..#......##...#.....####..###..#..##.#.##.
......###.#..#...#..#.#.##.#.###...##.#.#....####.#..#.######.#.#...####.
...#.##.####....##..##.#.###.###.....#..###...####..##..######.#..##.....
.....####.....###.#.#.......#####.#.#....##...#####..#..#.#..#.#.#..##.##
##..##.#..##..#..#.#####..##.####.#...#.#..#..###..#..#....#...#.###.##..
#.#..#.#########.####..#####..####.#.#####....#.#..##...#..####.#..###.#.
#..##.###.##..#....#...#..#.##..#..###..#####..#######.#####....#.##.....
####.####.########.#.###....#.#..#..#.#.#.#..#....#..#.....#..##..#.##.#.

27
2022/inputs/24.txt Normal file
View File

@@ -0,0 +1,27 @@
#.########################################################################################################################
#<^^^^v^><<v<v.v<>><^><v<vv^vv<^^.^v^.v.<<<<v.vv<.>^^><v.^>v^>^>^^v>>v^^^.<v<>v<>.<>v^^^^^^>>^^.^^>>vv><^v<^.<v><^^v^<<<>#
#<>>>^^v^>v>v>^^^^.<<<>><^^>>^^<>v^v^v>^v>v>^vv.vvv>v<^^<<v>v^^><^>.>^^^.><^^<v.<^^>.v<vv<^>^<<<<v^vv>>>>v^.^v.>>>^v.>.v>#
#.v^v>vv.v<<^v>^<^v<.v<<.>>^vv<.^v^<^^>^<vv^vv>><^vv<<v>^^^vvv<v.><^.<v<^>>>.^<^<.v<^<^v>><^^^><^>>v^<^<v>^>>v^v<><^vv<v<#
#>.>>^<^v>v^.><^^.>.^>v>^^><vv>v><.^v<>^<<vvvv.<>>>^v.v<vv>.v..v^>><<v.^.^^v>^^v<v>>>^v<vvv.<^^<<>^>^.>v^^>^v<^v^v<>.<v<<#
#<v^^>v>vvvv<^^.^<^v><v<>v^>v<^<^^^<>^<<v<^>^^.<^v^^<<>.>vvv^^^v<v.^^^^<<<>^v^><^>v>><^.<^^^<>^v^v>^^v>>v>v<v><>v.^><v>>>#
#<^v>..>^>vv>v<<v>.v>vv>v^v<<<<<<<<v^^<v<.v.^<>>^>^^<>^^<>v<v.<^<.vvvvv>v^.^><<v>v<>>v.v.v^^>v<^v<^>v^v><<.<^^>v^vv<^^vv>#
#>v^^v^v>.<.^vv.^<<<<.<v>>v>>v^<.<><>v><<<^.<>v><.v^<v><<.><<<^^vv>^>v<<<>^<.^v>vv^<<^.>^<^^v<<vvvvv><^>v>^.>>>.v^.v^vv<>#
#<<<>>...v^^>^v<^v>>><<<>>vv^^<^^>^v<.>v^.>>v<<v>>>>^><.>v^.^vv><v^<.^v<^v<<<.^v^^^^<>^v>^>>>vv^<<.^>>v><vvvv<>v^<>><v<v>#
#>.>><vvv<<>v<><^><v>>.^<>.>^v^.<^.<>^>v^.><<^>><v><>..v<>^^<^.>><<^<<^<.^>^.vv^^>^.^>^.v^>v<>^^vv<.<>>><<^v>v<<>>v><^^<>#
#<<>.v<<<>^.vv<^v>.>^<><>v^.v<>v<>>vv<<.^^<<>^>>.><v<^<v^.>^vvv<vv.^^.^><v^v^v^<>v.vv>v>.>v.vv<<v^<>^^^^<v^^^.>v.vv^<..><#
#>.<<<v<>vv>>^v>vvv<^<>.vvv^<^>v<>^^<v^..><.<^<><>^^^^<^>.<v^>>v>^>v>^<><<v>v>v<^^<v>v>v>><>^v<.^v^><v^^<v^>v><..^.v<^<v>#
#>>^<^<v<<^vv>^^<>^<<>.<<v<^v^^v>.vv<><<v>^<>^><v^>.>>v^^<^^^^>v^^^^vv<>>><<^^<<><<<>v^<v^v<^.<>>>>^v>^><<<^^><vv<<<^<.<>#
#<^>.vv>>^.v.>^^v>.^<>>^<<..<v><^><><^v<v<^v^>^^^>v<^^.<>v.<<v<vv.>v^^<^<>>>vvv<^<^v><v>v>v^>..^<v<vv<<^^^v>.^><v<>^>><>>#
#>^<><<>^<<v><^>v^.v><>.<<^>>.<^^<v<<^>.>v.>v>><^^<>vv<<<>v.<vv><v<<.<>v<<.vv<><>>^vv<>v>vv^.<v<v<>><.v^v><.v^.v^v>>v>>v<#
#<<>><^^<v.v<<vv>>.<>v>>^^<^v.<v^<vv.vvv<><<<^v.^^<.><v<v<..v^>v^.^v^>v<>^v<<^<>vvv><>>v^^^>v<<<>.^<vv^>^>v^v^^.><<.>>^^>#
#<^.v^>^v>^<^><<^v^>v^<><<^^^v<<^.v^v<>^.>.v<<<v^vv^^v.<v<^^<^v^.><^^>v.<v<<^^<vv<>>>.<>^.^v>v>v><^><<<>.^^<>v.<.v><><v><#
#><<^>^<v<>^^^vv^>>.vv>vvv^v^>^^>v<<>^^^^>^>v<>>v^v>v><>.^vv^<>>>><<<>^>^.>..vv>^^^<^>v<>>^v><v<>^vv>v>^^vv<><^>^^^..>>>>#
#><vv^<v^^>><<v<v.<.v^..v><^v<<>^v>.^><v><^^v^<^<v><vvv^^v^><^v.><vv><^>^<v^v><v<.>^><^<<<v>>>v<><.^<^>^v<<^^>.<>vv<^.<v>#
#<.^^>><>><>><><>^.^>.vv^>>><<><vvvvv^v<<^^>.^..>><<<v>>.<>v<^<vv<^^.v^>>v<>vv^>vv<^<><<.vv><.<^^><>.vv<<><v>><>v<vvvv^.>#
#<v<<.^..v<>v><v<>>^<<.><^<v<^vv>vv>>v>^^<^^^>v^^>><^v<^.<<^^v<^v>>^.^<v.<>^v<^v^>v><v<>>^.>v.>>v>.>^v<>v<v>v<v<.>vv><.>>#
#<v^vv>>v<<.<v^<<.>^<^v<>v^^<>.v^>^v<v>>>vv>^^>>>v<<<><<^^.>>^><>^<v<>>.v>^>v^^>^^>>>v>v^>>v>^^.v>.vvv>.v<>.^^<<<^vv^>^^>#
#>v^^.v^<.<^v<>.^<><>^^^.v.<<.^<^v<vv^v^>v^>^v.^.v^>vvv<^<>^>^^v>v>v^.v^^>^>>^>^v^>^v^^.><^.^^>^^<^><>>^>.>.^^^v<<<v.>v>.#
#<v><>v<^^<><<vv.v><v>.vv^><.v^.<v^v.><>^<>.^<<vvv^vv^>v.^v>.><^^<.>>vvv><^<^<v>v<^v.^^><>>>.<^^<v<v^^.^v<^>^<v^<>>v>>>><#
#><^^v>>>vv>^<<<<>>v>vv<vv<>>>><v>.v<<.<>><v^.<>.<<^vv>^><v<^>^<<v^<^><>>.v<^vv<vv<><^<>.vv^v^^<>>vvv<>^<v<<v<<v^<v<^>^^>#
#<v..<.vv<v<>vvv^..v>^v^><^<^>>^.v^^<><>>v^>><><<v<v>><^^^v>vv><<^<.>>>v<v.><>v><>>^^<<.>>.><>vv>.^^vv>>>^vv^<^>^<^<^<<^>#
########################################################################################################################.#

126
2022/inputs/25.txt Normal file
View File

@@ -0,0 +1,126 @@
2=1
2=-02211=
2=-1111=2-0-20=
2=2-=12
1--2-=2211-221
1=20011
1221=021-0=2011-1
1=00=202011=
200=121-=2-11=21
2-21002021202
1-11=12011112
1==2-=0-=2-0-0
20=-12--12
101122=222021221-
12=2200-1==1=12=1=1
2==-21=-=2
1==-1222-1==2-
111-2-2=0
1=2
1=20=-00=22
1=2=0-2101=2
10=
10-=12101-102=1=
12=11=-
1202=0--0-2==0
1-0--
10210210-10021=2-2
22=
12-110101
2=-===0=0=11--
2=21022-00-
2-111102102--201=0
2=-2=
12=22=11-1000=121
11=10-02111211
20210121--0=1=-=
1=-
10=-==02-20-0=01
21=0=-=
2=10002
1-0102-020201121
11---01101=--
1=-1=-=-011
211-00-2==21==
21
1201-1202=2-0
21000=2=1-=10--2
1=0=
1-1
1-2---=1====-0210=-0
2-220-=
122-
110200-0
2=--2
20112=0-2022-
1=-0--
1=-01-0-10=2=0===-
1=22=2=--11=-0-2111
1==00-1=00=0-
1=2212-1-=201
2-200=2001
2222012-10-0=-0=
1-====
100=2200
1-11==0
1--2111-1
1---2121-202210=2
11222=
1=2102-2221-111-
111
1=
1--0=-1
10=00=10=---1=-
1=0==-2
220002
1==211-0=222102-
1-==-121021
1202-1=01--202
12=-0===11=0
20-001=
1000-2-==2=-
1=01--
10=--01221
1-=2-=0=-0==10-22-
2021212-1020=002
11===1==-2-01-21
2-00-10-
12-0221212000
201==
20011
2---0=1222--02
20-
10-=02010
101--0202=-2=1==01
2=0121-02112-0=
2-=-=1011
11-=02
110-2001
1==011-12000101-11
2=
1-11-=--=
110
101=21
1=11
212-10020-212111-2
102=22
1-
1-02=22-=1==2
11=10-00-=00-00=-
220200-=2
1-0=----
1022=0-2--==--1
1-=201-1021
2=-1-10=1=-2020=00
12201=0102-0110=-
20=2
2020=-===1==-212
1=0-222-2=22=-=
1=--12==0100=-21
1=1-2
1=-220001=1
20
1=1
1=0=-=1=0-=01
202102-200
2-=2-110012

View File

@@ -1,6 +1,14 @@
//! Common helper utilities to all days
use std::cmp::Ordering;
use std::ops::Add;
use std::ops::Div;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Sub;
use anyhow::Result;
use nom::combinator::map;
use nom::error::ErrorKind;
use nom::error::ParseError;
use nom::Finish;
@@ -93,6 +101,17 @@ where
}
}
/// Add an index to repeated successful invocations of the embedded parser.
pub fn enumerate<I, O, E>(f: impl Parser<I, O, E>) -> impl FnMut(I) -> IResult<I, (usize, O), E> {
let mut index = 0usize;
map(f, move |v| {
let res = (index, v);
index += 1;
res
})
}
/// Return the minimum and maximum of two unordered variables
pub fn minmax<T>(a: T, b: T) -> (T, T)
where
@@ -104,3 +123,114 @@ where
(b, a)
}
}
/// Some magic to get two mutable references into the same slice
pub fn get_both<T>(slice: &mut [T], first: usize, second: usize) -> (&mut T, &mut T) {
match first.cmp(&second) {
Ordering::Greater => {
let (begin, end) = slice.split_at_mut(first);
(&mut end[0], &mut begin[second])
}
Ordering::Less => {
let (begin, end) = slice.split_at_mut(second);
(&mut begin[first], &mut end[0])
}
Ordering::Equal => panic!("Tried to get the same index twice {first}"),
}
}
#[derive(Debug, Default)]
pub struct IndexSet(Vec<u32>);
impl IndexSet {
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(
capacity / std::mem::size_of::<u32>() / 8,
))
}
fn ensure_item(&mut self, item: usize) -> &mut u32 {
if self.0.len() <= item {
self.0.resize(item + 1, 0);
}
&mut self.0[item]
}
#[inline]
fn index(index: usize) -> (usize, u8) {
const PER_ENTRY: usize = 8 * std::mem::size_of::<u32>();
(index / PER_ENTRY, (index % PER_ENTRY) as u8)
}
pub fn insert(&mut self, index: usize) -> bool {
let (entry, pos) = Self::index(index);
let item = self.ensure_item(entry);
if *item & (1 << pos) != 0 {
false
} else {
*item |= 1 << pos;
true
}
}
pub fn contains(&self, index: usize) -> bool {
let (entry, pos) = Self::index(index);
self.0
.get(entry)
.map_or(false, |&entry| (entry & (1 << pos) != 0))
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Vec2(pub [i32; 2]);
impl Vec2 {
pub fn l1(self) -> i32 {
self.0.into_iter().map(i32::abs).sum()
}
}
impl Add<Self> for Vec2 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self([self[0] + rhs[0], self[1] + rhs[1]])
}
}
impl Sub<Self> for Vec2 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self([self[0] - rhs[0], self[1] - rhs[1]])
}
}
impl Div<i32> for Vec2 {
type Output = Self;
fn div(self, rhs: i32) -> Self::Output {
Self(self.0.map(|v| v / rhs))
}
}
impl Index<usize> for Vec2 {
type Output = i32;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl IndexMut<usize> for Vec2 {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}

View File

@@ -1,9 +1,151 @@
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::bytes::complete::take_until;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::combinator::opt;
use nom::combinator::value;
use nom::multi::fold_many1;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::enumerate;
use crate::common::get_both;
use crate::common::parse_input;
type Move = (usize, usize, usize);
type OwnedStacks = Vec<Vec<u8>>;
fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8], ()> {
// Forgive me for this crime
fold_many1(
enumerate(terminated(
alt((
// Parse a delimited value into a Some(content)
map(delimited(tag("["), take(1usize), tag("]")), |v: &[u8]| {
Some(v[0])
}),
// Or an empty stack into a None
value(None, tag(" ")),
)),
opt(tag(" ")),
)),
|| (),
move |_, (index, c)| {
if let Some(b) = c {
if stacks.len() <= index {
stacks.resize_with(index + 1, Vec::new);
}
stacks[index].push(b)
}
},
)(input)
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn parse_stacks(input: &[u8]) -> IResult<&[u8], OwnedStacks> {
let mut stacks = Vec::new();
let (input, _) = terminated(
fold_many1(
terminated(|input| parse_row(input, &mut stacks), newline),
|| (),
|_, _| (),
),
// Skip the line with the numbers
take_until("\n\n"),
)(input)?;
// Reverse the stacks since we parsed them top-down
for stack in &mut stacks {
stack.reverse();
}
Ok((input, stacks))
}
fn parse_task(input: &[u8]) -> IResult<&[u8], (OwnedStacks, Vec<Move>)> {
fn parse_usize(input: &[u8]) -> IResult<&[u8], usize> {
map(nom::character::complete::u32, |v| v as usize)(input)
}
let (input, stacks) = parse_stacks(input)?;
// Consume the double newline
let (input, _) = tag("\n\n")(input)?;
let (input, moves) = many1(terminated(
tuple((
preceded(tag("move "), parse_usize),
preceded(tag(" from "), parse_usize),
preceded(tag(" to "), parse_usize),
)),
newline,
))(input)?;
Ok((input, (stacks, moves)))
}
fn compute_answer(stacks: &mut [Vec<u8>]) -> Result<String> {
let mut result = String::with_capacity(stacks.len());
for stack in stacks {
result.push(
*stack
.last()
.ok_or_else(|| anyhow::anyhow!("Encountered empty stack"))? as char,
);
}
Ok(result)
}
pub fn part1(input: &[u8]) -> Result<String> {
let (mut stacks, moves) = parse_input(input, parse_task)?;
for (count, from, to) in moves {
let (from, to) = get_both(&mut stacks, from - 1, to - 1);
let drain_start = from.len() - count;
to.extend(from.drain(drain_start..).rev());
}
compute_answer(&mut stacks)
}
pub fn part2(input: &[u8]) -> Result<String> {
let (mut stacks, moves) = parse_input(input, parse_task)?;
for (count, from, to) in moves {
let (from, to) = get_both(&mut stacks, from - 1, to - 1);
let drain_start = from.len() - count;
to.extend(from.drain(drain_start..));
}
compute_answer(&mut stacks)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/05.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "CMZ");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "MCD");
}
}

View File

@@ -1,9 +1,68 @@
use anyhow::Result;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
fn find_first(input: &[u8], unique: usize) -> Result<usize> {
let mut seen = [false; 256];
let mut tail_it = input.iter();
let mut first = 0;
// Loop invariant: input[first..last] contains only unique characters
for (last, &c) in input.iter().enumerate() {
if seen[c as usize] {
first += (&mut tail_it)
.take_while(|&&b| b != c)
.map(|&b| seen[b as usize] = false)
.count()
+ 1; // +1 because take_while doesn't return the first element that didn't satisfy the condition, while we do need to count it
} else {
// New unique character found: input[first..=last] contains unique characters
if last - first + 1 == unique {
return Ok(last + 1);
}
seen[c as usize] = true;
}
}
anyhow::bail!("Did not find unique sequence of length {unique}");
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
pub fn part1(input: &[u8]) -> Result<String> {
Ok(find_first(input, 4)?.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
Ok(find_first(input, 14)?.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLES: &[&[u8]] = &[
b"mjqjpqmgbljsphdztnvjfqwrcgsmlb",
b"bvwbjplbgvbhsrlpgdmjqwftvncz",
b"nppdvjthqldpwncqszvftbrmjlhg",
b"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg",
b"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw",
];
#[test]
fn sample_part1() {
const CORRECT: &[usize] = &[7, 5, 6, 10, 11];
for (&sample, &correct) in SAMPLES.iter().zip(CORRECT) {
assert_eq!(find_first(sample, 4).unwrap(), correct);
}
}
#[test]
fn sample_part2() {
const CORRECT: &[usize] = &[19, 23, 23, 29, 26];
for (&sample, &correct) in SAMPLES.iter().zip(CORRECT) {
assert_eq!(find_first(sample, 14).unwrap(), correct);
}
}
}

View File

@@ -1,9 +1,124 @@
use anyhow::Context;
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::combinator::opt;
use nom::multi::fold_many0;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
fn parse_dir<'a>(
input: &'a [u8],
dirs: &mut Vec<u32>,
dir_stack: &mut Vec<&'a [u8]>,
) -> IResult<&'a [u8], u32> {
use nom::character::complete::u32;
enum Entry<'a> {
File(u32),
Dir(&'a [u8]),
}
let initial_len = dir_stack.len();
let (mut input, mut size) = preceded(
tag("$ ls\n"),
fold_many0(
// Map many newline-terminated entries
terminated(
// of either
alt((
// A size followed by a name
map(terminated(u32, take_until("\n")), Entry::File),
// Or the word "dir" followed by a name
map(preceded(tag("dir "), take_until("\n")), Entry::Dir),
)),
newline,
),
|| 0u32,
|files_sum, entry| match entry {
Entry::File(size) => files_sum + size,
Entry::Dir(name) => {
dir_stack.push(name);
files_sum
}
},
),
)(input)?;
for i in initial_len..dir_stack.len() {
let (new_input, content_size) = delimited(
tuple((tag("$ cd "), tag(dir_stack[i]), newline)),
|input| parse_dir(input, dirs, dir_stack),
// Optional cd'ing out because the last directory is never exited.
opt(tag("$ cd ..\n")),
)(input)?;
input = new_input;
size += content_size;
}
dirs.push(size);
dir_stack.truncate(initial_len);
Ok((input, size))
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn parse_program(input: &[u8]) -> IResult<&[u8], (u32, Vec<u32>)> {
let mut dirs = Vec::new();
let mut dirstack = Vec::new();
let (input, size) = preceded(tag("$ cd /\n"), |input| {
parse_dir(input, &mut dirs, &mut dirstack)
})(input)?;
Ok((input, (size, dirs)))
}
pub fn part1(input: &[u8]) -> Result<String> {
let (_, sizes) = parse_input(input, parse_program)?;
let searched_size: u32 = sizes.into_iter().filter(|&size| size <= 100_000).sum();
Ok(searched_size.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
const TARGET: u32 = 30_000_000;
const TOTAL: u32 = 70_000_000;
let (used, sizes) = parse_input(input, parse_program)?;
let required = TARGET - (TOTAL - used);
let min = sizes
.into_iter()
.filter(|&size| size >= required)
.min()
.context("Did not find dir large enough to delete")?;
Ok(min.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/07.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "95437");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "24933642");
}
}

View File

@@ -1,9 +1,136 @@
use anyhow::Context;
use anyhow::Result;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
#[inline]
fn stripe<'a>(
values: impl IntoIterator<Item = &'a u8>,
visible: impl IntoIterator<Item = &'a mut bool>,
) {
let mut max = 0;
for (&val, visible) in values.into_iter().zip(visible) {
if val > max {
max = val;
*visible = true;
if val == b'9' {
return;
}
}
}
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
pub fn part1(input: &[u8]) -> Result<String> {
let width = input
.iter()
.position(|&b| b == b'\n')
.context("Single row field")?;
let height = input.len() / (width + 1); // Include newlines
let mut visible = vec![false; width * height];
// Horizontal striping
for (y, row) in input.chunks_exact(width + 1).enumerate() {
// First, left to right
stripe(&row[..width], &mut visible[(y * width)..]);
// Then right to left
stripe(
row[..width].iter().rev(),
visible[(y * width)..(y * width + width)].iter_mut().rev(),
);
}
// Vertical striping
for x in 0..width {
// Top to bottom
stripe(
input[x..].iter().step_by(width + 1),
visible[x..].iter_mut().step_by(width),
);
// Bottom to top
stripe(
input[x..].iter().step_by(width + 1).rev(),
visible[x..].iter_mut().step_by(width).rev(),
)
}
Ok(visible.into_iter().filter(|&b| b).count().to_string())
}
#[inline]
fn scenery<'a>(
values: impl IntoIterator<Item = &'a u8>,
visible: impl IntoIterator<Item = &'a mut usize>,
) {
let mut last_seen = [0; 10];
for (i, (&val, score)) in values.into_iter().zip(visible).enumerate() {
let val = val - b'0';
let visible = i - last_seen[val as usize];
if i > 0 {
*score *= visible;
last_seen[..=(val as usize)].fill(i);
} else {
*score = 0;
}
}
}
pub fn part2(input: &[u8]) -> Result<String> {
let width = input
.iter()
.position(|&b| b == b'\n')
.context("Single row field")?;
let height = input.len() / (width + 1); // Include newlines
let mut score = vec![1; width * height];
// Horizontal striping
for (y, row) in input.chunks_exact(width + 1).enumerate() {
// First, left to right
scenery(&row[..width], &mut score[(y * width)..]);
// Then right to left
scenery(
row[..width].iter().rev(),
score[(y * width)..(y * width + width)].iter_mut().rev(),
);
}
// Vertical striping
for x in 0..width {
// Top to bottom
scenery(
input[x..].iter().step_by(width + 1),
score[x..].iter_mut().step_by(width),
);
// Bottom to top
scenery(
input[x..].iter().step_by(width + 1).rev(),
score[x..].iter_mut().step_by(width).rev(),
)
}
Ok(score.into_iter().max().context("empty field")?.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/08.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "21");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "8");
}
}

View File

@@ -1,9 +1,122 @@
use ahash::AHashSet;
use anyhow::Result;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::character::complete::newline;
use nom::combinator::map_res;
use nom::multi::many0;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
use crate::common::Vec2;
#[derive(Copy, Clone)]
enum Direction {
Up,
Left,
Right,
Down,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Direction {
fn vec_for(self) -> Vec2 {
Vec2(match self {
Direction::Up => [0, -1],
Direction::Left => [1, 0],
Direction::Right => [-1, 0],
Direction::Down => [0, 1],
})
}
}
impl TryFrom<u8> for Direction {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
b'U' => Ok(Direction::Up),
b'L' => Ok(Direction::Left),
b'R' => Ok(Direction::Right),
b'D' => Ok(Direction::Down),
b => anyhow::bail!("Invalid direction '{b}'"),
}
}
}
fn parse_moves(input: &[u8]) -> IResult<&[u8], Vec<(Direction, u32)>> {
many0(terminated(
separated_pair(
map_res(take(1usize), |bs: &[u8]| Direction::try_from(bs[0])),
tag(" "),
nom::character::complete::u32,
),
newline,
))(input)
}
fn part_generic<const N: usize>(input: &[u8]) -> Result<String> {
let moves = parse_input(input, parse_moves)?;
let mut head_pos = Vec2([0, 0]);
let mut tails = [head_pos; N];
let mut visited = AHashSet::new();
visited.insert(head_pos);
for (direction, steps) in moves {
let step = direction.vec_for();
for _ in 0..steps {
head_pos = head_pos + step;
let mut ref_pos = head_pos;
for tail_pos in &mut tails {
let delta = ref_pos - *tail_pos;
if delta[0].abs() <= 1 && delta[1].abs() <= 1 {
break;
}
let step = Vec2([delta[0].signum(), delta[1].signum()]);
*tail_pos = *tail_pos + step;
ref_pos = *tail_pos;
}
visited.insert(*tails.last().unwrap());
}
}
Ok(visited.len().to_string())
}
pub fn part1(input: &[u8]) -> Result<String> {
part_generic::<1>(input)
}
pub fn part2(input: &[u8]) -> Result<String> {
part_generic::<9>(input)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/09.txt");
const SAMPLE_LARGE: &[u8] = include_bytes!("samples/09.large.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "13");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "1");
assert_eq!(part2(SAMPLE_LARGE).unwrap(), "36");
}
}

View File

@@ -1,9 +1,131 @@
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::iterator;
use nom::combinator::map;
use nom::combinator::value;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
#[derive(Copy, Clone)]
enum Instruction {
AddX(i32),
Noop,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Instruction {
#[inline]
pub fn cycles(self) -> i32 {
match self {
Instruction::AddX(_) => 2,
Instruction::Noop => 1,
}
}
#[inline]
pub fn execute(self, x: &mut i32, cycle: &mut i32) {
*cycle += self.cycles();
if let Instruction::AddX(v) = self {
*x += v;
}
}
}
fn parse_instruction(input: &[u8]) -> IResult<&[u8], Instruction> {
terminated(
alt((
value(Instruction::Noop, tag("noop")),
map(preceded(tag("addx "), nom::character::complete::i32), |v| {
Instruction::AddX(v)
}),
)),
newline,
)(input)
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut x = 1;
// Count from one like a scrub
let mut cycle = 1;
let mut input_it = iterator(input, parse_instruction);
let mut total = 0;
for instruction in &mut input_it {
let old_cycle = cycle;
let old_x = x;
instruction.execute(&mut x, &mut cycle);
if old_cycle % 40 < 20 && cycle % 40 >= 20 {
let to_report = if cycle % 40 == 20 { x } else { old_x };
let checkpoint = cycle / 20 * 20;
total += to_report * checkpoint;
}
if cycle >= 220 {
return Ok(total.to_string());
}
}
anyhow::bail!("out of instructions")
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut x = 1;
let mut input_it = iterator(input, parse_instruction);
let mut input_it = (&mut input_it).peekable();
let mut output = String::with_capacity(6 * (40 + 1));
let mut cpu_cycle = 0;
for crt_cycle in 1..=240 {
if let Some(instruction) = input_it.next_if(|i| cpu_cycle + i.cycles() < crt_cycle) {
instruction.execute(&mut x, &mut cpu_cycle);
}
let beam_pos = (crt_cycle + 39) % 40;
if (beam_pos - x).abs() <= 1 {
output.push('#');
} else {
output.push(' ');
}
if crt_cycle % 40 == 0 {
output.push('\n');
}
}
Ok(output)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/10.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "13140");
}
#[test]
fn sample_part2() {
let answer = "## ## ## ## ## ## ## ## ## ##
### ### ### ### ### ### ###
#### #### #### #### ####
##### ##### ##### #####
###### ###### ###### ####
####### ####### ####### \n";
assert_eq!(part2(SAMPLE).unwrap(), answer);
}
}

View File

@@ -1,9 +1,189 @@
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::character::complete::digit1;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::combinator::map_res;
use nom::combinator::value;
use nom::multi::separated_list0;
use nom::multi::separated_list1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::sequence::tuple;
use nom::IResult;
use strength_reduce::StrengthReducedU64;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
#[derive(Debug, Copy, Clone)]
enum Operation {
Mul(u64),
Add(u64),
Square,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Operation {
fn transform(self, worry: u64) -> u64 {
match self {
Operation::Mul(val) => worry * val,
Operation::Add(val) => worry + val,
Operation::Square => worry * worry,
}
}
}
#[derive(Debug)]
struct Monkey {
items: Vec<u64>,
operation: Operation,
test_mod: StrengthReducedU64,
targets: [usize; 2],
inspected: usize,
}
impl Monkey {
fn handle_items(&mut self, drains: &mut [Vec<u64>; 2]) {
self.inspected += self.items.len();
for item in self.items.drain(..) {
let mut new_val = self.operation.transform(item);
// Miraculously get less worried
new_val /= 3;
drains[usize::from(new_val % self.test_mod == 0)].push(new_val);
}
}
fn handle_items2(&mut self, drains: &mut [Vec<u64>], mod_base: StrengthReducedU64) {
self.inspected += self.items.len();
for item in self.items.drain(..) {
let mut new_val = self.operation.transform(item);
// Modular arithmetic is a good way to get less worried
new_val = new_val % mod_base;
drains[usize::from(new_val % self.test_mod == 0)].push(new_val);
}
}
}
fn parse_operation(input: &[u8]) -> IResult<&[u8], Operation> {
preceded(
tag("new = old "),
alt((
map_res(
separated_pair(take(1usize), tag(" "), nom::character::complete::u64),
|(op, val): (&[u8], u64)| match op[0] {
b'*' => Ok(Operation::Mul(val)),
b'+' => Ok(Operation::Add(val)),
_ => Err(anyhow::anyhow!("Invalid operation {op:?}")),
},
),
value(Operation::Square, tag("* old")),
)),
)(input)
}
fn parse_monkey(input: &[u8]) -> IResult<&[u8], Monkey> {
use nom::character::complete::u64;
map(
preceded(
// Skip the useless header line
tuple((tag("Monkey "), digit1, tag(":\n"))),
// Parse the actual interesting bits of the monkey
tuple((
// Parse the starting items
delimited(
tag(" Starting items: "),
separated_list1(tag(", "), u64),
newline,
),
// Parse operation
delimited(tag(" Operation: "), parse_operation, newline),
// Parse the test
delimited(tag(" Test: divisible by "), u64, newline),
// Parse both cases
delimited(tag(" If true: throw to monkey "), u64, newline),
delimited(tag(" If false: throw to monkey "), u64, newline),
)),
),
|(items, operation, test_mod, if_true, if_false)| Monkey {
items,
operation,
test_mod: StrengthReducedU64::new(test_mod),
targets: [if_false as usize, if_true as usize],
inspected: 0,
},
)(input)
}
fn parse_monkeys(input: &[u8]) -> IResult<&[u8], Vec<Monkey>> {
separated_list0(newline, parse_monkey)(input)
}
fn format_result(mut monkeys: Vec<Monkey>) -> Result<String> {
monkeys.sort_by(|a, b| b.inspected.cmp(&a.inspected));
let result: usize = monkeys[0].inspected * monkeys[1].inspected;
Ok(result.to_string())
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut monkeys = parse_input(input, parse_monkeys)?;
let mut drains = [Vec::new(), Vec::new()];
for _ in 0..20 {
for i in 0..monkeys.len() {
monkeys[i].handle_items(&mut drains);
for (j, drain) in drains.iter_mut().enumerate() {
let target = monkeys[i].targets[j];
monkeys[target].items.append(drain);
}
}
}
format_result(monkeys)
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut monkeys = parse_input(input, parse_monkeys)?;
let mut drains = [Vec::new(), Vec::new()];
let mod_base = StrengthReducedU64::new(monkeys.iter().map(|m| m.test_mod.get()).product());
for _ in 0..10000 {
for i in 0..monkeys.len() {
monkeys[i].handle_items2(&mut drains, mod_base);
for (j, drain) in drains.iter_mut().enumerate() {
let target = monkeys[i].targets[j];
monkeys[target].items.append(drain);
}
}
}
format_result(monkeys)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/11.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "10605");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "2713310158");
}
}

View File

@@ -1,9 +1,109 @@
use std::collections::VecDeque;
use anyhow::Context;
use anyhow::Result;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::IndexSet;
fn can_travel(from: u8, to: u8) -> bool {
match (from, to) {
(b'S', b'a'..=b'b') => true,
(b'y'..=b'z', b'E') => true,
(b'a'..=b'z', b'a'..=b'z') => to <= from || to - from == 1,
_ => false,
}
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn parts_common(
input: &[u8],
starting_symbol: u8,
// Neither of these functions needs to be generic closures; function pointers would do as well.
// However, doing so causes the compiler not to inline them which in turn hurts performance by
// about 25%. I would have hoped the reduced code size would make up for it, but it seems that
// doesn't quite work for this particular benchmark.
is_end: impl Fn(u8) -> bool,
accessible: impl Fn(u8, u8) -> bool,
) -> Result<String> {
let width = input
.iter()
.position(|&c| c == b'\n')
.context("No newlines in input")?
+ 1;
let starting_pos = input
.iter()
.position(|&c| c == starting_symbol)
.context("Could not find starting position")?;
let mut visited = IndexSet::with_capacity(input.len());
let mut todo = VecDeque::new();
todo.push_back((0, starting_pos));
while let Some((dist, pos)) = todo.pop_front() {
// Implementing an early exit doesn't appear to be helpful; the additional branching appears
// to throw off the performance by 35%. Instead, we can simply wait for the destination to
// pop off of the todo queue.
//
// For reference, by the time we find the exit, the queue is roughly two dozen entries long,
// so the potential benefits of skipping it are minimal compared to the additional branching
// code involved.
if is_end(input[pos]) {
return Ok(dist.to_string());
}
let mut add_todo = |new: usize| {
if accessible(input[pos], input[new]) && visited.insert(new) {
todo.push_back((dist + 1, new));
}
};
if pos % width != 0 {
add_todo(pos - 1);
}
if pos % width != width - 1 {
add_todo(pos + 1)
}
if pos >= width {
add_todo(pos - width);
}
if pos + width < input.len() {
add_todo(pos + width);
}
}
anyhow::bail!("Did not find a valid route")
}
pub fn part1(input: &[u8]) -> Result<String> {
parts_common(input, b'S', |b| b == b'E', can_travel)
}
pub fn part2(input: &[u8]) -> Result<String> {
parts_common(
input,
b'E',
|b| b == b'a' || b == b'S',
|a, b| can_travel(b, a),
)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/12.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "31")
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "29")
}
}

View File

@@ -1,9 +1,135 @@
use core::slice;
use std::cmp::Ordering;
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::multispace1;
use nom::character::complete::newline;
use nom::combinator::iterator;
use nom::combinator::map;
use nom::multi::separated_list0;
use nom::sequence::delimited;
use nom::sequence::pair;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
#[derive(Debug, PartialEq, Eq, Clone)]
enum Signal {
Number(u32),
List(Vec<Signal>),
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Ord for Signal {
fn cmp(&self, other: &Self) -> Ordering {
fn list_cmp(a: &[Signal], b: &[Signal]) -> Ordering {
a.cmp(b)
}
match (self, other) {
(Signal::Number(first), Signal::Number(second)) => first.cmp(second),
(first @ Signal::Number(_), Signal::List(second)) => {
list_cmp(slice::from_ref(first), second)
}
(Signal::List(first), second @ Signal::Number(_)) => {
list_cmp(first, slice::from_ref(second))
}
(Signal::List(first), Signal::List(second)) => list_cmp(first, second),
}
}
}
impl PartialOrd for Signal {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl From<u32> for Signal {
fn from(val: u32) -> Self {
Signal::Number(val)
}
}
impl<T> From<Vec<T>> for Signal
where
Signal: From<T>,
{
fn from(vec: Vec<T>) -> Self {
Signal::List(vec.into_iter().map(Signal::from).collect())
}
}
fn parse_signal(input: &[u8]) -> IResult<&[u8], Signal> {
alt((
map(nom::character::complete::u32, Signal::Number),
map(
delimited(tag("["), separated_list0(tag(","), parse_signal), tag("]")),
Signal::List,
),
))(input)
}
fn parse_signal_pair(input: &[u8]) -> IResult<&[u8], (Signal, Signal)> {
pair(
terminated(parse_signal, newline),
terminated(parse_signal, multispace1),
)(input)
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut iterator = iterator(input, parse_signal_pair);
let result: usize = (&mut iterator)
.enumerate()
.filter_map(|(i, (first, second))| (first < second).then_some(i + 1))
.sum();
Ok(result.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let marker1 = Signal::Number(2);
let marker2 = Signal::Number(6);
let mut iterator = iterator(input, terminated(parse_signal, multispace1));
let mut pos1 = 1;
let mut pos2 = 2;
for signal in &mut iterator {
if signal < marker1 {
pos1 += 1;
pos2 += 1;
} else if signal < marker2 {
pos2 += 1;
}
}
Ok((pos1 * pos2).to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/13.txt");
#[test]
fn test_parse_signal() {
assert_eq!(
parse_signal(b"[1,1,3,1,1]").unwrap(),
(&[][..], Signal::from(vec![1, 1, 3, 1, 1]))
);
}
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "13");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "140");
}
}

View File

@@ -1,9 +1,155 @@
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map_res;
use nom::combinator::opt;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
use crate::common::reduce_many1;
use crate::common::IndexSet;
#[derive(Debug)]
struct Cave {
width: usize,
height: usize,
occupied: IndexSet,
floor: usize,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Cave {
pub fn insert(&mut self, x: usize, y: usize) -> bool {
// Note: we're indexing column major for better cache locality
self.occupied.insert(self.floor * x + y)
}
pub fn drop(&mut self, x: usize, y: usize, total: &mut usize) -> bool {
if x >= self.width || y >= self.height {
return false;
} else if !self.insert(x, y) {
return true;
}
// x + usize::MAX is used to compute x - 1 because usize - isize doesn't exist in stable yet.
let supported = [0, usize::MAX, 1]
.into_iter()
.all(|dx| self.drop(x.wrapping_add(dx), y + 1, total));
if supported {
*total += 1;
}
supported
}
fn drop2(&mut self, x: usize, y: usize, total: &mut usize) {
if y >= self.floor || !self.insert(x, y) {
return;
}
*total += 1;
for dx in [0, usize::MAX, 1] {
self.drop2(x.wrapping_add(dx), y + 1, total);
}
}
}
fn parse_pair(input: &[u8]) -> IResult<&[u8], (usize, usize)> {
fn parse_usize(input: &[u8]) -> IResult<&[u8], usize> {
map_res(nom::character::complete::u32, usize::try_from)(input)
}
separated_pair(parse_usize, tag(","), parse_usize)(input)
}
fn find_dimensions(input: &[u8]) -> IResult<&[u8], (usize, usize)> {
reduce_many1(
terminated(parse_pair, alt((tag(" -> "), tag("\n")))), // Somehow this cant be `newline` because type deduction goes awry
|(width, height), (x, y)| (width.max(x + 1), height.max(y + 1)),
)(input)
}
fn parse_cave(input: &[u8]) -> IResult<&[u8], Cave> {
let (width, height) = find_dimensions(input)?.1;
let floor = height + 1;
// Assume parsing went somewhat right
debug_assert_ne!(width, 0);
debug_assert_ne!(height, 0);
let mut cave = Cave {
width,
height,
occupied: IndexSet::with_capacity(width * floor),
floor,
};
let mut input = input;
while input != &b""[..] {
let new_input = terminated(
reduce_many1(
terminated(parse_pair, opt(tag(" -> "))),
|(x_old, y_old), (x_prime, y_prime)| {
if x_prime == x_old {
for y in (y_old.min(y_prime))..=(y_old.max(y_prime)) {
cave.insert(x_old, y);
}
} else {
for x in (x_old.min(x_prime))..=(x_old.max(x_prime)) {
cave.insert(x, y_old);
}
}
(x_prime, y_prime)
},
),
newline,
)(input)?
.0;
input = new_input;
}
Ok((input, cave))
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut cave = parse_input(input, parse_cave)?;
let mut total = 0;
cave.drop(500, 0, &mut total);
Ok(total.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut cave = parse_input(input, parse_cave)?;
let mut total = 0;
cave.drop2(500, 0, &mut total);
Ok(total.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/14.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "24");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "93")
}
}

View File

@@ -1,9 +1,178 @@
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use ahash::AHashSet;
use anyhow::Result;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::many0;
use nom::sequence::pair;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
use crate::common::Vec2;
struct Beacon {
pos: Vec2,
closest: Vec2,
range: i32,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Beacon {
pub fn can_contain_unseen(&self, lower: Vec2, upper: Vec2) -> bool {
let corners = [
lower,
upper,
Vec2([lower[0], upper[1]]),
Vec2([upper[0], lower[1]]),
];
corners
.into_iter()
.any(|c| (c - self.pos).l1() > self.range)
}
}
fn parse_pos(input: &[u8]) -> IResult<&[u8], Vec2> {
use nom::character::complete::i32;
map(
pair(preceded(tag("x="), i32), preceded(tag(", y="), i32)),
|(x, y)| Vec2([x, y]),
)(input)
}
fn parse_beacons(input: &[u8]) -> IResult<&[u8], Vec<Beacon>> {
let parse_beacon = map(
pair(
preceded(tag("Sensor at "), parse_pos),
preceded(tag(": closest beacon is at "), parse_pos),
),
|(pos, closest)| Beacon {
pos,
closest,
range: (pos - closest).l1(),
},
);
many0(terminated(parse_beacon, newline))(input)
}
fn part1_generic<const Y: i32>(input: &[u8]) -> Result<String> {
let beacons = parse_input(input, parse_beacons)?;
let mut not_blocking_yet = BinaryHeap::new();
let mut blocking = BinaryHeap::new();
let mut total = 0;
let mut on_line = AHashSet::new();
for beacon in beacons {
let horizontal_distance = beacon.range - (beacon.pos[1] - Y).abs();
if horizontal_distance >= 0 {
not_blocking_yet.push(Reverse((
beacon.pos[0] - horizontal_distance,
beacon.pos[0] + horizontal_distance + 1,
)))
}
// Beacons can be beacons, so we should uncount them
if beacon.closest[1] == Y {
on_line.insert(beacon.closest);
}
}
while let Some(Reverse((block_from, mut block_until))) = not_blocking_yet.pop() {
blocking.push(Reverse(block_until));
while let Some(Reverse(block_end)) = blocking.pop() {
block_until = block_until.max(block_end);
while matches!(not_blocking_yet.peek(), Some(Reverse((block_from, _))) if block_from < &block_end)
{
let Reverse((_, additional_block_until)) = not_blocking_yet.pop().unwrap();
blocking.push(Reverse(additional_block_until));
}
}
total += block_until - block_from;
}
total -= on_line.len() as i32;
Ok(total.to_string())
}
pub fn part1(input: &[u8]) -> Result<String> {
part1_generic::<2_000_000>(input)
}
fn part2_generic<const MAX: i32>(input: &[u8]) -> Result<String> {
let beacons = parse_input(input, parse_beacons)?;
fn find_unseen<const MAX: i32>(beacons: &[Beacon]) -> Result<Vec2> {
let mut todo = vec![(Vec2([0, 0]), Vec2([MAX, MAX]))];
while let Some((lower, upper)) = todo.pop() {
if lower == upper {
if beacons
.iter()
.all(|beacon| (beacon.pos - lower).l1() > beacon.range)
{
return Ok(lower);
}
} else {
let mid = (lower + upper) / 2;
let quads = [
(lower, mid),
(Vec2([lower[0], mid[1] + 1]), Vec2([mid[0], upper[1]])),
(Vec2([mid[0] + 1, lower[1]]), Vec2([upper[0], mid[1]])),
(Vec2([mid[0] + 1, mid[1] + 1]), upper),
];
for (lower_new, upper_new) in quads {
if lower_new[0] > upper_new[0] || lower_new[1] > upper_new[1] {
// Empty quad in quad tree, skip
} else if beacons
.iter()
.all(|beacon| beacon.can_contain_unseen(lower_new, upper_new))
{
todo.push((lower_new, upper_new));
}
}
}
}
anyhow::bail!("Did not find position")
}
let Vec2([x, y]) = find_unseen::<MAX>(&beacons)?;
Ok((i64::from(x) * 4_000_000 + i64::from(y)).to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
part2_generic::<4_000_000>(input)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/15.txt");
#[test]
fn sample_part1() {
assert_eq!(part1_generic::<10>(SAMPLE).unwrap(), "26");
}
#[test]
fn sample_part2() {
assert_eq!(part2_generic::<20>(SAMPLE).unwrap(), "56000011");
}
}

View File

@@ -1,9 +1,166 @@
use std::ops::Deref;
use ahash::AHashMap;
use anyhow::Result;
use ndarray::Array2;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::alpha1;
use nom::character::complete::newline;
use nom::combinator::into;
use nom::multi::many1;
use nom::multi::separated_list1;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
type ParsedValve<'a> = (&'a [u8], u16, Vec<&'a [u8]>);
type ParsedNetwork<'a> = Vec<ParsedValve<'a>>;
#[derive(Debug)]
struct SimpleNetwork {
valves: Vec<SimpleValve>,
start: usize,
useful: usize,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Deref for SimpleNetwork {
type Target = [SimpleValve];
fn deref(&self) -> &Self::Target {
&self.valves
}
}
#[derive(Debug)]
struct SimpleValve {
connected: Vec<usize>,
flow: u16,
}
impl From<ParsedNetwork<'_>> for SimpleNetwork {
fn from(mut parsed: ParsedNetwork) -> Self {
// Make sure the positive numbers are in the front
parsed.sort_by(|a, b| b.1.cmp(&a.1));
let mapping: AHashMap<_, _> = parsed
.iter()
.enumerate()
.map(|(index, (name, _, _))| (*name, index))
.collect();
let useful = parsed.iter().filter(|(_, flow, _)| *flow > 0).count();
Self {
valves: parsed
.into_iter()
.map(|(_, flow, connected)| {
let connected = connected.into_iter().map(|name| mapping[&name]).collect();
SimpleValve { connected, flow }
})
.collect(),
start: mapping[&b"AA"[..]],
useful,
}
}
}
fn parse_network(input: &[u8]) -> IResult<&[u8], ParsedNetwork> {
let parse_network = terminated(
tuple((
// Parse the name of the valve
preceded(tag("Valve "), alpha1),
// Parse the flow of the valve
preceded(tag(" has flow rate="), nom::character::complete::u16),
// Parse the connections
preceded(
// Did you really have to distinguish plural
alt((
tag("; tunnels lead to valves "),
tag("; tunnel leads to valve "),
)),
separated_list1(tag(", "), alpha1),
),
)),
newline,
);
many1(parse_network)(input)
}
pub fn part1(input: &[u8]) -> Result<String> {
let network: SimpleNetwork = parse_input(input, into(parse_network))?;
let (valves_available, dp) = run_optimization(&network, 30);
Ok(dp[(network.start, valves_available)].to_string())
}
fn run_optimization(network: &SimpleNetwork, time: usize) -> (usize, Array2<u16>) {
let valves_available = (1 << network.useful) - 1;
let mut cur = Array2::zeros((network.len(), valves_available + 1));
let mut prev = cur.clone();
for time_remaining in 1..time {
for pos in 0..network.len() {
let bit = 1 << pos;
for open_valves in 0..=valves_available {
let optimal = if (bit & open_valves) != 0 && time_remaining > 2 {
prev[(pos, open_valves - bit)] + time_remaining as u16 * network[pos].flow
} else {
0
};
cur[(pos, open_valves)] = network[pos]
.connected
.iter()
.map(|&other| prev[(other, open_valves)])
.fold(optimal, Ord::max);
}
}
std::mem::swap(&mut prev, &mut cur);
}
(valves_available, prev)
}
pub fn part2(input: &[u8]) -> Result<String> {
let network: SimpleNetwork = parse_input(input, into(parse_network))?;
let (valves_available, dp) = run_optimization(&network, 26);
// Find the minimum of all combinations of your work/elephant's work
let best = (0..=valves_available)
.map(|my_valves| {
let elephant_valves = valves_available - my_valves;
dp[(network.start, my_valves)] + dp[(network.start, elephant_valves)]
})
.max()
.unwrap_or(0);
// Guesses: 1802 (too low)
Ok(best.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/16.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "1651");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "1707");
}
}

View File

@@ -1,9 +1,239 @@
use anyhow::Result;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::IndexSet;
const SHAPES: [&[&[bool]]; 5] = [
&[&[true; 4]],
&[&[false, true, false], &[true; 3], &[false, true, false]],
&[&[false, false, true], &[false, false, true], &[true; 3]],
&[&[true], &[true], &[true], &[true]],
&[&[true; 2], &[true; 2]],
];
const WIDTH: usize = 7;
#[allow(unused)]
fn print_cavern(cavern: &IndexSet, max_height: usize) {
for y in (0..=max_height).rev() {
for x in 0..7 {
print!(
"{}",
if cavern.contains(y * WIDTH + x) {
'#'
} else {
'.'
}
);
}
println!();
}
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn collides(shape: &[&[bool]], cavern: &IndexSet, x: usize, y: usize) -> bool {
for (row, line) in shape.iter().enumerate() {
if x + line.len() > WIDTH {
return true;
}
for (col, &on) in line.iter().enumerate().rev() {
if on && cavern.contains((y - row) * WIDTH + x + col) {
return true;
}
}
}
false
}
fn simulate(
mut cavern: IndexSet,
shapes: impl Iterator<Item = &'static &'static [&'static [bool]]>,
mut gusts: impl Iterator<Item = isize>,
mut max_height: usize,
) -> usize {
for &shape in shapes {
let mut x = 2usize;
let mut y = max_height + shape.len() + 2;
// Acquire gust of wind
for offset in gusts.by_ref() {
if let Some(nx) = x.checked_add_signed(offset) {
if !collides(shape, &cavern, nx, y) {
x = nx;
}
} else {
// Hit the left wall
}
// Move down if possible
if y >= shape.len() && !collides(shape, &cavern, x, y - 1) {
y -= 1;
} else {
break;
}
}
// If we get here we've successfully stopped falling
max_height = max_height.max(y + 1);
for (row, line) in shape.iter().enumerate() {
for (col, &on) in line.iter().enumerate() {
if on {
cavern.insert((y - row) * WIDTH + x + col);
}
}
}
}
max_height
}
pub fn part1(input: &[u8]) -> Result<String> {
// Poor man's trim()
let input = if input[input.len() - 1] == b'\n' {
&input[..input.len() - 1]
} else {
input
};
let gusts = input
.iter()
.cycle()
.map(|&b| if b == b'<' { -1 } else { 1 });
Ok(simulate(
IndexSet::default(),
SHAPES.iter().cycle().take(2022),
gusts,
0,
)
.to_string())
}
#[derive(Clone, Copy, Debug)]
struct HeightMap([usize; 7]);
impl HeightMap {
fn max(&self) -> &usize {
self.0.iter().max().unwrap()
}
}
impl PartialEq for HeightMap {
fn eq(&self, other: &Self) -> bool {
let self_min = *self.0.iter().min().unwrap();
let other_min = *other.0.iter().min().unwrap();
self.0
.iter()
.zip(&other.0)
.all(|(&a, &b)| a - self_min == b - other_min)
}
}
pub fn part2(input: &[u8]) -> Result<String> {
// Poor man's trim()
let input = if input[input.len() - 1] == b'\n' {
&input[..input.len() - 1]
} else {
input
};
let mut cavern = IndexSet::default();
let mut height_map = HeightMap([0; 7]);
let mut shapes = SHAPES.iter().enumerate().cycle();
let mut gusts = input
.iter()
.map(|&b| if b == b'<' { -1 } else { 1 })
.enumerate()
.cycle();
let mut tortoise = (0, 0, height_map);
let mut tortoise_time = 0;
let mut last_gust = 0;
const TARGET: usize = 1_000_000_000_000;
for (it, (shape_id, &shape)) in shapes.by_ref().enumerate() {
let mut x = 2usize;
let mut y = height_map.max() + shape.len() + 2;
// Acquire gust of wind
for (gust_id, offset) in gusts.by_ref() {
last_gust = gust_id;
if let Some(nx) = x.checked_add_signed(offset) {
if !collides(shape, &cavern, nx, y) {
x = nx;
}
} else {
// Hit the left wall
}
// Move down if possible
if y >= shape.len() && !collides(shape, &cavern, x, y - 1) {
y -= 1;
} else {
break;
}
}
// If we get here we've successfully stopped falling
for (row, line) in shape.iter().enumerate() {
for (col, &on) in line.iter().enumerate() {
if on {
height_map.0[x + col] = height_map.0[x + col].max(y - row + 1);
cavern.insert((y - row) * WIDTH + x + col);
}
}
}
// See if we found a circle
let hare_time = it + 1;
let hare = (shape_id, last_gust, height_map);
if hare == tortoise {
let cycle_len = hare_time - tortoise_time;
let remaining = TARGET - hare_time;
let to_skip = remaining / cycle_len;
let remainder = remaining % cycle_len;
let current_max = *height_map.max();
// All of them rose by the same amount so we just need to compare the first one
let delta = height_map.0[0] - tortoise.2 .0[0];
let result = simulate(
cavern,
shapes.map(|(_, shape)| shape).take(remainder),
gusts.map(|(_, offset)| offset),
current_max,
) + delta * to_skip;
return Ok(result.to_string());
} else if it.count_ones() == 1 {
tortoise = hare;
tortoise_time = hare_time;
}
}
Ok(height_map.max().to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/17.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "3068");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "1514285714288");
}
}

View File

@@ -1,9 +1,148 @@
use ahash::AHashMap;
use ahash::AHashSet;
use anyhow::Context;
use anyhow::Result;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::fold_many1;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
fn parse_voxels(input: &[u8]) -> IResult<&[u8], AHashSet<[u8; 3]>> {
use nom::character::complete::u8;
fold_many1(
terminated(
map(
tuple((u8, preceded(tag(","), u8), preceded(tag(","), u8))),
|(x, y, z)| [x, y, z],
),
newline,
),
AHashSet::new,
|mut set, coord| {
set.insert(coord);
set
},
)(input)
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
pub fn part1(input: &[u8]) -> Result<String> {
let voxels = parse_input(input, parse_voxels)?;
let mut faces = 0;
for &voxel in &voxels {
for axis in 0..3 {
for offset in [-1, 1] {
let mut to_search = voxel;
to_search[axis] = to_search[axis].wrapping_add_signed(offset);
if !voxels.contains(&to_search) {
faces += 1;
}
}
}
}
Ok(faces.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let voxels = parse_input(input, parse_voxels)?;
let max = voxels
.iter()
.copied()
.flatten()
.max()
.context("No voxels?")?;
let mut outside = AHashMap::new();
let mut outside_candidates = AHashSet::new();
let mut todo = Vec::new();
let mut is_outside = |voxel: [u8; 3]| {
if let Some(&state) = outside.get(&voxel) {
return state;
}
let mut is_outside = false;
todo.push(voxel);
outside_candidates.insert(voxel);
'outer: while let Some(voxel) = todo.pop() {
for axis in 0..3 {
for offset in [-1, 1] {
let mut to_search = voxel;
if let Some(new_coord) = to_search[axis].checked_add_signed(offset) {
to_search[axis] = new_coord;
if voxels.contains(&to_search) {
// Filled voxels cannot lead outside
continue;
} else if new_coord >= max {
is_outside = true;
break 'outer;
} else if let Some(&state) = outside.get(&to_search) {
is_outside = state;
break 'outer;
} else if outside_candidates.insert(to_search) {
todo.push(to_search);
}
} else {
// Managed to get below zero, which is outside
is_outside = true;
break 'outer;
}
}
}
}
let map = |voxel| (voxel, is_outside);
outside.extend(todo.drain(..).map(map));
outside.extend(outside_candidates.drain().map(map));
is_outside
};
let mut faces = 0;
for &voxel in &voxels {
for axis in 0..3 {
for offset in [-1, 1] {
let mut to_search = voxel;
to_search[axis] = to_search[axis].wrapping_add_signed(offset);
if !voxels.contains(&to_search) && is_outside(to_search) {
faces += 1;
}
}
}
}
Ok(faces.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/18.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "64");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "58");
}
}

View File

@@ -1,9 +1,297 @@
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use anyhow::Result;
use nom::bytes::complete::tag;
use nom::character::complete::multispace1;
use nom::character::streaming::alpha1;
use nom::combinator::map_res;
use nom::combinator::opt;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
#[repr(usize)]
#[derive(Clone, Copy)]
enum Mineral {
Ore,
Clay,
Obsidian,
Geode,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl TryFrom<&'_ [u8]> for Mineral {
type Error = String;
fn try_from(value: &'_ [u8]) -> std::result::Result<Self, Self::Error> {
match value {
b"ore" => Ok(Self::Ore),
b"clay" => Ok(Self::Clay),
b"obsidian" => Ok(Self::Obsidian),
b"geode" => Ok(Self::Geode),
other => Err(format!(
"Invalid mineral '{}'",
String::from_utf8_lossy(other)
)),
}
}
}
#[derive(Debug)]
struct BluePrint {
id: u32,
costs: [[u8; 3]; 4],
}
impl BluePrint {
pub fn max_geodes(&self, time: u8) -> u8 {
/// How much would we produce if all we did was produce geode robots for the remaining time
fn ideal(remaining: u32) -> u32 {
if remaining <= 1 {
0
} else {
(remaining - 1) * remaining / 2
}
}
#[derive(Eq, PartialEq)]
struct State {
missed: u32,
got: u8,
time_left: u8,
resources: [u8; 3],
machines: [u8; 3],
}
impl Ord for State {
fn cmp(&self, other: &Self) -> Ordering {
Ordering::Equal
.then(other.missed.cmp(&self.missed))
.then(self.got.cmp(&other.got))
.then(self.time_left.cmp(&other.time_left))
.then(self.machines.cmp(&other.machines))
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
let max_needed = self.max_needed();
let mut todo = BinaryHeap::new();
let mut best = 0;
todo.push(State {
missed: 0,
got: 0,
time_left: time,
resources: [0; 3],
machines: [1, 0, 0],
});
while let Some(State {
missed,
got,
time_left,
resources,
machines,
}) = todo.pop()
{
let ideal_from_now = ideal(u32::from(time_left));
// Need to check again because we might've gotten a better result in the meantime.
if u32::from(best - got) >= ideal_from_now {
continue;
}
assert!(
todo.len() <= 1_000_000,
"Safety: got a todo list of len {}, best: {best}",
todo.len()
);
for (element, &costs) in self.costs.iter().enumerate() {
let Some(min_to_build) = self.until_buildable(costs, resources, machines) else {
break;
};
// +1 because we need a turn to build
let built_after = min_to_build + 1;
if built_after >= time_left {
continue;
}
// Ideally, would be written as a nice `array::from_fn`. It turns out that codegen
// for `array::from_fn` is very bad, and writing it out into this for loop reduces
// time taken by approximately 100%.
let mut resources_after = [0; 3];
for i in 0..3 {
resources_after[i] = resources[i] + machines[i] * built_after - costs[i];
}
let time_after = time_left - built_after;
if element == Mineral::Geode as usize {
let new_got = got + time_after;
best = best.max(new_got);
if u32::from(best - new_got) >= ideal(time_after.into()) {
continue;
}
todo.push(State {
missed,
got: new_got,
time_left: time_after,
resources: resources_after,
machines,
});
best = best.max(new_got);
} else {
if machines[element] >= max_needed[element]
|| u32::from(best - got) >= ideal(time_after.into())
{
continue;
}
let mut new_machines = machines;
new_machines[element] += 1;
let new_missed = ideal_from_now - ideal(u32::from(time_after));
todo.push(State {
missed: new_missed,
got,
time_left: time_after,
resources: resources_after,
machines: new_machines,
})
}
}
}
best
}
#[inline]
fn until_buildable(&self, costs: [u8; 3], resources: [u8; 3], machines: [u8; 3]) -> Option<u8> {
let mut min_to_build = 0;
for ((&cost, &avail), &machine) in costs.iter().zip(&resources).zip(&machines) {
if cost > avail {
if machine == 0 {
return None;
} else {
min_to_build = min_to_build.max((cost - avail + machine - 1) / machine);
}
}
}
Some(min_to_build)
}
fn max_needed(&self) -> [u8; 3] {
let mut max_needed = [0; 3];
for cost in &self.costs {
for (max, &new) in max_needed.iter_mut().zip(cost) {
*max = (*max).max(new);
}
}
max_needed
}
}
fn parse_blueprint(input: &[u8]) -> IResult<&[u8], BluePrint> {
use nom::character::complete::u32;
fn parse_mineral(input: &[u8]) -> IResult<&[u8], Mineral> {
map_res(alpha1, Mineral::try_from)(input)
}
fn parse_cost(input: &[u8]) -> IResult<&[u8], (u8, Mineral)> {
separated_pair(nom::character::complete::u8, tag(" "), parse_mineral)(input)
}
let (mut input, id) =
terminated(delimited(tag("Blueprint "), u32, tag(":")), multispace1)(input)?;
let mut costs: [[u8; 3]; 4] = Default::default();
let mut parse_robot = terminated(
tuple((
preceded(tag("Each "), parse_mineral),
preceded(tag(" robot costs "), parse_cost),
terminated(opt(preceded(tag(" and "), parse_cost)), tag(".")),
)),
multispace1,
);
for _ in 0..4 {
let (remaining, (element, (amount1, req1), cost2)) = parse_robot(input)?;
input = remaining;
costs[element as usize][req1 as usize] = amount1;
if let Some((amount2, req2)) = cost2 {
costs[element as usize][req2 as usize] = amount2;
}
}
Ok((input, BluePrint { id, costs }))
}
pub fn part1(input: &[u8]) -> Result<String> {
let blueprints = parse_input(input, many1(parse_blueprint))?;
Ok(blueprints
.into_iter()
.map(|bp| u32::from(bp.max_geodes(24)) * bp.id)
.sum::<u32>()
.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let blueprints = parse_input(input, many1(parse_blueprint))?;
let result: u32 = blueprints
.iter()
.take(3)
.map(|bp| u32::from(bp.max_geodes(32)))
.product();
Ok(result.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("./samples/19.txt");
fn get_samples() -> Vec<BluePrint> {
parse_input(SAMPLE, many1(parse_blueprint)).unwrap()
}
#[test]
fn sample_part1() {
let samples = get_samples();
assert_eq!(samples[0].max_geodes(24), 9);
assert_eq!(samples[1].max_geodes(24), 12);
assert_eq!(part1(SAMPLE).unwrap(), "33");
}
#[test]
fn sample_part2() {
let samples = get_samples();
assert_eq!(samples[0].max_geodes(32), 56);
assert_eq!(samples[1].max_geodes(32), 62);
}
}

View File

@@ -1,9 +1,133 @@
use std::cmp::Ordering;
use std::iter::once;
use anyhow::Context;
use anyhow::Result;
use nom::character::complete::newline;
use nom::multi::many0;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
fn parse_encrypted(input: &[u8]) -> IResult<&[u8], Vec<i64>> {
many0(terminated(nom::character::complete::i64, newline))(input)
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
// While looping around to find a spot to move to, you must ignore the piece itself, but for
// computing the answer, you shouldn't. This function does the latter.
fn step(steps: &[usize], mut start: usize, count: usize) -> usize {
for _ in 0..(count % steps.len()) {
start = steps[start];
}
start
}
fn move_between(prev: &mut [usize], next: &mut [usize], i: usize, before: usize, after: usize) {
if before == i || after == i {
return;
}
let before_i = prev[i];
let after_i = next[i];
// Remove i from its original place
prev[after_i] = before_i;
next[before_i] = after_i;
// Connect i properly to before
prev[before] = i;
next[i] = before;
// Connect i properly to after
prev[i] = after;
next[after] = i;
}
pub fn part1(input: &[u8]) -> Result<String> {
let encrypted = parse_input(input, parse_encrypted)?;
shuffle(&encrypted, 1)
}
fn shuffle(encrypted: &[i64], times: usize) -> Result<String> {
let mut next: Vec<_> = (1..encrypted.len()).chain(once(0)).collect();
let mut prev: Vec<_> = once(encrypted.len() - 1)
.chain(0..(encrypted.len() - 1))
.collect();
let len = encrypted.len() as i64;
let half_len = len / 2;
for _ in 0..times {
for (i, &value) in encrypted.iter().enumerate() {
let mut value = value % (len - 1);
if value < -half_len {
value += len - 1;
} else if value > half_len {
value -= len - 1;
}
match value.cmp(&0) {
Ordering::Less => {
let before = step(&prev, i, (-value) as usize);
let after = prev[before];
move_between(&mut prev, &mut next, i, before, after);
}
Ordering::Equal => continue,
Ordering::Greater => {
let after = step(&next, i, value as usize);
let before = next[after];
move_between(&mut prev, &mut next, i, before, after);
}
}
// print(&encrypted, &next);
}
}
let mut start = encrypted
.iter()
.position(|&v| v == 0)
.context("Could not find zero")?;
let mut sum = 0;
for _ in 0..3 {
start = step(&next, start, 1000);
sum += encrypted[start];
}
Ok(sum.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
const ENCRYPTION_KEY: i64 = 811_589_153;
let mut encrypted = parse_input(input, parse_encrypted)?;
encrypted.iter_mut().for_each(|v| *v *= ENCRYPTION_KEY);
shuffle(&encrypted, 10)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/20.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "3");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "1623178306");
}
}

View File

@@ -1,9 +1,191 @@
use ahash::AHashMap;
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::character::complete::alpha1;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::combinator::map_res;
use nom::multi::fold_many1;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
type Input<'a> = AHashMap<&'a [u8], Monkey<'a>>;
#[derive(Clone, Copy)]
enum Operation {
Mul,
Div,
Add,
Sub,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
impl Operation {
pub fn apply(self, first: i64, second: i64) -> i64 {
match self {
Operation::Mul => first * second,
Operation::Div => first / second,
Operation::Add => first + second,
Operation::Sub => first - second,
}
}
}
impl TryFrom<u8> for Operation {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
b'*' => Operation::Mul,
b'/' => Operation::Div,
b'+' => Operation::Add,
b'-' => Operation::Sub,
other => anyhow::bail!("Invalid operation: {other}"),
})
}
}
enum Monkey<'a> {
Operation(&'a [u8], &'a [u8], Operation),
Literal(i64),
}
fn parse_monkeys(input: &[u8]) -> IResult<&[u8], Input> {
let parse_monkey = terminated(
tuple((
alpha1,
preceded(
tag(": "),
alt((
map(nom::character::complete::i64, Monkey::Literal),
map(
tuple((
terminated(alpha1, tag(" ")),
map_res(take(1usize), |v: &[u8]| Operation::try_from(v[0])),
preceded(tag(" "), alpha1),
)),
|(first, operation, second)| Monkey::Operation(first, second, operation),
),
)),
),
)),
newline,
);
fold_many1(parse_monkey, AHashMap::new, |mut map, (name, monkey)| {
map.insert(name, monkey);
map
})(input)
}
fn evaluate(monkeys: &Input, start: &[u8]) -> i64 {
match &monkeys[start] {
Monkey::Operation(first, second, op) => {
let first = evaluate(monkeys, first);
let second = evaluate(monkeys, second);
op.apply(first, second)
}
Monkey::Literal(value) => *value,
}
}
enum IncompleteSide {
Left,
Right,
}
fn evaluate2(
monkeys: &Input,
start: &[u8],
) -> std::result::Result<i64, Vec<(i64, IncompleteSide, Operation)>> {
if start == b"humn" {
return Err(Vec::new());
}
match &monkeys[start] {
Monkey::Operation(first, second, op) => {
match (evaluate2(monkeys, first), evaluate2(monkeys, second)) {
(Ok(first), Ok(second)) => Ok(op.apply(first, second)),
(Ok(first), Err(mut incomplete)) => {
incomplete.push((first, IncompleteSide::Right, *op));
Err(incomplete)
}
(Err(mut incomplete), Ok(second)) => {
incomplete.push((second, IncompleteSide::Left, *op));
Err(incomplete)
}
(Err(_), Err(_)) => unreachable!("Should not happen on fair input"),
}
}
Monkey::Literal(val) => Ok(*val),
}
}
pub fn part1(input: &[u8]) -> Result<String> {
let monkeys = parse_input(input, parse_monkeys)?;
Ok(evaluate(&monkeys, b"root").to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let monkeys = parse_input(input, parse_monkeys)?;
let Monkey::Operation(first, second, _) = &monkeys[&b"root"[..]] else {
anyhow::bail!("root is a literal somehow")
};
let result = match (evaluate2(&monkeys, first), evaluate2(&monkeys, second)) {
(Ok(_), Ok(_)) => anyhow::bail!("both arms succeeded"),
(Ok(goal), Err(incomplete)) | (Err(incomplete), Ok(goal)) => incomplete
.into_iter()
.rev()
.fold(goal, |next, (complete, arm, op)| match (op, arm) {
// Multiplication and addition are commutative so the arm doesn't matter
(Operation::Mul, _) => {
// This was a very useful sanity check
debug_assert_eq!(next % complete, 0);
next / complete
}
(Operation::Add, _) => next - complete,
// The other operations need some tweaking. x: unknown quantity. c: known quantity. n: current value
// x - c = n -> x = n + c
(Operation::Sub, IncompleteSide::Left) => next + complete,
// c - x = n -> c = n + x -> c - n = x
(Operation::Sub, IncompleteSide::Right) => complete - next,
// Similarly for division, if we miss the left arm we can undo the division and multiply instead
// x / c = n -> x = n * c
(Operation::Div, IncompleteSide::Left) => next * complete,
// c / x = n -> c = n * x -> c / n = x
(Operation::Div, IncompleteSide::Right) => complete / next,
}),
(Err(_), Err(_)) => anyhow::bail!("both arms failed"),
};
Ok(result.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/21.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "152");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "301");
}
}

View File

@@ -1,9 +1,456 @@
use std::mem;
use anyhow::Context;
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::combinator::value;
use nom::multi::many1;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::parse_input;
// This describes the transitions between the different squares.
//
// For every direction, write down which direction you end up going, in which square, and
// whether you should flip the axis.
//
// The squares are laid out as follows:
//
// #01
// #2#
// 34#
// 5##
//
// Entries are specified right, down, left, up.
#[allow(dead_code)]
const TRANSITIONS: [[(Direction, usize, bool); 4]; 6] = [
// Square 0
[
(Direction::Right, 1, false),
(Direction::Down, 2, false),
(Direction::Right, 3, true),
(Direction::Right, 5, false),
],
// Square 1
[
(Direction::Left, 4, true),
(Direction::Left, 2, false),
(Direction::Left, 0, false),
(Direction::Up, 5, false),
],
// Square 2
[
(Direction::Up, 1, false),
(Direction::Down, 4, false),
(Direction::Down, 3, false),
(Direction::Up, 0, false),
],
// Square 3
[
(Direction::Right, 4, false),
(Direction::Down, 5, false),
(Direction::Right, 0, true),
(Direction::Right, 2, false),
],
// Square 4
[
(Direction::Left, 1, true),
(Direction::Left, 5, false),
(Direction::Left, 3, false),
(Direction::Up, 2, false),
],
// Square 5
[
(Direction::Up, 4, false),
(Direction::Down, 1, false),
(Direction::Down, 0, false),
(Direction::Up, 3, false),
],
];
#[derive(Clone, Copy, Debug)]
enum Step {
Forward(u32),
Left,
Right,
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
#[derive(Clone, Copy, Debug)]
enum Direction {
Up = 3,
Down = 1,
Left = 2,
Right = 0,
}
type Map<'a> = Vec<&'a [u8]>;
impl Direction {
fn turn_left(self) -> Self {
match self {
Direction::Up => Direction::Left,
Direction::Down => Direction::Right,
Direction::Left => Direction::Down,
Direction::Right => Direction::Up,
}
}
fn turn_right(self) -> Self {
match self {
Direction::Up => Direction::Right,
Direction::Down => Direction::Left,
Direction::Left => Direction::Up,
Direction::Right => Direction::Down,
}
}
}
fn parse_map(input: &[u8]) -> IResult<&[u8], (Map, Vec<Step>)> {
separated_pair(
map(take_until("\n\n"), |map: &[u8]| {
map.split(|&b| b == b'\n').collect()
}),
tag("\n\n"),
terminated(
many1(alt((
map(nom::character::complete::u32, Step::Forward),
value(Step::Right, tag("R")),
value(Step::Left, tag("L")),
))),
newline,
),
)(input)
}
fn find_starting_x(top_row: &[u8]) -> Result<usize> {
top_row
.iter()
.position(|&b| b == b'.')
.context("Could not find starting position")
}
pub fn part1(input: &[u8]) -> Result<String> {
let (map, steps) = parse_input(input, parse_map)?;
let mut dir = Direction::Right;
let mut y = 0;
let mut x = find_starting_x(map[y])?;
for step in steps {
match step {
Step::Forward(amount) => match dir {
Direction::Up => {
for _ in 0..amount {
if y == 0 || map[y - 1].get(x).map_or(true, |&b| b == b' ') {
let new_y = map
.iter()
.rposition(|line| {
line.get(x).map_or(false, |&b| b == b'.' || b == b'#')
})
.unwrap();
if map[new_y][x] == b'#' {
break;
} else {
y = new_y;
}
} else if map[y - 1][x] == b'#' {
break;
} else {
y -= 1;
}
}
}
Direction::Down => {
for _ in 0..amount {
if y + 1 >= map.len() || map[y + 1].get(x).map_or(true, |&b| b == b' ') {
let new_y = map
.iter()
.position(|line| {
line.get(x).map_or(false, |&b| b == b'.' || b == b'#')
})
.unwrap();
if map[new_y][x] == b'#' {
break;
} else {
y = new_y;
}
} else if map[y + 1][x] == b'#' {
break;
} else {
y += 1;
}
}
}
Direction::Left => {
for _ in 0..amount {
if x == 0 || map[y][x - 1] == b' ' {
let new_x = map[y]
.iter()
.rposition(|&b| b == b'.' || b == b'#')
.unwrap();
if map[y][new_x] == b'.' {
x = new_x;
} else {
break;
}
} else if map[y][x - 1] == b'#' {
break;
} else {
x -= 1;
}
}
}
Direction::Right => {
for _ in 0..amount {
if x + 1 >= map[y].len() || map[y][x + 1] == b' ' {
let new_x =
map[y].iter().position(|&b| b == b'.' || b == b'#').unwrap();
if map[y][new_x] == b'.' {
x = new_x;
} else {
break;
}
} else if map[y][x + 1] == b'#' {
break;
} else {
x += 1;
}
}
}
},
Step::Left => dir = dir.turn_left(),
Step::Right => dir = dir.turn_right(),
}
}
Ok((1000 * (y + 1) + 4 * (x + 1) + dir as usize).to_string())
}
fn side_length_of(map: &[&[u8]]) -> usize {
let taken_tiles = map
.iter()
.flat_map(|r| r.iter())
.filter(|c| !c.is_ascii_whitespace())
.count();
// Future Bert: this needs to be an integer square root.
((taken_tiles / 6) as f64).sqrt() as usize
}
fn break_squares<'a>(map: &[&'a [u8]], side_length: usize) -> [(Map<'a>, usize, usize); 6] {
let mut result: [(Map<'a>, usize, usize); 6] = Default::default();
let mut row_holder = [(); 4].map(|_| Map::new());
let mut index = 0;
for (y, block_row) in map.chunks_exact(side_length).enumerate() {
for row in block_row {
for (i, segment) in row.chunks_exact(side_length).enumerate() {
if segment[0] != b' ' {
row_holder[i].push(segment);
}
}
}
for (x, potential_side) in row_holder.iter_mut().enumerate() {
if !potential_side.is_empty() {
mem::swap(potential_side, &mut result[index].0);
result[index].1 = x;
result[index].2 = y;
index += 1;
}
}
}
result
}
pub fn part2(input: &[u8]) -> Result<String> {
let (map, steps) = parse_input(input, parse_map)?;
let side_length = side_length_of(&map);
let squares = break_squares(&map, side_length);
let convert_coords = |square: usize, x: usize, y: usize| {
let offset_x = squares[square].1 * side_length + x + 1;
let offset_y = squares[square].2 * side_length + y + 1;
(offset_x, offset_y)
};
let mut current_square = 0;
let mut y = 0;
let mut x = find_starting_x(squares[current_square].0[y])?;
let mut dir = Direction::Right;
for step in steps {
match step {
Step::Left => dir = dir.turn_left(),
Step::Right => dir = dir.turn_right(),
Step::Forward(mut amount) => {
'outer: while amount > 0 {
let map = &squares[current_square].0;
let coord = match dir {
Direction::Up => {
while amount > 0 {
if y == 0 {
break;
} else if map[y - 1][x] == b'#' {
break 'outer;
} else {
y -= 1;
amount -= 1;
}
}
x
}
Direction::Down => {
while amount > 0 {
if y + 1 >= side_length {
break;
} else if map[y + 1][x] == b'#' {
break 'outer;
} else {
amount -= 1;
y += 1;
}
}
x
}
Direction::Left => {
while amount > 0 {
if x == 0 {
break;
} else if map[y][x - 1] == b'#' {
break 'outer;
} else {
x -= 1;
amount -= 1;
}
}
y
}
Direction::Right => {
while amount > 0 {
if x + 1 >= side_length {
break;
} else if map[y][x + 1] == b'#' {
break 'outer;
} else {
amount -= 1;
x += 1;
}
}
y
}
};
if amount > 0 {
let (new_dir, new_square, invert) =
TRANSITIONS[current_square][dir as usize];
let flipped_coord = if invert {
side_length - 1 - coord
} else {
coord
};
let (new_x, new_y) = match new_dir {
Direction::Up => (flipped_coord, side_length - 1),
Direction::Down => (flipped_coord, 0),
Direction::Left => (side_length - 1, flipped_coord),
Direction::Right => (0, flipped_coord),
};
if squares[new_square].0[new_y][new_x] == b'#' {
break 'outer;
}
x = new_x;
y = new_y;
current_square = new_square;
dir = new_dir;
amount -= 1;
}
}
}
}
}
let (real_x, real_y) = convert_coords(current_square, x, y);
Ok((1000 * real_y + 4 * real_x + dir as usize).to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/22.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "6032");
}
#[test]
fn test_side_length() {
let (map, _) = parse_input(SAMPLE, parse_map).unwrap();
assert_eq!(side_length_of(&map), 4);
}
#[test]
fn test_break_squares() {
let (map, _) = parse_input(SAMPLE, parse_map).unwrap();
let side_length = side_length_of(&map);
let squares = break_squares(&map, side_length);
assert_eq!(squares[0].1, 2);
assert_eq!(squares[0].2, 0);
assert_eq!(squares[5].1, 3);
assert_eq!(squares[5].2, 2);
for square in squares {
assert_eq!(square.0.len(), side_length);
for row in square.0 {
assert_eq!(row.len(), side_length);
}
}
}
#[test]
fn test_sanity_transitions() {
for (cur_face, &face) in TRANSITIONS.iter().enumerate() {
for (dir, (arrive_dir, arrive_face, invert)) in face.into_iter().enumerate() {
let inverse_dir = (arrive_dir as usize + 2) % 4;
let (back_dir, back_face, back_invert) = TRANSITIONS[arrive_face][inverse_dir];
assert_eq!(
invert, back_invert,
"Reciprocal invert failed: face {cur_face} dir {dir} to face {arrive_face} arrives as {arrive_dir:?}"
);
assert_eq!(back_face, cur_face, "Reciprocal transition failed: face {cur_face} dir {dir} arrives at {arrive_face} but returns at {back_face}");
let correct_back_dir = (dir + 2) % 4;
assert_eq!(back_dir as usize, correct_back_dir, "Reciprocal direction failed: face {cur_face} dir {dir} did not arrive the opposite direction from {arrive_face}");
}
}
}
}

View File

@@ -1,9 +1,205 @@
use std::collections::hash_map::Entry;
use std::ops::RangeInclusive;
use ahash::AHashMap;
use ahash::AHashSet;
use anyhow::Context;
use anyhow::Result;
use itertools::Itertools;
use nom::bytes::complete::take_until;
use nom::character::complete::newline;
use nom::multi::fold_many1;
use nom::sequence::terminated;
use nom::IResult;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
use crate::common::enumerate;
use crate::common::parse_input;
use crate::common::Vec2;
const OPTIONS: [[Vec2; 3]; 4] = [
// North
[Vec2([0, -1]), Vec2([-1, -1]), Vec2([1, -1])],
// South
[Vec2([0, 1]), Vec2([-1, 1]), Vec2([1, 1])],
// West
[Vec2([-1, 0]), Vec2([-1, -1]), Vec2([-1, 1])],
// East
[Vec2([1, 0]), Vec2([1, -1]), Vec2([1, 1])],
];
fn parse_elves(input: &[u8]) -> IResult<&[u8], AHashSet<Vec2>> {
fold_many1(
enumerate(terminated(take_until("\n"), newline)),
AHashSet::new,
|mut elves, (y, line): (usize, &[u8])| {
let y = y as i32;
elves.extend(
line.iter()
.enumerate()
.filter_map(|(x, &val)| (val == b'#').then_some(Vec2([x as i32, y]))),
);
elves
},
)(input)
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn determine_bounding_box(
elves: &AHashSet<Vec2>,
) -> Result<(RangeInclusive<i32>, RangeInclusive<i32>)> {
let (x_min, x_max) = elves
.iter()
.map(|&Vec2([x, _])| x)
.minmax()
.into_option()
.context("Could not determine x range")?;
let (y_min, y_max) = elves
.iter()
.map(|&Vec2([_, y])| y)
.minmax()
.into_option()
.context("Could not determine y range")?;
Ok((x_min..=x_max, y_min..=y_max))
}
#[allow(unused)]
fn print(elves: &AHashSet<Vec2>) -> Result<()> {
let (x_bounds, y_bounds) = determine_bounding_box(elves)?;
for y in y_bounds {
for x in x_bounds.clone() {
print!(
"{}",
if elves.contains(&Vec2([x, y])) {
'#'
} else {
'.'
}
);
}
println!();
}
Ok(())
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut elves = parse_input(input, parse_elves)?;
simulate(&mut elves, 10);
let (x_bounds, y_bounds) = determine_bounding_box(&elves)?;
let area = (x_bounds.end() - x_bounds.start() + 1) * (y_bounds.end() - y_bounds.start() + 1);
let free = area - elves.len() as i32;
Ok(free.to_string())
}
fn simulate(elves: &mut AHashSet<Vec2>, max: usize) -> Option<usize> {
let mut todo = Vec::new();
let mut to_return = Vec::new();
let mut origin = AHashMap::new();
for it in 0..max {
// Remove all todos from a previous iteration
todo.clear();
// Find all the elves with at least one neighbour
todo.extend(elves.iter().copied().filter(|&Vec2([x, y])| {
for dx in [-1, 0, 1] {
for dy in [-1, 0, 1] {
if dx == 0 && dy == 0 {
continue;
}
if elves.contains(&Vec2([x + dx, y + dy])) {
return true;
}
}
}
false
}));
for &elf in &todo {
let mut moved = false;
for &deltas in OPTIONS[(it % 4)..].iter().chain(&OPTIONS[..(it % 4)]) {
if deltas
.into_iter()
.all(|delta| !elves.contains(&(elf + delta)))
{
// Observation: any collision will only happen between opposite pairs of elves,
// not three. Otherwise they wouldn't have chosen to move this direction.
// Somewhat messy but it avoids computing the hash more than once per elf
match origin.entry(deltas[0] + elf) {
Entry::Occupied(entry) => {
to_return.push(elf);
to_return.push(entry.remove());
}
Entry::Vacant(entry) => {
entry.insert(elf);
}
};
// We moved, or collided, but we shouldn't look other directions any more
moved = true;
break;
}
}
if !moved {
to_return.push(elf);
}
}
if origin.is_empty() {
return Some(it + 1);
}
// Remove entries we processed
for elf in &todo {
elves.remove(elf);
}
// Add back any entries we ended up not moving
elves.extend(to_return.drain(..));
// Add all the elves in their new positions
elves.extend(origin.drain().map(|(dest, _)| dest));
}
None
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut elves = parse_input(input, parse_elves)?;
let first_non_moved = simulate(&mut elves, usize::MAX).context("Elves didn't stop moving?")?;
Ok(first_non_moved.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("./samples/23.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "110");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "20");
}
}

View File

@@ -1,9 +1,214 @@
use std::collections::VecDeque;
use std::mem;
use ahash::AHashSet;
use anyhow::Context;
use anyhow::Result;
use strength_reduce::StrengthReducedUsize;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
fn gcd(mut a: usize, mut b: usize) -> usize {
while a % b != 0 {
b = a % b;
mem::swap(&mut a, &mut b);
}
b
}
pub fn part2(_input: &[u8]) -> Result<String> {
todo!()
fn lcm(a: usize, b: usize) -> usize {
a * b / gcd(a, b)
}
#[derive(Debug)]
struct Storm {
// Dimensions of the entire area. Includes the wall
width: usize,
height: usize,
// Periods of repetition. Basically the dimensions without the wall
width_period: StrengthReducedUsize,
height_period: StrengthReducedUsize,
combined_period: StrengthReducedUsize,
// Flying blizzards by direction and starting point
left_right: AHashSet<(usize, usize)>,
right_left: AHashSet<(usize, usize)>,
top_bottom: AHashSet<(usize, usize)>,
bottom_top: AHashSet<(usize, usize)>,
}
impl Storm {
/// Whether you can stand in the given position at the given time
fn can_stand(&self, time: usize, (x, y): (usize, usize)) -> bool {
!self
.right_left
.contains(&((x + time) % self.width_period, y))
&& !self
.bottom_top
.contains(&(x, (y + time) % self.height_period))
&& !self.left_right.contains(&(
(self.width_period.get() - time % self.width_period + x) % self.width_period,
y,
))
&& !self.top_bottom.contains(&(
x,
(self.height_period.get() - time % self.height_period + y) % self.height_period,
))
}
fn dist(&self, from: (usize, usize), goal: (usize, usize), start: usize) -> Result<usize> {
let mut todo = VecDeque::new();
todo.push_back((start, from));
let mut visited = AHashSet::new();
while let Some((time, pos)) = todo.pop_front() {
let mut enqueue = |pos| {
let new_time = time + 1;
if self.can_stand(new_time, pos)
&& visited.insert((new_time % self.combined_period, pos))
{
todo.push_back((new_time, pos));
}
};
// Waiting is perhaps an option
enqueue(pos);
// If not in the starting position or the right edge
if pos.0 > 1 && pos.1 < self.height - 1 {
enqueue((pos.0 - 1, pos.1));
}
if pos.1 > 0 && pos.0 < self.width - 2 {
enqueue((pos.0 + 1, pos.1));
}
if pos.1 > 1 {
enqueue((pos.0, pos.1 - 1));
}
if pos.0 > 0 && pos.1 < self.height - 2 {
enqueue((pos.0, pos.1 + 1));
}
if pos.1 >= 1 && (pos.0, pos.1 - 1) == goal {
return Ok(time + 1);
}
if (pos.0, pos.1 + 1) == goal {
return Ok(time + 1);
}
}
anyhow::bail!("Did not find a route to {goal:?}")
}
}
impl TryFrom<&'_ [u8]> for Storm {
type Error = anyhow::Error;
fn try_from(value: &'_ [u8]) -> Result<Self, Self::Error> {
let width = value
.iter()
.position(|&b| b == b'\n')
.context("Could not find end of line")?;
let height = value.len() / (width + 1);
let width_period = StrengthReducedUsize::new(width - 2);
let height_period = StrengthReducedUsize::new(height - 2);
let combined_period = StrengthReducedUsize::new(lcm(width - 2, height - 2));
let mut left_right = AHashSet::new();
let mut right_left = AHashSet::new();
let mut top_bottom = AHashSet::new();
let mut bottom_top = AHashSet::new();
for (y, line) in value
.split(|&b| b == b'\n')
.enumerate()
.skip(1)
.take(height - 2)
{
for (x, &c) in line.iter().enumerate() {
match c {
b'>' => left_right.insert((x % width_period, y)),
b'<' => right_left.insert((x % width_period, y)),
b'v' => top_bottom.insert((x, y % height_period)),
b'^' => bottom_top.insert((x, y % height_period)),
_ => continue,
};
}
}
Ok(Storm {
width,
height,
width_period,
height_period,
combined_period,
left_right,
right_left,
top_bottom,
bottom_top,
})
}
}
pub fn part1(input: &[u8]) -> Result<String> {
let storm = Storm::try_from(input)?;
let goal = (storm.width - 2, storm.height - 1);
storm.dist((1, 0), goal, 0).map(|d| d.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let storm = Storm::try_from(input)?;
let goal = (storm.width - 2, storm.height - 1);
let there = storm.dist((1, 0), goal, 0)?;
let back_again = storm.dist(goal, (1, 0), there)?;
storm.dist((1, 0), goal, back_again).map(|s| s.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("./samples/24.txt");
#[test]
fn test_can_stand() {
let storm = Storm::try_from(SAMPLE).unwrap();
dbg!(&storm);
// Test a storm moving right to left
assert!(storm.can_stand(0, (4, 2)));
assert!(!storm.can_stand(1, (4, 2)));
assert!(!storm.can_stand(0, (6, 2)));
assert!(storm.can_stand(1, (6, 2)));
// Test a storm moving bottom to top
assert!(!storm.can_stand(0, (4, 4)));
assert!(storm.can_stand(1, (4, 4)));
// Simple moving to the right
assert!(!storm.can_stand(0, (1, 1)));
assert!(storm.can_stand(1, (1, 1)));
assert!(storm.can_stand(0, (1, 2)));
assert!(!storm.can_stand(1, (1, 2)));
}
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "18");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "54");
}
}

View File

@@ -1,5 +1,71 @@
use anyhow::Result;
pub fn part1(_input: &[u8]) -> Result<String> {
todo!()
fn parse_num(num: &[u8]) -> Result<i64> {
let mut total = 0;
let mut factor = 1;
for &b in num.iter().rev() {
match b {
b'0' => (),
b'1' => total += factor,
b'2' => total += 2 * factor,
b'-' => total -= factor,
b'=' => total -= 2 * factor,
other => anyhow::bail!("Invalid digit {other}"),
}
factor *= 5;
}
Ok(total)
}
fn encode(mut num: i64) -> String {
let mut buffer = Vec::new();
while num > 0 {
match num % 5 {
0 => buffer.push(b'0'),
1 => buffer.push(b'1'),
2 => buffer.push(b'2'),
3 => {
buffer.push(b'=');
num += 2
}
4 => {
buffer.push(b'-');
num += 1;
}
_ => unreachable!("math"),
}
num /= 5;
}
// We've built the string right to left, to print we must reverse
buffer.reverse();
// Safe unwrap as we've only pushed valid ascii characters
String::from_utf8(buffer).unwrap()
}
pub fn part1(input: &[u8]) -> Result<String> {
let total = input
.split(|&b| b == b'\n')
.map(parse_num)
.try_fold(0, |acc, val| val.map(|val| val + acc))?;
Ok(encode(total))
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("./samples/25.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "2=-1=0");
}
}

View File

@@ -56,6 +56,6 @@ fn main() -> Result<()> {
eprintln!("Execution time: {:?}", Instant::now().duration_since(begin));
}
println!("{}", result);
println!("{result}");
Ok(())
}

9
2022/src/samples/05.txt Normal file
View File

@@ -0,0 +1,9 @@
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2

23
2022/src/samples/07.txt Normal file
View File

@@ -0,0 +1,23 @@
$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k

5
2022/src/samples/08.txt Normal file
View File

@@ -0,0 +1,5 @@
30373
25512
65332
33549
35390

View File

@@ -0,0 +1,8 @@
R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20

8
2022/src/samples/09.txt Normal file
View File

@@ -0,0 +1,8 @@
R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2

146
2022/src/samples/10.txt Normal file
View File

@@ -0,0 +1,146 @@
addx 15
addx -11
addx 6
addx -3
addx 5
addx -1
addx -8
addx 13
addx 4
noop
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx 5
addx -1
addx -35
addx 1
addx 24
addx -19
addx 1
addx 16
addx -11
noop
noop
addx 21
addx -15
noop
noop
addx -3
addx 9
addx 1
addx -3
addx 8
addx 1
addx 5
noop
noop
noop
noop
noop
addx -36
noop
addx 1
addx 7
noop
noop
noop
addx 2
addx 6
noop
noop
noop
noop
noop
addx 1
noop
noop
addx 7
addx 1
noop
addx -13
addx 13
addx 7
noop
addx 1
addx -33
noop
noop
noop
addx 2
noop
noop
noop
addx 8
noop
addx -1
addx 2
addx 1
noop
addx 17
addx -9
addx 1
addx 1
addx -3
addx 11
noop
noop
addx 1
noop
addx 1
noop
noop
addx -13
addx -19
addx 1
addx 3
addx 26
addx -30
addx 12
addx -1
addx 3
addx 1
noop
noop
noop
addx -9
addx 18
addx 1
addx 2
noop
noop
addx 9
noop
noop
noop
addx -1
addx 2
addx -37
addx 1
addx 3
noop
addx 15
addx -21
addx 22
addx -6
addx 1
noop
addx 2
addx 1
noop
addx -10
noop
noop
addx 20
addx 1
addx 2
addx 2
addx -6
addx -11
noop
noop
noop

27
2022/src/samples/11.txt Normal file
View File

@@ -0,0 +1,27 @@
Monkey 0:
Starting items: 79, 98
Operation: new = old * 19
Test: divisible by 23
If true: throw to monkey 2
If false: throw to monkey 3
Monkey 1:
Starting items: 54, 65, 75, 74
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 2
If false: throw to monkey 0
Monkey 2:
Starting items: 79, 60, 97
Operation: new = old * old
Test: divisible by 13
If true: throw to monkey 1
If false: throw to monkey 3
Monkey 3:
Starting items: 74
Operation: new = old + 3
Test: divisible by 17
If true: throw to monkey 0
If false: throw to monkey 1

5
2022/src/samples/12.txt Normal file
View File

@@ -0,0 +1,5 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

23
2022/src/samples/13.txt Normal file
View File

@@ -0,0 +1,23 @@
[1,1,3,1,1]
[1,1,5,1,1]
[[1],[2,3,4]]
[[1],4]
[9]
[[8,7,6]]
[[4,4],4,4]
[[4,4],4,4,4]
[7,7,7,7]
[7,7,7]
[]
[3]
[[[]]]
[[]]
[1,[2,[3,[4,[5,6,7]]]],8,9]
[1,[2,[3,[4,[5,6,0]]]],8,9]

2
2022/src/samples/14.txt Normal file
View File

@@ -0,0 +1,2 @@
498,4 -> 498,6 -> 496,6
503,4 -> 502,4 -> 502,9 -> 494,9

14
2022/src/samples/15.txt Normal file
View File

@@ -0,0 +1,14 @@
Sensor at x=2, y=18: closest beacon is at x=-2, y=15
Sensor at x=9, y=16: closest beacon is at x=10, y=16
Sensor at x=13, y=2: closest beacon is at x=15, y=3
Sensor at x=12, y=14: closest beacon is at x=10, y=16
Sensor at x=10, y=20: closest beacon is at x=10, y=16
Sensor at x=14, y=17: closest beacon is at x=10, y=16
Sensor at x=8, y=7: closest beacon is at x=2, y=10
Sensor at x=2, y=0: closest beacon is at x=2, y=10
Sensor at x=0, y=11: closest beacon is at x=2, y=10
Sensor at x=20, y=14: closest beacon is at x=25, y=17
Sensor at x=17, y=20: closest beacon is at x=21, y=22
Sensor at x=16, y=7: closest beacon is at x=15, y=3
Sensor at x=14, y=3: closest beacon is at x=15, y=3
Sensor at x=20, y=1: closest beacon is at x=15, y=3

10
2022/src/samples/16.txt Normal file
View File

@@ -0,0 +1,10 @@
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
Valve BB has flow rate=13; tunnels lead to valves CC, AA
Valve CC has flow rate=2; tunnels lead to valves DD, BB
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
Valve EE has flow rate=3; tunnels lead to valves FF, DD
Valve FF has flow rate=0; tunnels lead to valves EE, GG
Valve GG has flow rate=0; tunnels lead to valves FF, HH
Valve HH has flow rate=22; tunnel leads to valve GG
Valve II has flow rate=0; tunnels lead to valves AA, JJ
Valve JJ has flow rate=21; tunnel leads to valve II

1
2022/src/samples/17.txt Normal file
View File

@@ -0,0 +1 @@
>>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>

13
2022/src/samples/18.txt Normal file
View File

@@ -0,0 +1,13 @@
2,2,2
1,2,2
3,2,2
2,1,2
2,3,2
2,2,1
2,2,3
2,2,4
2,2,6
1,2,5
3,2,5
2,1,5
2,3,5

11
2022/src/samples/19.txt Normal file
View File

@@ -0,0 +1,11 @@
Blueprint 1:
Each ore robot costs 4 ore.
Each clay robot costs 2 ore.
Each obsidian robot costs 3 ore and 14 clay.
Each geode robot costs 2 ore and 7 obsidian.
Blueprint 2:
Each ore robot costs 2 ore.
Each clay robot costs 3 ore.
Each obsidian robot costs 3 ore and 8 clay.
Each geode robot costs 3 ore and 12 obsidian.

7
2022/src/samples/20.txt Normal file
View File

@@ -0,0 +1,7 @@
1
2
-3
3
-2
0
4

15
2022/src/samples/21.txt Normal file
View File

@@ -0,0 +1,15 @@
root: pppw + sjmn
dbpl: 5
cczh: sllz + lgvd
zczc: 2
ptdq: humn - dvpt
dvpt: 3
lfqf: 4
humn: 5
ljgn: 2
sjmn: drzm * dbpl
sllz: 4
pppw: cczh / lfqf
lgvd: ljgn * ptdq
drzm: hmdt - zczc
hmdt: 32

14
2022/src/samples/22.txt Normal file
View File

@@ -0,0 +1,14 @@
...#
.#..
#...
....
...#.......#
........#...
..#....#....
..........#.
...#....
.....#..
.#......
......#.
10R5L5R10L4R5L5

12
2022/src/samples/23.txt Normal file
View File

@@ -0,0 +1,12 @@
..............
..............
.......#......
.....###.#....
...#...#.#....
....#...##....
...#.###......
...##.#.##....
....#..#......
..............
..............
..............

6
2022/src/samples/24.txt Normal file
View File

@@ -0,0 +1,6 @@
#.######
#>>.<^<#
#.<..<<#
#>v.><>#
#<^v^^>#
######.#

13
2022/src/samples/25.txt Normal file
View File

@@ -0,0 +1,13 @@
1=-0-2
12111
2=0=
21
2=01
111
20012
112
1=-1=
1-12
12
1=
122

25
2023/Cargo.toml Normal file
View File

@@ -0,0 +1,25 @@
[package]
name = "aoc-2023"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aho-corasick = "1.1.2"
anyhow = "1.0.75"
clap = { version = "4.4.8", features = ["derive"] }
linked-hash-map = "0.5.6"
nom = "7.1.3"
num-integer = "0.1.45"
[dev-dependencies]
criterion = "0.5.1"
[profile.release]
# Keep debug information in release for better flamegraphs
debug = true
[[bench]]
name = "days"
harness = false

44
2023/benches/days.rs Normal file
View File

@@ -0,0 +1,44 @@
use std::fs::File;
use std::io::Read;
use criterion::criterion_group;
use criterion::criterion_main;
use criterion::BenchmarkId;
use criterion::Criterion;
use aoc_2023::get_implementation;
/// Number of days we have an implementation to benchmark
const DAYS_IMPLEMENTED: u8 = 25;
fn read_input(day: u8) -> std::io::Result<Vec<u8>> {
let input_path = format!("inputs/{day:02}.txt");
let mut buffer = Vec::new();
File::open(input_path)?.read_to_end(&mut buffer)?;
Ok(buffer)
}
pub fn benchmark_days(c: &mut Criterion) {
for day in 1..=DAYS_IMPLEMENTED {
if let Ok(input) = read_input(day) {
let part1 = get_implementation(day, false).unwrap();
c.bench_with_input(BenchmarkId::new("part1", day), &input, |b, i| {
b.iter(|| part1(i));
});
if day < 25 {
let part2 = get_implementation(day, true).unwrap();
c.bench_with_input(BenchmarkId::new("part2", day), &input, |b, i| {
b.iter(|| part2(i));
});
}
}
}
}
criterion_group!(benches, benchmark_days);
criterion_main!(benches);

0
2023/inputs/.gitkeep Normal file
View File

383
2023/src/common.rs Normal file
View File

@@ -0,0 +1,383 @@
//! Common helper utilities to all days
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Display;
use std::ops::Add;
use std::ops::Div;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Sub;
use anyhow::Context;
use anyhow::Result;
use nom::combinator::map;
use nom::error::ErrorKind;
use nom::error::ParseError;
use nom::Finish;
use nom::IResult;
use nom::InputLength;
use nom::Parser;
pub fn convert_nom_error(e: nom::error::Error<&[u8]>) -> anyhow::Error {
anyhow::anyhow!(
"Parser error {:?} to parse at {}",
e.code,
String::from_utf8_lossy(e.input)
)
}
/// Parse input from some nom parser and return as an anyhow result
///
/// This method exists as a convenience because nom's errors cannot otherwise be easily converted to
/// an anyhow error, and I don't want to keep track of custom error implementations here.
pub fn parse_input<'a, O>(
input: &'a [u8],
mut parser: impl Parser<&'a [u8], O, nom::error::Error<&'a [u8]>>,
) -> Result<O> {
let (unparsed, output) = parser.parse(input).finish().map_err(convert_nom_error)?;
if !unparsed.is_empty() {
Err(anyhow::anyhow!(
"Not all input consumed: {}",
String::from_utf8_lossy(unparsed)
))
} else {
Ok(output)
}
}
/// Applies a parser iteratively and reduces the results using the given function. Fails if the
/// embedded parser doesn't return at least one result.
///
/// # Arguments
/// - `f`: the function to apply
/// - `g`: the function that combines the result o `f` with previous results
///
/// This implementation is based on [`nom::multi::fold_many1`] with minor differences. If
/// successful, this should probably be upstreamed.
#[allow(unused)]
pub fn reduce_many1<I, O, E, F>(
mut f: F,
mut g: impl FnMut(O, O) -> O,
) -> impl FnMut(I) -> IResult<I, O, E>
where
I: Clone + InputLength,
E: ParseError<I>,
F: Parser<I, O, E>,
{
// Cannot delegate to fold_many0 because that would make the function FnOnce rather than FnMut,
// since it would transfer ownership of the embedded parser to fold_many0.
move |i: I| {
let _i = i.clone();
match f.parse(_i) {
Err(nom::Err::Error(_)) => {
Err(nom::Err::Error(E::from_error_kind(i, ErrorKind::Many1)))
}
Err(e) => Err(e),
Ok((i1, mut acc)) => {
let mut input = i1;
loop {
let _input = input.clone();
let len = input.input_len();
match f.parse(_input) {
Err(nom::Err::Error(_)) => {
break;
}
Err(e) => return Err(e),
Ok((i, o)) => {
// infinite loop check: the parser must always consume
if i.input_len() == len {
return Err(nom::Err::Failure(E::from_error_kind(
i,
ErrorKind::Many1,
)));
}
acc = g(acc, o);
input = i;
}
}
}
Ok((input, acc))
}
}
}
}
/// Add an index to repeated successful invocations of the embedded parser.
#[allow(unused)]
pub fn enumerate<I, O, E>(f: impl Parser<I, O, E>) -> impl FnMut(I) -> IResult<I, (usize, O), E> {
let mut index = 0usize;
map(f, move |v| {
let res = (index, v);
index += 1;
res
})
}
/// Return the minimum and maximum of two unordered variables
#[allow(unused)]
pub fn minmax<T>(a: T, b: T) -> (T, T)
where
T: PartialOrd,
{
if a < b {
(a, b)
} else {
(b, a)
}
}
/// Some magic to get two mutable references into the same slice
#[allow(unused)]
pub fn get_both<T>(slice: &mut [T], first: usize, second: usize) -> (&mut T, &mut T) {
match first.cmp(&second) {
Ordering::Greater => {
let (begin, end) = slice.split_at_mut(first);
(&mut end[0], &mut begin[second])
}
Ordering::Less => {
let (begin, end) = slice.split_at_mut(second);
(&mut begin[first], &mut end[0])
}
Ordering::Equal => panic!("Tried to get the same index twice {first}"),
}
}
#[derive(Debug, Default)]
pub struct IndexSet(Vec<u32>);
impl IndexSet {
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(
capacity / std::mem::size_of::<u32>() / 8,
))
}
fn ensure_item(&mut self, item: usize) -> &mut u32 {
if self.0.len() <= item {
self.0.resize(item + 1, 0);
}
&mut self.0[item]
}
#[inline]
fn index(index: usize) -> (usize, u8) {
const PER_ENTRY: usize = 8 * std::mem::size_of::<u32>();
(index / PER_ENTRY, (index % PER_ENTRY) as u8)
}
pub fn insert(&mut self, index: usize) -> bool {
let (entry, pos) = Self::index(index);
let item = self.ensure_item(entry);
let old = *item;
*item |= 1 << pos;
old != *item
}
pub fn contains(&self, index: usize) -> bool {
let (entry, pos) = Self::index(index);
self.0
.get(entry)
.map_or(false, |&entry| (entry & (1 << pos) != 0))
}
}
#[allow(unused)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Vec2(pub [i32; 2]);
#[allow(unused)]
impl Vec2 {
pub fn l1(self) -> i32 {
self.0.into_iter().map(i32::abs).sum()
}
}
impl Add<Self> for Vec2 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self([self[0] + rhs[0], self[1] + rhs[1]])
}
}
impl Sub<Self> for Vec2 {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self([self[0] - rhs[0], self[1] - rhs[1]])
}
}
impl Div<i32> for Vec2 {
type Output = Self;
fn div(self, rhs: i32) -> Self::Output {
Self(self.0.map(|v| v / rhs))
}
}
impl Index<usize> for Vec2 {
type Output = i32;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl IndexMut<usize> for Vec2 {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
#[derive(PartialEq)]
pub struct Grid<T: AsRef<[u8]>> {
width: usize,
data: T,
}
impl<T: AsRef<[u8]>> Grid<T> {
pub fn new(data: T) -> anyhow::Result<Self> {
let width = 1 + data
.as_ref()
.iter()
.position(|&c| c == b'\n')
.context("Failed to find end of line in grid")?;
anyhow::ensure!(
data.as_ref().len() % width == 0,
"Grid should divide equally into rows"
);
Ok(Self { width, data })
}
pub fn height(&self) -> usize {
self.data.as_ref().len() / self.width
}
pub fn width(&self) -> usize {
self.width - 1
}
pub fn rows(&self) -> impl Iterator<Item = &[u8]> {
let width = self.width();
self.data
.as_ref()
.chunks_exact(self.width)
.map(move |row| &row[..width])
}
pub fn find(&self, c: u8) -> Option<(usize, usize)> {
let pos = self.data.as_ref().iter().position(|&d| d == c)?;
Some((pos % self.width, pos / self.width))
}
}
impl Grid<Vec<u8>> {
pub fn zeroed(width: usize, height: usize) -> Self {
let mut data = vec![0; (width + 1) * height];
for line_end in data[width..].iter_mut().step_by(width + 1) {
*line_end = b'\n';
}
Self {
width: width + 1,
data,
}
}
}
impl<T: AsMut<[u8]> + AsRef<[u8]>> Grid<T> {
pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [u8]> {
let width = self.width();
self.data
.as_mut()
.chunks_exact_mut(self.width)
.map(move |row| &mut row[..width])
}
}
impl<T: AsRef<[u8]>> Index<usize> for Grid<T> {
type Output = [u8];
fn index(&self, y: usize) -> &Self::Output {
let offset = y * self.width;
&self.data.as_ref()[offset..(offset + self.width())]
}
}
impl<T: AsRef<[u8]>> Index<(usize, usize)> for Grid<T> {
type Output = u8;
fn index(&self, (y, x): (usize, usize)) -> &Self::Output {
debug_assert!(y < self.height());
debug_assert!(x < self.width());
let offset = self.width * y + x;
&self.data.as_ref()[offset]
}
}
impl<T: AsRef<[u8]>> Display for Grid<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", String::from_utf8_lossy(self.data.as_ref()))
}
}
// Custom Clone impl so we don't allocate in `clone_from`
impl<T: AsRef<[u8]> + Clone> Clone for Grid<T> {
fn clone(&self) -> Self {
Self {
width: self.width,
data: self.data.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.width = source.width;
self.data.clone_from(&source.data);
}
}
impl<T: AsMut<[u8]> + AsRef<[u8]>> IndexMut<usize> for Grid<T> {
fn index_mut(&mut self, y: usize) -> &mut Self::Output {
let offset = y * self.width;
let width = self.width;
&mut self.data.as_mut()[offset..(offset + width)]
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Direction {
Up = 0,
Left = 1,
Down = 2,
Right = 3,
}
impl Direction {
pub fn bit(self) -> u8 {
1 << self as u8
}
pub fn is_vertical(self) -> bool {
matches!(self, Direction::Down | Direction::Up)
}
}

74
2023/src/day01.rs Normal file
View File

@@ -0,0 +1,74 @@
use aho_corasick::AhoCorasick;
use anyhow::Result;
pub fn part1(input: &[u8]) -> Result<String> {
let mut it = input.iter();
let mut sum = 0;
while let Some(&first) = it.find(|s| s.is_ascii_digit()) {
let mut last = first;
for &c in &mut it {
match c {
d @ b'0'..=b'9' => last = d,
b'\n' => break,
_ => continue,
}
}
sum += u32::from(10 * (first - b'0') + last - b'0');
}
Ok(sum.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let parser = AhoCorasick::new([
"1", "2", "3", "4", "5", "6", "7", "8", "9", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine",
])?;
fn convert_id(id: u32) -> Result<u32> {
Ok(match id {
0..=8 => id + 1,
9..=17 => id - 8,
_ => anyhow::bail!("unreachable"),
})
}
let mut sum = 0;
for line in input.split(|&c| c == b'\n') {
let mut it = parser.find_overlapping_iter(line);
if let Some(first) = it.next() {
let first = convert_id(first.pattern().as_u32())?;
let last = if let Some(last) = it.last() {
convert_id(last.pattern().as_u32())?
} else {
first
};
sum += 10 * first + last;
}
}
Ok(sum.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/01.1.txt");
const SAMPLE2: &[u8] = include_bytes!("samples/01.2.txt");
#[test]
fn sample_part1() {
assert_eq!("142", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("281", part2(SAMPLE2).unwrap());
}
}

98
2023/src/day02.rs Normal file
View File

@@ -0,0 +1,98 @@
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::iterator;
use nom::combinator::opt;
use nom::combinator::value;
use nom::multi::fold_many1;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::convert_nom_error;
#[derive(Clone, Copy)]
#[repr(usize)]
enum Color {
Red,
Green,
Blue,
}
fn parse_game(i: &[u8]) -> IResult<&[u8], (u8, [u8; 3])> {
let parse_color = terminated(
separated_pair(
nom::character::complete::u8,
tag(" "),
alt((
value(Color::Red, tag("red")),
value(Color::Green, tag("green")),
value(Color::Blue, tag("blue")),
)),
),
opt(alt((tag(", "), tag("; ")))),
);
separated_pair(
preceded(tag("Game "), nom::character::complete::u8),
tag(": "),
terminated(
fold_many1(
parse_color,
|| [0u8; 3],
|mut cur, (value, color)| {
cur[color as usize] = Ord::max(cur[color as usize], value);
cur
},
),
newline,
),
)(i)
}
fn parts_common(input: &[u8], map: impl Fn((u8, [u8; 3])) -> u32) -> anyhow::Result<String> {
let mut game_it = iterator(input, parse_game);
let total: u32 = game_it.into_iter().map(map).sum();
game_it.finish().map_err(|e| match e {
nom::Err::Incomplete(_) => anyhow::anyhow!("unreachable"),
nom::Err::Failure(e) | nom::Err::Error(e) => convert_nom_error(e),
})?;
Ok(total.to_string())
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, |(id, colors)| {
if colors[0] <= 12 && colors[1] <= 13 && colors[2] <= 14 {
u32::from(id)
} else {
0
}
})
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, |(_, colors)| {
u32::from(colors[0]) * u32::from(colors[1]) * u32::from(colors[2])
})
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/02.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "8");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "2286");
}
}

133
2023/src/day03.rs Normal file
View File

@@ -0,0 +1,133 @@
use std::collections::HashMap;
use crate::common::Grid;
fn is_surrounded(grid: &Grid<&[u8]>, y: usize, start: usize, last: usize) -> bool {
fn is_symbol(c: u8) -> bool {
!matches!(c, b'0'..=b'9' | b'.' | b'\n')
}
let x_min = start.saturating_sub(1);
let x_max = Ord::min(grid.width(), last + 2);
if y > 0 {
for nx in x_min..x_max {
if is_symbol(grid[y - 1][nx]) {
return true;
}
}
}
if y + 1 < grid.height() {
for nx in x_min..x_max {
if is_symbol(grid[y + 1][nx]) {
return true;
}
}
}
is_symbol(grid[y][x_min]) || is_symbol(grid[y][x_max - 1])
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let grid = Grid::new(input)?;
let mut sum = 0;
for (y, row) in grid.rows().enumerate() {
let mut it = row.iter().enumerate();
while let Some((start, &c)) = it.find(|&(_, c)| c.is_ascii_digit()) {
let mut end = start;
let mut num = u32::from(c - b'0');
for (x, &c) in it.by_ref().take_while(|&(_, c)| c.is_ascii_digit()) {
end = x;
num *= 10;
num += u32::from(c - b'0');
}
if is_surrounded(&grid, y, start, end) {
sum += num;
}
}
}
Ok(sum.to_string())
}
fn find_gear(grid: &Grid<&[u8]>, y: usize, start: usize, end: usize) -> Option<(usize, usize)> {
let x_min = start.saturating_sub(1);
let x_max = Ord::min(grid.width(), end + 2);
if y > 0 {
for nx in x_min..x_max {
if grid[y - 1][nx] == b'*' {
return Some((nx, y - 1));
}
}
}
if y + 1 < grid.height() {
for nx in x_min..x_max {
if grid[y + 1][nx] == b'*' {
return Some((nx, y + 1));
}
}
}
for nx in [x_min, x_max - 1] {
if grid[y][nx] == b'*' {
return Some((nx, y));
}
}
None
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let grid = Grid::new(input)?;
let mut gears: HashMap<(usize, usize), (u32, u32)> = HashMap::new();
for (y, row) in grid.rows().enumerate() {
let mut it = row.iter().enumerate();
while let Some((start, &c)) = it.find(|&(_, c)| c.is_ascii_digit()) {
let mut end = start;
let mut num = u32::from(c - b'0');
for (x, &c) in it.by_ref().take_while(|&(_, c)| c.is_ascii_digit()) {
end = x;
num *= 10;
num += u32::from(c - b'0');
}
// Assumption: there is only one gear per number. This turns out to be true.
if let Some((gear_x, gear_y)) = find_gear(&grid, y, start, end) {
let entry = gears.entry((gear_x, gear_y)).or_insert((0, 1));
entry.0 += 1;
entry.1 *= num;
}
}
}
let sum: u32 = gears
.into_values()
.filter_map(|(count, ratio)| if count == 2 { Some(ratio) } else { None })
.sum();
Ok(sum.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/03.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "4361");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "467835");
}
}

103
2023/src/day04.rs Normal file
View File

@@ -0,0 +1,103 @@
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::character::complete::space1;
use nom::combinator::iterator;
use nom::combinator::map;
use nom::multi::fold_many1;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::pair;
use nom::sequence::preceded;
use nom::IResult;
use crate::common::convert_nom_error;
use crate::common::parse_input;
struct Card {
have: u128,
winning: u128,
}
fn parse_card(i: &[u8]) -> IResult<&[u8], Card> {
fn parse_set(i: &[u8]) -> IResult<&[u8], u128> {
fold_many1(
preceded(space1, nom::character::complete::u8),
|| 0u128,
|cur, bit| cur | (1 << bit),
)(i)
}
map(
pair(
preceded(
delimited(
pair(tag("Card"), space1),
nom::character::complete::u32,
tag(":"),
),
parse_set,
),
delimited(tag(" |"), parse_set, newline),
),
|(have, winning)| Card { have, winning },
)(i)
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let mut card_it = iterator(input, parse_card);
let total: u32 = card_it
.into_iter()
.map(|card| {
let winners = (card.have & card.winning).count_ones();
if winners > 0 {
1 << (winners - 1)
} else {
0
}
})
.sum();
card_it.finish().map_err(|e| match e {
nom::Err::Incomplete(_) => anyhow::anyhow!("unreachable"),
nom::Err::Failure(e) | nom::Err::Error(e) => convert_nom_error(e),
})?;
Ok(total.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let cards = parse_input(input, many1(parse_card))?;
let mut counts = vec![1; cards.len()];
for (id, card) in cards.iter().enumerate() {
let winners = (card.have & card.winning).count_ones() as usize;
let count = counts[id];
for offset in 1..=winners {
counts[id + offset] += count;
}
}
let total: u32 = counts.iter().sum();
Ok(total.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/04.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "13");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "30");
}
}

208
2023/src/day05.rs Normal file
View File

@@ -0,0 +1,208 @@
use std::mem;
use anyhow::Context;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
use crate::common::parse_input;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Mapping {
source_start: u64,
dest_start: u64,
len: u64,
}
fn parse_mapping(i: &[u8]) -> IResult<&[u8], Vec<Mapping>> {
use nom::character::complete::u64;
let mut mapping = many1(map(
tuple((
terminated(u64, tag(" ")),
terminated(u64, tag(" ")),
terminated(u64, newline),
)),
|(dest_start, source_start, len)| Mapping {
source_start,
dest_start,
len,
},
))(i)?;
// Sort mappings for O(log n) lookup of appropriate mapping later
mapping.1.sort_unstable();
Ok(mapping)
}
struct Almanac {
seeds: Vec<u64>,
// There's a lot of mappings but their names don't matter, they all work the same.
mappings: [Vec<Mapping>; 7],
}
fn parse_almanac(i: &[u8]) -> IResult<&[u8], Almanac> {
let parse_seeds = delimited(
tag("seeds:"),
many1(preceded(tag(" "), nom::character::complete::u64)),
newline,
);
let mapping_parser = |header| preceded(tag(header), parse_mapping);
map(
tuple((
parse_seeds,
mapping_parser("\nseed-to-soil map:\n"),
mapping_parser("\nsoil-to-fertilizer map:\n"),
mapping_parser("\nfertilizer-to-water map:\n"),
mapping_parser("\nwater-to-light map:\n"),
mapping_parser("\nlight-to-temperature map:\n"),
mapping_parser("\ntemperature-to-humidity map:\n"),
mapping_parser("\nhumidity-to-location map:\n"),
)),
|(seeds, soil, fertilizer, water, light, temperature, humidity, location)| Almanac {
seeds,
mappings: [
soil,
fertilizer,
water,
light,
temperature,
humidity,
location,
],
},
)(i)
}
fn follow_mapping(node: u64, mappings: &[Mapping]) -> u64 {
let point = mappings.partition_point(|mapping| mapping.source_start <= node);
if point == 0 {
// There are no mappings that are smaller than the node, so it maps to itself
node
} else {
// `mapping`` is the last mapping that starts smaller or equal to our node, so it is the one
// that might contain it.
let mapping = &mappings[point - 1];
// Check if the node is in range of this mapping
if node - mapping.source_start < mapping.len {
// It is, note the order of operations to avoid underflow
node + mapping.dest_start - mapping.source_start
} else {
// It's not, return itself
node
}
}
}
fn follow_all_mappings(mut node: u64, mappings: &[Vec<Mapping>]) -> u64 {
for mappings in mappings {
node = follow_mapping(node, mappings)
}
node
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let almanac = parse_input(input, parse_almanac)?;
let min = almanac
.seeds
.iter()
.map(|node| follow_all_mappings(*node, &almanac.mappings))
.min()
.context("Unreachable, no seeds but parser ensures seeds")?;
Ok(min.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let almanac = parse_input(input, parse_almanac)?;
let mut ranges: Vec<(u64, u64)> = almanac
.seeds
.chunks_exact(2)
.map(|c| (c[0], c[1]))
.collect();
let mut target = Vec::new();
for mappings in &almanac.mappings {
for (mut start, mut len) in ranges.drain(..) {
debug_assert_ne!(len, 0);
let mut point = mappings.partition_point(|mapping| mapping.source_start <= start);
if point > 0 && start < mappings[point - 1].source_start + mappings[point - 1].len {
let mapping = &mappings[point - 1];
let overlapping_len = mapping.len - (start - mapping.source_start);
let use_len = Ord::min(len, overlapping_len);
debug_assert!(use_len > 0);
target.push((start - mapping.source_start + mapping.dest_start, use_len));
start += use_len;
len -= use_len;
}
// Loop invariant: start is not in a range and the next range is mappings[point]
while len > 0 && point < mappings.len() {
let mapping = &mappings[point];
let before_len = Ord::min(len, mapping.source_start - start);
if before_len > 0 {
len -= before_len;
target.push((start, before_len));
start += before_len;
}
if len > 0 {
let inside_len = Ord::min(len, mapping.len);
debug_assert!(inside_len > 0);
target.push((mapping.dest_start, inside_len));
start += inside_len;
len -= inside_len;
point += 1;
}
}
if len > 0 {
target.push((start, len));
}
}
mem::swap(&mut ranges, &mut target);
}
let min = ranges
.iter()
.map(|&(start, _)| start)
.min()
.context("Somehow lost all ranges")?;
Ok(min.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/05.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "35");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "46");
}
}

110
2023/src/day06.rs Normal file
View File

@@ -0,0 +1,110 @@
use nom::bytes::complete::tag;
use nom::character::complete::digit1;
use nom::character::complete::newline;
use nom::character::complete::space1;
use nom::multi::fold_many1;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::pair;
use nom::sequence::preceded;
use nom::IResult;
use crate::common::parse_input;
fn parse_race(i: &[u8]) -> IResult<&[u8], (Vec<u64>, Vec<u64>)> {
let line = |header| {
delimited(
tag(header),
many1(preceded(space1, nom::character::complete::u64)),
newline,
)
};
pair(line("Time:"), line("Distance:"))(i)
}
fn parse_long_race(i: &[u8]) -> IResult<&[u8], (u64, u64)> {
let line = |header| {
delimited(
tag(header),
fold_many1(
preceded(space1, digit1),
|| 0,
|mut cur, sequence| {
for &c in sequence {
cur *= 10;
cur += u64::from(c - b'0');
}
cur
},
),
newline,
)
};
pair(line("Time:"), line("Distance:"))(i)
}
fn ways(time: u64, distance: u64) -> u64 {
let a = -1.0;
let b = time as f64;
let c = -(distance as f64);
let d = b * b - 4.0 * a * c;
if d < 0.0 {
0
} else {
// Note: can leave out quite a bit of the quadratic formula because things cancel out nicely
let solution = ((b - d.sqrt()) / 2.0 + 1.0) as u64;
let half = time / 2;
let make_it = half - solution + 1;
if time % 2 == 0 {
2 * make_it - 1
} else {
2 * make_it
}
}
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let (time, distance) = parse_input(input, parse_race)?;
let total: u64 = time
.iter()
.zip(&distance)
.map(|(&time, &distance)| ways(time, distance))
.product();
Ok(total.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let (time, distance) = parse_input(input, parse_long_race)?;
Ok(ways(time, distance).to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/06.txt");
#[test]
fn individual_samples() {
assert_eq!(ways(7, 9), 4);
assert_eq!(ways(15, 40), 8);
assert_eq!(ways(30, 200), 9);
}
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "288");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "71503");
}
}

160
2023/src/day07.rs Normal file
View File

@@ -0,0 +1,160 @@
use std::mem;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::character::complete::newline;
use nom::combinator::map_res;
use nom::multi::many1;
use nom::sequence::pair;
use nom::sequence::terminated;
use nom::Parser;
use crate::common::parse_input;
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
enum Kind {
HighCard,
Pair,
TwoPair,
ThreeOfAKind,
FullHouse,
FourOfAKind,
FiveOfAKind,
}
#[inline]
fn kind_parser(cards: &[u8; 5], part2: bool) -> Kind {
let mut counts = [0u8; 15];
for &card in cards {
counts[card as usize] += 1;
}
let jokers = if part2 {
mem::take(&mut counts[1]) as usize
} else {
0
};
let mut counts_counts = [0u8; 6];
for count in counts {
counts_counts[count as usize] += 1;
}
let mut first = 0;
let mut second = 0;
for (count, &occurrences) in counts_counts.iter().enumerate() {
match occurrences {
0 => continue,
1 => {
second = first;
first = count;
}
_ => {
first = count;
second = count;
}
}
}
match (first + jokers, second) {
(5, _) => Kind::FiveOfAKind,
(4, _) => Kind::FourOfAKind,
(3, 2) => Kind::FullHouse,
(3, _) => Kind::ThreeOfAKind,
(2, 2) => Kind::TwoPair,
(2, _) => Kind::Pair,
_ => Kind::HighCard,
}
}
struct Hand {
cards: [u8; 5],
bid: u32,
kind: Kind,
}
#[inline]
fn map_card(c: u8, part2: bool) -> anyhow::Result<u8> {
Ok(match c {
d @ b'2'..=b'9' => d - b'0',
b'T' => 10,
b'J' => {
if part2 {
1
} else {
11
}
}
b'Q' => 12,
b'K' => 13,
b'A' => 14,
other => anyhow::bail!("Invalid card {other}"),
})
}
#[inline]
fn hands_parser<'a>(part2: bool) -> impl Parser<&'a [u8], Vec<Hand>, nom::error::Error<&'a [u8]>> {
many1(map_res(
pair(
terminated(take(5usize), tag(" ")),
terminated(nom::character::complete::u32, newline),
),
move |(hand, bid)| -> anyhow::Result<Hand> {
let mut cards = [0; 5];
for (t, &s) in cards.iter_mut().zip(hand) {
*t = map_card(s, part2)?
}
let kind = kind_parser(&cards, part2);
Ok(Hand { cards, bid, kind })
},
))
}
fn parts_common(hands: &mut [Hand]) -> anyhow::Result<String> {
hands.sort_unstable_by(|first, second| {
first
.kind
.cmp(&second.kind)
.then_with(|| first.cards.cmp(&second.cards))
});
let sum: u64 = hands
.iter()
.enumerate()
.map(|(i, hand)| (i + 1) as u64 * u64::from(hand.bid))
.sum();
Ok(sum.to_string())
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let mut hands = parse_input(input, hands_parser(false))?;
parts_common(&mut hands)
}
// Too high: 248859461
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let mut hands = parse_input(input, hands_parser(true))?;
parts_common(&mut hands)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/07.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "6440");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "5905");
}
}

151
2023/src/day08.rs Normal file
View File

@@ -0,0 +1,151 @@
use anyhow::Context;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::bytes::complete::take_until;
use nom::combinator::map;
use nom::multi::fold_many1;
use nom::sequence::preceded;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::sequence::tuple;
use nom::IResult;
use num_integer::Integer;
use crate::common::parse_input;
const NUM_PLACES: usize = 26 * 26 * 26;
struct Map<'a> {
instructions: &'a [u8],
transitions: Box<[(u16, u16); NUM_PLACES]>,
}
impl<'a> Map<'a> {
#[inline]
fn transition(&self, pos: u16, step: u8) -> u16 {
if step == b'L' {
self.transitions[pos as usize].0
} else {
self.transitions[pos as usize].1
}
}
}
fn place_to_index(place: &[u8]) -> u16 {
place
.iter()
.fold(0u16, |index, &c| index * 26 + u16::from(c - b'A'))
}
fn parse_map(i: &[u8]) -> IResult<&[u8], Map<'_>> {
map(
separated_pair(
take_until("\n"),
tag("\n\n"),
fold_many1(
tuple((
terminated(take(3usize), tag(" = (")),
terminated(take(3usize), tag(", ")),
terminated(take(3usize), tag(")\n")),
)),
|| Box::new([(0, 0); NUM_PLACES]),
|mut transitions, (pos, left, right)| {
let pos = place_to_index(pos);
let left = place_to_index(left);
let right = place_to_index(right);
transitions[pos as usize] = (left, right);
transitions
},
),
),
|(instructions, transitions)| Map {
instructions,
transitions,
},
)(i)
}
fn parse_starts(i: &[u8]) -> IResult<&[u8], Vec<u16>> {
preceded(
tuple((take_until("\n"), tag("\n\n"))),
fold_many1(
terminated(
map(take(3usize), place_to_index),
tuple((take_until("\n"), tag("\n"))),
),
Vec::new,
|mut starts, place| {
if place % 26 == 0 {
starts.push(place)
}
starts
},
),
)(i)
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let map = parse_input(input, parse_map)?;
let end = place_to_index(b"ZZZ");
let mut pos = 0;
for (count, &step) in map.instructions.iter().cycle().enumerate() {
if pos == end {
return Ok(count.to_string());
}
pos = map.transition(pos, step);
}
anyhow::bail!("Unreachable, loop is infinite");
}
// This code is wrong. There is no reason that the start of the cycle is indeed the equal to the
// length of the cycle. But it happens to be the case, so we roll with it. Otherwise you could go
// with the full Chinese remainder theorem and knock yourself out that way.
//
// I didn't wanna.
fn find_cycle(map: &Map<'_>, start: u16) -> usize {
let mut pos = start;
for (count, &step) in map.instructions.iter().cycle().enumerate() {
if pos % 26 == 25 {
return count;
}
pos = map.transition(pos, step);
}
unreachable!("Loop is actually infinite")
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let map = parse_input(input, parse_map)?;
let pos = parse_input(input, parse_starts)?;
pos.iter()
.map(|&p| find_cycle(&map, p))
.reduce(|a, b| a.lcm(&b))
.map(|s| s.to_string())
.context("No starting points somehow")
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/08.1.txt");
const SAMPLE2: &[u8] = include_bytes!("samples/08.2.txt");
// N.B. sample modified because I don't want to change my parser logic to deal with ascii digits
// in addition to capitals. 1 has been replaced with D, 2 has been replaced with E.
const SAMPLE3: &[u8] = include_bytes!("samples/08.3.txt");
#[test]
fn sample_part1() {
assert_eq!("2", part1(SAMPLE).unwrap());
assert_eq!("6", part1(SAMPLE2).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("6", part2(SAMPLE3).unwrap());
}
}

88
2023/src/day09.rs Normal file
View File

@@ -0,0 +1,88 @@
use std::mem;
use std::ops::Range;
use nom::IResult;
use crate::common::parse_input;
fn parse_reports(mut i: &[u8]) -> IResult<&[u8], (Vec<Range<usize>>, Vec<i32>)> {
let mut begin = 0;
let mut numbers = Vec::new();
let mut ranges = Vec::new();
while !i.is_empty() {
let (rem, num) = nom::character::complete::i32(i)?;
numbers.push(num);
if rem[0] == b'\n' {
let end = numbers.len();
ranges.push(begin..end);
begin = end;
}
i = &rem[1..];
}
Ok((i, (ranges, numbers)))
}
fn compute_next<'a>(report: impl IntoIterator<Item = &'a i32>, deltas: &mut Vec<i32>) -> i32 {
deltas.clear();
for &entry in report {
let mut delta = entry;
for prev_delta in &mut *deltas {
let prev = mem::replace(prev_delta, delta);
delta -= prev;
}
if delta != 0 {
deltas.push(delta);
}
}
deltas.iter().rev().sum::<i32>()
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let mut deltas = Vec::new();
let (ranges, numbers) = parse_input(input, parse_reports)?;
let result: i32 = ranges
.into_iter()
.map(|range| compute_next(&numbers[range], &mut deltas))
.sum();
Ok(result.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let mut deltas = Vec::new();
let (ranges, numbers) = parse_input(input, parse_reports)?;
let result: i32 = ranges
.into_iter()
.map(|range| compute_next(numbers[range].iter().rev(), &mut deltas))
.sum();
Ok(result.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/09.txt");
#[test]
fn samples_separate() {
assert_eq!(18, compute_next(&[0, 3, 6, 9, 12, 15], &mut Vec::new()));
assert_eq!(28, compute_next(&[1, 3, 6, 10, 15, 21], &mut Vec::new()));
assert_eq!(68, compute_next(&[10, 13, 16, 21, 30, 45], &mut Vec::new()));
}
#[test]
fn sample_part1() {
assert_eq!("114", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("2", part2(SAMPLE).unwrap());
}
}

144
2023/src/day10.rs Normal file
View File

@@ -0,0 +1,144 @@
use std::collections::VecDeque;
use anyhow::Context;
use crate::common::Grid;
use crate::common::IndexSet;
const LEFT: u8 = 1;
const RIGHT: u8 = 2;
const UP: u8 = 4;
const DOWN: u8 = 8;
fn get_connections(c: u8) -> u8 {
match c {
b'|' => UP | DOWN,
b'-' => LEFT | RIGHT,
b'F' => DOWN | RIGHT,
b'J' => LEFT | UP,
b'L' => RIGHT | UP,
b'7' => LEFT | DOWN,
_ => 0,
}
}
fn find_cycle(map: &Grid<&[u8]>) -> anyhow::Result<(usize, bool, IndexSet)> {
let (start_x, start_y) = map.find(b'S').context("Couldn't find starting point")?;
let mut visited = IndexSet::with_capacity(map.width() * map.height());
let mut todo = VecDeque::new();
visited.insert(start_y * map.width() + start_x);
let mut start_up = false;
if start_x > 0 && (get_connections(map[start_y][start_x - 1]) & RIGHT) != 0 {
todo.push_back((1, (start_x - 1, start_y)));
visited.insert(start_y * map.width() + start_x - 1);
}
if start_x + 1 < map.width() && (get_connections(map[start_y][start_x + 1]) & LEFT) != 0 {
todo.push_back((1, (start_x + 1, start_y)));
visited.insert(start_y * map.width() + start_x + 1);
}
if start_y > 0 && (get_connections(map[start_y - 1][start_x]) & DOWN) != 0 {
todo.push_back((1, (start_x, start_y - 1)));
visited.insert((start_y - 1) * map.width() + start_x);
start_up = true;
}
if start_y + 1 < map.height() && (get_connections(map[start_y + 1][start_x]) & DOWN) != 0 {
todo.push_back((1, (start_x, start_y + 1)));
visited.insert((start_y + 1) * map.width() + start_x);
}
let mut max_dist = 1;
while let Some((dist, (x, y))) = todo.pop_front() {
let mut enqueue = |x, y| {
if visited.insert(y * map.width() + x) {
todo.push_back((dist + 1, (x, y)));
// Can elide comparison because we do a BFS and length is strictly increasing
max_dist = dist + 1;
}
};
let connections = get_connections(map[y][x]);
if (connections & LEFT) != 0 {
enqueue(x - 1, y);
}
if (connections & RIGHT) != 0 {
enqueue(x + 1, y);
}
if (connections & UP) != 0 {
enqueue(x, y - 1);
}
if (connections & DOWN) != 0 {
enqueue(x, y + 1);
}
}
Ok((max_dist, start_up, visited))
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let map = Grid::new(input)?;
find_cycle(&map).map(|(max_dist, _, _)| max_dist.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let map = Grid::new(input)?;
let (_, s_up, visited) = find_cycle(&map)?;
let mut inside = 0;
for (y, row) in map.rows().enumerate() {
let y_offset = y * map.width();
let mut pipes = 0;
for (x, &c) in row.iter().enumerate() {
if visited.contains(y_offset + x) {
let is_up = match c {
b'|' | b'J' | b'L' => true,
b'S' => s_up,
_ => false,
};
if is_up {
pipes += 1;
}
} else {
inside += pipes % 2;
}
}
}
Ok(inside.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/10.1.txt");
const SAMPLE2: &[u8] = include_bytes!("samples/10.2.txt");
const SAMPLE3: &[u8] = include_bytes!("samples/10.3.txt");
const SAMPLE4: &[u8] = include_bytes!("samples/10.4.txt");
#[test]
fn sample_part1() {
assert_eq!("8", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("4", part2(SAMPLE2).unwrap());
assert_eq!("8", part2(SAMPLE3).unwrap());
assert_eq!("10", part2(SAMPLE4).unwrap());
}
}

74
2023/src/day11.rs Normal file
View File

@@ -0,0 +1,74 @@
use crate::common::Grid;
use crate::common::IndexSet;
fn find_doubles(occupied: IndexSet, len: usize) -> Vec<usize> {
// TODO: this should iterate over IndexSet but that doesn't work yet and I can't be bothered.
(0..len).filter(|&v| !occupied.contains(v)).collect()
}
fn transform<const S: usize>(pos: usize, doubles: &[usize]) -> usize {
let before = doubles.partition_point(|&v| v < pos);
pos + before * (S - 1)
}
fn part_common<const S: usize>(input: &[u8]) -> anyhow::Result<String> {
let map = Grid::new(input)?;
let mut stars = Vec::new();
let mut cols_occupied = IndexSet::with_capacity(map.width());
let mut rows_occupied = IndexSet::with_capacity(map.height());
for (y, row) in map.rows().enumerate() {
for (x, &pixel) in row.iter().enumerate() {
if pixel == b'#' {
cols_occupied.insert(x);
rows_occupied.insert(y);
stars.push((x, y));
}
}
}
let cols_doubled = find_doubles(cols_occupied, map.width());
let rows_doubled = find_doubles(rows_occupied, map.height());
for star in &mut stars {
star.0 = transform::<S>(star.0, &cols_doubled);
star.1 = transform::<S>(star.1, &rows_doubled);
}
let total: usize = stars
.iter()
.enumerate()
.flat_map(|(i, star)| {
stars[i + 1..]
.iter()
.map(|other| star.0.abs_diff(other.0) + star.1.abs_diff(other.1))
})
.sum();
Ok(total.to_string())
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
part_common::<2>(input)
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
part_common::<1_000_000>(input)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/11.txt");
#[test]
fn sample_part1() {
assert_eq!("374", part1(SAMPLE).unwrap());
}
#[test]
fn sample_scaled() {
assert_eq!("1030", part_common::<10>(SAMPLE).unwrap());
assert_eq!("8410", part_common::<100>(SAMPLE).unwrap());
}
}

118
2023/src/day12.rs Normal file
View File

@@ -0,0 +1,118 @@
use std::mem;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::multi::many1;
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::parse_input;
fn number_ways(line: &[u8], groups: &[u8]) -> u64 {
let Some(&max_group) = groups.iter().max() else {
return 0;
};
let group_stride = max_group as usize + 1;
let mut next = vec![0; (groups.len() + 1) * group_stride];
let mut cur = next.clone();
cur[0] = 1;
for &c in line {
next.fill(0);
for (group_pos, positions) in cur.chunks_exact(group_stride).enumerate() {
let group = *groups.get(group_pos).unwrap_or(&0);
for (cur_group, &ways) in positions.iter().enumerate() {
if ways == 0 {
continue;
}
// Either defective or maybe defective
if c != b'.' && cur_group < usize::from(group) {
next[group_pos * group_stride + cur_group + 1] += ways;
}
if c != b'#' {
if cur_group == 0 {
next[group_pos * group_stride] += ways;
} else if usize::from(group) == cur_group {
next[(group_pos + 1) * group_stride] += ways;
}
}
}
}
mem::swap(&mut cur, &mut next);
}
cur[groups.len() * group_stride]
+ cur[(groups.len() - 1) * group_stride + groups[groups.len() - 1] as usize]
}
fn parse_lines(i: &[u8]) -> IResult<&[u8], Vec<(&[u8], Vec<u8>)>> {
many1(terminated(
separated_pair(
take_until(" "),
tag(" "),
separated_list1(tag(","), nom::character::complete::u8),
),
tag("\n"),
))(i)
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let lines = parse_input(input, parse_lines)?;
let total: u64 = lines
.iter()
.map(|(line, groups)| number_ways(line, groups))
.sum();
Ok(total.to_string())
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let lines = parse_input(input, parse_lines)?;
let total: u64 = lines
.iter()
.map(|(line, groups)| {
let line: Vec<_> = [*line; 5].join(&b"?"[..]);
let groups = groups.repeat(5);
number_ways(&line, &groups)
})
.sum();
Ok(total.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/12.txt");
#[test]
fn test_number_ways() {
assert_eq!(1, number_ways(b"???.###", &[1, 1, 3]));
assert_eq!(4, number_ways(b".??..??...?##.", &[1, 1, 3]));
assert_eq!(1, number_ways(b"?#?#?#?#?#?#?#?", &[1, 3, 1, 6]));
assert_eq!(1, number_ways(b"????.#...#...", &[4, 1, 1]));
assert_eq!(4, number_ways(b"????.######..#####.", &[1, 6, 5]));
assert_eq!(10, number_ways(b"?###????????", &[3, 2, 1]));
}
#[test]
fn sample_part1() {
assert_eq!("21", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("525152", part2(SAMPLE).unwrap());
}
}

107
2023/src/day13.rs Normal file
View File

@@ -0,0 +1,107 @@
use crate::common::Grid;
#[derive(Debug)]
enum Symmetry {
Horizontal(u32),
Vertical(u32),
}
impl Symmetry {
fn value(self) -> u32 {
match self {
Symmetry::Horizontal(value) => 100 * value,
Symmetry::Vertical(value) => value,
}
}
}
fn find_symmetry(grid: Grid<&[u8]>, differences: usize) -> Option<Symmetry> {
// Attempt to find a vertical line of reflection first
for c in 1..grid.width() {
if grid
.rows()
.flat_map(|row| row[..c].iter().rev().zip(&row[c..]))
.filter(|(a, b)| a != b)
.take(differences + 1)
.count()
== differences
{
return Some(Symmetry::Vertical(c as u32));
}
}
for r in 1..grid.height() {
if (0..r)
.rev()
.zip(r..grid.height())
.flat_map(|(a, b)| grid[a].iter().zip(&grid[b]))
.filter(|(a, b)| a != b)
.take(differences + 1)
.count()
== differences
{
return Some(Symmetry::Horizontal(r as u32));
}
}
println!("Suspiciously did not find an axis of symmetry:\n\n{grid}\n");
None
}
fn parse_grids(input: &[u8]) -> anyhow::Result<Vec<Grid<&[u8]>>> {
let mut result = Vec::new();
let mut start = 0;
let mut last_newline = 0;
for i in input
.iter()
.enumerate()
.filter_map(|(i, c)| (*c == b'\n').then_some(i))
{
if last_newline == i - 1 {
result.push(Grid::new(&input[start..i])?);
start = i + 1;
}
last_newline = i;
}
result.push(Grid::new(&input[start..])?);
Ok(result)
}
fn parts_common(input: &[u8], differences: usize) -> anyhow::Result<String> {
let grids = parse_grids(input)?;
let sum: u32 = grids
.into_iter()
.filter_map(|grid| find_symmetry(grid, differences))
.map(Symmetry::value)
.sum();
Ok(sum.to_string())
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, 0)
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, 1)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/13.txt");
#[test]
fn sample_part1() {
assert_eq!("405", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("400", part2(SAMPLE).unwrap());
}
}

167
2023/src/day14.rs Normal file
View File

@@ -0,0 +1,167 @@
use crate::common::Grid;
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let grid = Grid::new(input)?;
let mut stack_heights = vec![0; grid.width()];
let mut load = 0;
let height = grid.height();
for (y, row) in grid.rows().enumerate() {
for (&c, stack_height) in row.iter().zip(&mut stack_heights) {
match c {
b'#' => *stack_height = y + 1,
b'O' => {
load += height - *stack_height;
*stack_height += 1;
}
_ => continue,
}
}
}
Ok(load.to_string())
}
fn advance(grid: &mut Grid<Vec<u8>>, stack_heights: &mut [usize]) {
// Tilt north
stack_heights.fill(0);
for y in 0..grid.height() {
for (x, stack_height) in stack_heights.iter_mut().enumerate() {
let c = grid[y][x];
match c {
b'#' => *stack_height = y + 1,
b'O' => {
grid[y][x] = b'.';
grid[*stack_height][x] = b'O';
*stack_height += 1;
}
_ => continue,
}
}
}
// Tilt west
for row in grid.rows_mut() {
let mut stack_height = 0;
for x in 0..row.len() {
let c = row[x];
match c {
b'#' => stack_height = x + 1,
b'O' => {
row[x] = b'.';
row[stack_height] = b'O';
stack_height += 1;
}
_ => continue,
}
}
}
// Tilt south
stack_heights.fill(grid.height() - 1);
for y in (0..grid.height()).rev() {
for (x, stack_height) in stack_heights.iter_mut().enumerate() {
let c = grid[y][x];
match c {
b'#' => *stack_height = y.saturating_sub(1),
b'O' => {
grid[y][x] = b'.';
grid[*stack_height][x] = b'O';
// Saturating because possible underflow
*stack_height = stack_height.saturating_sub(1);
}
_ => continue,
}
}
}
// Tilt east
for row in grid.rows_mut() {
let mut stack_height = row.len() - 1;
for x in (0..row.len()).rev() {
let c = row[x];
match c {
b'#' => stack_height = x.saturating_sub(1),
b'O' => {
row[x] = b'.';
row[stack_height] = b'O';
stack_height = stack_height.saturating_sub(1);
}
_ => continue,
}
}
}
}
fn find_cycle(
it: impl Iterator<Item = usize>,
hare: &mut Grid<Vec<u8>>,
stack_heights: &mut [usize],
) -> Option<usize> {
let mut tortoise = hare.clone();
let mut last_sync = 0;
for cycle in it {
advance(hare, stack_heights);
if tortoise == *hare {
return Some(cycle - last_sync);
} else if cycle.count_ones() == 1 {
// New power of two, sync up the tortoise and the hare
tortoise.clone_from(hare);
last_sync = cycle;
}
}
None
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
const GOAL: usize = 1000000000;
let mut hare = Grid::new(input.to_owned())?;
let mut stack_heights = vec![0; hare.width()];
let mut it = 1..=GOAL;
// If there is a cycle found, skip ahead
if let Some(len) = find_cycle(&mut it, &mut hare, &mut stack_heights) {
let remaining = it.size_hint().0;
let steps = remaining % len;
for _ in 0..steps {
advance(&mut hare, &mut stack_heights);
}
}
let height = hare.height();
let load = hare
.rows()
.enumerate()
.flat_map(|(y, row)| {
row.iter()
.filter_map(move |&c| (c == b'O').then_some(height - y))
})
.sum::<usize>();
Ok(load.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/14.txt");
#[test]
fn sample_part1() {
assert_eq!("136", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("64", part2(SAMPLE).unwrap());
}
}

110
2023/src/day15.rs Normal file
View File

@@ -0,0 +1,110 @@
use linked_hash_map::LinkedHashMap;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_till;
use nom::combinator::map;
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::parse_input;
fn trim(input: &[u8]) -> &[u8] {
let whitespace = input
.iter()
.rev()
.take_while(|c| c.is_ascii_whitespace())
.count();
&input[..(input.len() - whitespace)]
}
fn hash(input: &[u8]) -> u8 {
input
.iter()
.fold(0, |cur, &c| cur.wrapping_add(c).wrapping_mul(17))
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let input = trim(input);
Ok(input
.split(|&c| c == b',')
.map(|word| u32::from(hash(word)))
.sum::<u32>()
.to_string())
}
enum Command<'a> {
Add(&'a [u8], u32),
Remove(&'a [u8]),
}
fn parse_commands(i: &[u8]) -> IResult<&[u8], Vec<Command>> {
fn is_op(c: u8) -> bool {
c == b'=' || c == b'-'
}
separated_list1(
tag(","),
alt((
map(
separated_pair(take_till(is_op), tag("="), nom::character::complete::u32),
|(a, b)| Command::Add(a, b),
),
map(terminated(take_till(is_op), tag("-")), Command::Remove),
)),
)(i)
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let commands = parse_input(trim(input), parse_commands)?;
let mut state = LinkedHashMap::new();
for command in commands {
match command {
Command::Add(identifier, focal_len) => {
*state.entry(identifier).or_default() = focal_len;
}
Command::Remove(identifier) => {
state.remove(identifier);
}
}
}
let mut box_slot = [0; 256];
let mut total = 0;
for (&identifier, &focal_len) in &state {
let index = hash(identifier);
let box_no = u32::from(index) + 1;
let slot_no = &mut box_slot[index as usize];
*slot_no += 1;
total += box_no * *slot_no * focal_len;
}
Ok(total.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/15.txt");
#[test]
fn sample_hash() {
assert_eq!(hash(b"HASH"), 52);
}
#[test]
fn sample_part1() {
assert_eq!("1320", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("145", part2(SAMPLE).unwrap());
}
}

139
2023/src/day16.rs Normal file
View File

@@ -0,0 +1,139 @@
use crate::common::Direction;
use crate::common::Grid;
fn compute_energized(
map: &Grid<&[u8]>,
state: &mut Grid<Vec<u8>>,
todo: &mut Vec<(Direction, usize, usize)>,
) -> u32 {
let mut energized = todo.len() as u32;
while let Some((dir, x, y)) = todo.pop() {
let mut enqueue = |dir: Direction, x: usize, y: usize| {
let state = &mut state[y][x];
if state == &0 {
energized += 1;
}
if *state & dir.bit() == 0 {
*state |= dir.bit();
todo.push((dir, x, y));
}
};
let new_dir = match (map[y][x], dir) {
(b'/', Direction::Left) => Direction::Down,
(b'/', Direction::Up) => Direction::Right,
(b'/', Direction::Down) => Direction::Left,
(b'/', Direction::Right) => Direction::Up,
(b'\\', Direction::Left) => Direction::Up,
(b'\\', Direction::Up) => Direction::Left,
(b'\\', Direction::Down) => Direction::Right,
(b'\\', Direction::Right) => Direction::Down,
(b'|', Direction::Right) | (b'|', Direction::Left) => {
if y > 0 {
enqueue(Direction::Up, x, y - 1);
}
if y + 1 < map.height() {
enqueue(Direction::Down, x, y + 1);
}
continue;
}
(b'-', Direction::Up) | (b'-', Direction::Down) => {
if x > 0 {
enqueue(Direction::Left, x - 1, y);
}
if x + 1 < map.width() {
enqueue(Direction::Right, x + 1, y);
}
continue;
}
(_, dir) => dir,
};
match new_dir {
Direction::Up => {
if y > 0 {
enqueue(new_dir, x, y - 1);
}
}
Direction::Left => {
if x > 0 {
enqueue(new_dir, x - 1, y);
}
}
Direction::Down => {
if y + 1 < map.height() {
enqueue(new_dir, x, y + 1);
}
}
Direction::Right => {
if x + 1 < map.width() {
enqueue(new_dir, x + 1, y);
}
}
}
}
energized
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let map = Grid::new(input)?;
let mut state = Grid::zeroed(map.width(), map.height());
state[0][0] = Direction::Right.bit();
let mut todo = Vec::new();
todo.push((Direction::Right, 0, 0));
Ok(compute_energized(&map, &mut state, &mut todo).to_string())
}
fn reset_state(state: &mut Grid<Vec<u8>>) {
for row in state.rows_mut() {
row.fill(0);
}
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let map = Grid::new(input)?;
let mut state = Grid::zeroed(map.width(), map.height());
let mut todo = Vec::new();
let mut helper = |dir: Direction, x: usize, y: usize| {
todo.push((dir, x, y));
reset_state(&mut state);
state[y][x] = dir.bit();
compute_energized(&map, &mut state, &mut todo)
};
let mut best = 0;
for x in 0..map.width() {
best = Ord::max(best, helper(Direction::Down, x, 0));
best = Ord::max(best, helper(Direction::Up, x, map.height() - 1));
}
for y in 0..map.height() {
best = Ord::max(best, helper(Direction::Down, 0, y));
best = Ord::max(best, helper(Direction::Up, map.width() - 1, y));
}
Ok(best.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/16.txt");
#[test]
fn sample_part1() {
assert_eq!("46", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("51", part2(SAMPLE).unwrap());
}
}

205
2023/src/day17.rs Normal file
View File

@@ -0,0 +1,205 @@
use std::cmp;
use std::collections::hash_map::Entry;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use crate::common::Direction;
use crate::common::Grid;
#[derive(PartialEq, Eq)]
struct State {
x: usize,
y: usize,
dir: Direction,
heat_loss: u32,
estimate: u32,
}
impl Ord for State {
fn cmp(&self, other: &Self) -> cmp::Ordering {
// N.B. estimate and heat loss are compared in reverse for heap purposes, since BinaryHeap is a max heap.
other
.estimate
.cmp(&self.estimate)
.then_with(|| other.heat_loss.cmp(&self.heat_loss))
.then_with(|| self.x.cmp(&other.x))
.then_with(|| self.y.cmp(&other.y))
.then_with(|| self.dir.cmp(&other.dir))
}
}
impl PartialOrd for State {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
pub fn parts_common(input: &[u8], min: usize, max: usize) -> anyhow::Result<String> {
let to_skip = min - 1;
let to_take = max - min + 1;
let map = Grid::new(input)?;
let mut visited = HashMap::new();
let width = map.width();
let height = map.height();
let mut todo = BinaryHeap::new();
todo.push(State {
x: 0,
y: 0,
dir: Direction::Right,
heat_loss: 0,
estimate: (width + height - 2) as u32,
});
todo.push(State {
x: 0,
y: 0,
dir: Direction::Down,
heat_loss: 0,
estimate: (width + height - 2) as u32,
});
visited.insert((0usize, 0usize, true), 0u32);
visited.insert((0usize, 0usize, false), 0u32);
while let Some(State {
x,
y,
dir,
heat_loss,
..
}) = todo.pop()
{
if x == map.width() - 1 && y == map.height() - 1 {
return Ok(heat_loss.to_string());
} else if visited[&(x, y, dir.is_vertical())] < heat_loss {
continue;
}
let next_is_vertical = !dir.is_vertical();
let mut new_loss = heat_loss;
let mut enqueue = |x, y, heat_loss| {
match visited.entry((x, y, next_is_vertical)) {
Entry::Occupied(mut entry) => {
if entry.get() <= &heat_loss {
return;
} else {
entry.insert(heat_loss);
}
}
Entry::Vacant(entry) => {
entry.insert(heat_loss);
}
}
let estimate = (width + height - 2 - x - y) as u32 + heat_loss;
if next_is_vertical {
todo.push(State {
x,
y,
heat_loss,
dir: Direction::Up,
estimate,
});
todo.push(State {
x,
y,
heat_loss,
dir: Direction::Down,
estimate,
});
} else {
todo.push(State {
x,
y,
heat_loss,
dir: Direction::Left,
estimate,
});
todo.push(State {
x,
y,
heat_loss,
dir: Direction::Right,
estimate,
});
}
};
match dir {
Direction::Up => {
for (y, new_loss) in (0..y)
.rev()
.map(|y| {
new_loss += u32::from(map[(y, x)] - b'0');
(y, new_loss)
})
.skip(to_skip)
.take(to_take)
{
enqueue(x, y, new_loss);
}
}
Direction::Left => {
for (x, new_loss) in (0..x)
.rev()
.map(|x| {
new_loss += u32::from(map[(y, x)] - b'0');
(x, new_loss)
})
.skip(to_skip)
.take(to_take)
{
enqueue(x, y, new_loss);
}
}
Direction::Down => {
for (y, new_loss) in ((y + 1)..map.height())
.map(|y| {
new_loss += u32::from(map[(y, x)] - b'0');
(y, new_loss)
})
.skip(to_skip)
.take(to_take)
{
enqueue(x, y, new_loss);
}
}
Direction::Right => {
for (x, new_loss) in ((x + 1)..map.width())
.map(|x| {
new_loss += u32::from(map[(y, x)] - b'0');
(x, new_loss)
})
.skip(to_skip)
.take(to_take)
{
enqueue(x, y, new_loss);
}
}
}
}
anyhow::bail!("Did not find a solution")
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, 1, 3)
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
parts_common(input, 4, 10)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/17.txt");
#[test]
fn sample_part1() {
assert_eq!("102", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("94", part2(SAMPLE).unwrap());
}
}

147
2023/src/day18.rs Normal file
View File

@@ -0,0 +1,147 @@
use anyhow::Context;
use nom::bytes::complete::tag;
use nom::bytes::complete::take;
use nom::bytes::complete::take_until;
use nom::combinator::map;
use nom::combinator::map_res;
use nom::multi::many1;
use nom::sequence::delimited;
use nom::sequence::pair;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::parse_input;
use crate::common::Direction;
struct Dig {
dir: Direction,
amount: u64,
}
fn parse_instructions(i: &[u8]) -> IResult<&[u8], Vec<Dig>> {
many1(terminated(
map(
pair(
terminated(
map_res(take(1usize), |c: &[u8]| {
Ok(match c[0] {
b'L' => Direction::Left,
b'U' => Direction::Up,
b'R' => Direction::Right,
b'D' => Direction::Down,
e => return Err(format!("Invalid digging direction {e}")),
})
}),
tag(" "),
),
terminated(nom::character::complete::u64, tag(" ")),
),
|(dir, amount)| Dig { dir, amount },
),
take(10usize),
))(i)
}
fn compute_points(instructions: &[Dig]) -> Vec<(i64, i64)> {
let mut result = Vec::with_capacity(instructions.len() + 1);
result.push((0, 0));
let mut x = 0;
let mut y = 0;
for &Dig { dir, amount } in instructions {
match dir {
Direction::Up => y -= amount as i64,
Direction::Left => x -= amount as i64,
Direction::Down => y += amount as i64,
Direction::Right => x += amount as i64,
}
result.push((x, y));
}
debug_assert_eq!(result.first(), result.last());
result
}
fn shoelace(points: &[(i64, i64)]) -> i64 {
points
.windows(2)
.map(|w| w[0].0 * w[1].1 - w[0].1 * w[1].0)
.sum::<i64>()
/ 2
}
fn solve(digs: &[Dig]) -> anyhow::Result<String> {
let points = compute_points(digs);
let area = shoelace(&points);
// Assumption: we don't cross over ourselves
let perimeter = digs.iter().map(|dig| dig.amount as i64).sum::<i64>();
let total = area + perimeter / 2 + 1;
Ok(total.to_string())
}
pub fn part1(input: &[u8]) -> anyhow::Result<String> {
let digs = parse_input(input, parse_instructions)?;
solve(&digs)
}
fn parse_colors(i: &[u8]) -> IResult<&[u8], Vec<Dig>> {
fn parse_color(i: &[u8]) -> anyhow::Result<u64> {
// stdlib offers hex parsing but requires going through string, incurring utf-8 validation.
// better do it ourselves.
let mut num = 0;
for &c in &i[1..] {
num *= 16;
num += (c as char).to_digit(16).context("Invalid hex")?;
}
Ok(num.into())
}
many1(delimited(
take_until("#"),
map_res(take(7usize), |color: &[u8]| -> anyhow::Result<Dig> {
let num = parse_color(color)?;
let amount = num >> 4;
let dir = match num & 0xF {
0 => Direction::Right,
1 => Direction::Down,
2 => Direction::Left,
3 => Direction::Up,
other => anyhow::bail!("Unknown direction: {other}"),
};
Ok(Dig { dir, amount })
}),
tag(")\n"),
))(i)
}
pub fn part2(input: &[u8]) -> anyhow::Result<String> {
let digs = parse_input(input, parse_colors)?;
solve(&digs)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/18.txt");
#[test]
fn sample_part1() {
assert_eq!("62", part1(SAMPLE).unwrap());
}
#[test]
fn sample_part2() {
assert_eq!("952408144115", part2(SAMPLE).unwrap());
}
}

7
2023/src/day19.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

7
2023/src/day20.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

7
2023/src/day21.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

7
2023/src/day22.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

7
2023/src/day23.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

7
2023/src/day24.rs Normal file
View File

@@ -0,0 +1,7 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

3
2023/src/day25.rs Normal file
View File

@@ -0,0 +1,3 @@
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
anyhow::bail!("Not implemented")
}

91
2023/src/lib.rs Normal file
View File

@@ -0,0 +1,91 @@
use anyhow::Result;
mod common;
mod day01;
mod day02;
mod day03;
mod day04;
mod day05;
mod day06;
mod day07;
mod day08;
mod day09;
mod day10;
mod day11;
mod day12;
mod day13;
mod day14;
mod day15;
mod day16;
mod day17;
mod day18;
mod day19;
mod day20;
mod day21;
mod day22;
mod day23;
mod day24;
mod day25;
type Solution = fn(&[u8]) -> Result<String>;
pub fn get_implementation(day: u8, part2: bool) -> Result<Solution> {
if !part2 {
match day {
1 => Ok(day01::part1),
2 => Ok(day02::part1),
3 => Ok(day03::part1),
4 => Ok(day04::part1),
5 => Ok(day05::part1),
6 => Ok(day06::part1),
7 => Ok(day07::part1),
8 => Ok(day08::part1),
9 => Ok(day09::part1),
10 => Ok(day10::part1),
11 => Ok(day11::part1),
12 => Ok(day12::part1),
13 => Ok(day13::part1),
14 => Ok(day14::part1),
15 => Ok(day15::part1),
16 => Ok(day16::part1),
17 => Ok(day17::part1),
18 => Ok(day18::part1),
19 => Ok(day19::part1),
20 => Ok(day20::part1),
21 => Ok(day21::part1),
22 => Ok(day22::part1),
23 => Ok(day23::part1),
24 => Ok(day24::part1),
25 => Ok(day25::part1),
_ => anyhow::bail!("Invalid day for part 1: {day}"),
}
} else {
match day {
1 => Ok(day01::part2),
2 => Ok(day02::part2),
3 => Ok(day03::part2),
4 => Ok(day04::part2),
5 => Ok(day05::part2),
6 => Ok(day06::part2),
7 => Ok(day07::part2),
8 => Ok(day08::part2),
9 => Ok(day09::part2),
10 => Ok(day10::part2),
11 => Ok(day11::part2),
12 => Ok(day12::part2),
13 => Ok(day13::part2),
14 => Ok(day14::part2),
15 => Ok(day15::part2),
16 => Ok(day16::part2),
17 => Ok(day17::part2),
18 => Ok(day18::part2),
19 => Ok(day19::part2),
20 => Ok(day20::part2),
21 => Ok(day21::part2),
22 => Ok(day22::part2),
23 => Ok(day23::part2),
24 => Ok(day24::part2),
_ => anyhow::bail!("Invalid day for part 2: {day}"),
}
}
}

61
2023/src/main.rs Normal file
View File

@@ -0,0 +1,61 @@
use std::fs::File;
use std::io::Read;
use std::num::NonZeroU8;
use std::path::PathBuf;
use std::time::Instant;
use anyhow::Result;
use clap::Parser;
use aoc_2023::get_implementation;
/// Advent of Code 2022 runner
#[derive(Parser)]
struct Opts {
/// Which day to run
day: NonZeroU8,
/// Print time taken
#[clap(short, long)]
time: bool,
/// Run part 2 instead of part 1
#[clap(short = '2', long)]
part2: bool,
/// Read input from the given file instead of stdin
#[clap(short, long)]
input: Option<PathBuf>,
}
impl Opts {
fn input_data(&self) -> Result<Vec<u8>> {
let mut buffer = Vec::new();
if let Some(input) = &self.input {
File::open(input)?.read_to_end(&mut buffer)?;
} else {
std::io::stdin().read_to_end(&mut buffer)?;
}
Ok(buffer)
}
}
fn main() -> Result<()> {
let opts: Opts = Opts::parse();
let input = opts.input_data()?;
let implementation = get_implementation(opts.day.get(), opts.part2)?;
let begin = Instant::now();
let result = implementation(&input)?;
if opts.time {
eprintln!("Execution time: {:?}", Instant::now().duration_since(begin));
}
println!("{result}");
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More