2 Commits

Author SHA1 Message Date
bbfa367775 Slightly better ICACHE hits 2022-12-09 09:20:34 +01:00
951ed73024 Slow O(n) algorithm for part 2 2022-12-08 22:57:36 +01:00
97 changed files with 155 additions and 18554 deletions

View File

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

3
.gitignore vendored
View File

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

View File

@@ -6,16 +6,13 @@ 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.11"
ndarray = "0.15.6"
itertools = "0.10.5"
nom = "7.1.1"
strength_reduce = "0.2.4"
[dev-dependencies]
criterion = "0.5.0"
criterion = "0.4.0"
[profile.release]
# Keep debug information in release for better flamegraphs

View File

@@ -10,31 +10,34 @@ use criterion::Criterion;
/// 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");
fn read_input(day: u8) -> Vec<u8> {
let input_path = format!("inputs/{:02}.txt", day);
let mut buffer = Vec::new();
File::open(input_path)?.read_to_end(&mut buffer)?;
File::open(input_path)
.expect("Failed to open input file")
.read_to_end(&mut buffer)
.expect("Failed to read input file");
Ok(buffer)
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();
let input = read_input(day);
c.bench_with_input(BenchmarkId::new("part1", day), &input, |b, i| {
b.iter(|| part1(i));
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));
});
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));
});
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,140 +0,0 @@
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

View File

@@ -1,55 +0,0 @@
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

View File

@@ -1,41 +0,0 @@
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

View File

@@ -1,449 +0,0 @@
[[[],[],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]]]

View File

@@ -1,147 +0,0 @@
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

View File

@@ -1,24 +0,0 @@
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

View File

@@ -1,50 +0,0 @@
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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -1,27 +0,0 @@
#.########################################################################################################################
#<^^^^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^<^>^<^<^<<^>#
########################################################################################################################.#

View File

@@ -1,126 +0,0 @@
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,12 +1,5 @@
//! 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;
@@ -123,114 +116,3 @@ 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,3 +1,5 @@
use std::cmp::Ordering;
use anyhow::Result;
use nom::branch::alt;
use nom::bytes::complete::tag;
@@ -6,7 +8,6 @@ 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;
@@ -16,7 +17,6 @@ use nom::sequence::tuple;
use nom::IResult;
use crate::common::enumerate;
use crate::common::get_both;
use crate::common::parse_input;
type Move = (usize, usize, usize);
@@ -32,7 +32,7 @@ fn parse_row<'a>(input: &'a [u8], stacks: &mut OwnedStacks) -> IResult<&'a [u8],
Some(v[0])
}),
// Or an empty stack into a None
value(None, tag(" ")),
map(tag(" "), |_| None),
)),
opt(tag(" ")),
)),
@@ -91,6 +91,21 @@ fn parse_task(input: &[u8]) -> IResult<&[u8], (OwnedStacks, Vec<Move>)> {
Ok((input, (stacks, moves)))
}
/// Some magic to get two mutable references into the same slice
fn get_both(stacks: &mut [Vec<u8>], from: usize, to: usize) -> (&mut Vec<u8>, &mut Vec<u8>) {
match from.cmp(&to) {
Ordering::Greater => {
let (begin, end) = stacks.split_at_mut(from);
(&mut end[0], &mut begin[to])
}
Ordering::Less => {
let (begin, end) = stacks.split_at_mut(to);
(&mut begin[from], &mut end[0])
}
Ordering::Equal => panic!("Tried to stack from and to {from}"),
}
}
fn compute_answer(stacks: &mut [Vec<u8>]) -> Result<String> {
let mut result = String::with_capacity(stacks.len());

View File

@@ -84,14 +84,14 @@ fn parse_program(input: &[u8]) -> IResult<&[u8], (u32, Vec<u32>)> {
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();
let searched_size: u32 = sizes.into_iter().filter(|&size| size <= 100000).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;
const TARGET: u32 = 30000000;
const TOTAL: u32 = 70000000;
let (used, sizes) = parse_input(input, parse_program)?;

View File

@@ -1,3 +1,5 @@
use std::cmp::Ordering;
use anyhow::Context;
use anyhow::Result;
@@ -63,19 +65,39 @@ pub fn part1(input: &[u8]) -> Result<String> {
fn scenery<'a>(
values: impl IntoIterator<Item = &'a u8>,
visible: impl IntoIterator<Item = &'a mut usize>,
tree_stack: &mut Vec<(usize, u8)>,
) {
let mut last_seen = [0; 10];
tree_stack.clear();
for (i, (&val, score)) in values.into_iter().zip(visible).enumerate() {
let val = val - b'0';
let visible = i - last_seen[val as usize];
scenery_helper(i, tree_stack, val, score);
}
}
if i > 0 {
*score *= visible;
last_seen[..=(val as usize)].fill(i);
} else {
*score = 0;
fn scenery_helper(i: usize, tree_stack: &mut Vec<(usize, u8)>, val: u8, score: &mut usize) {
if i > 0 {
let mut first = 0;
while let Some((pos, other)) = tree_stack.pop() {
match other.cmp(&val) {
Ordering::Less => (),
Ordering::Equal => {
first = pos;
break;
}
Ordering::Greater => {
tree_stack.push((pos, other));
first = pos;
break;
}
}
}
tree_stack.push((i, val));
*score *= i - first;
} else {
*score = 0;
}
}
@@ -88,15 +110,18 @@ pub fn part2(input: &[u8]) -> Result<String> {
let mut score = vec![1; width * height];
let mut tree_stack = Vec::with_capacity(10);
// Horizontal striping
for (y, row) in input.chunks_exact(width + 1).enumerate() {
// First, left to right
scenery(&row[..width], &mut score[(y * width)..]);
scenery(&row[..width], &mut score[(y * width)..], &mut tree_stack);
// Then right to left
scenery(
row[..width].iter().rev(),
score[(y * width)..(y * width + width)].iter_mut().rev(),
&mut tree_stack,
);
}
@@ -106,12 +131,14 @@ pub fn part2(input: &[u8]) -> Result<String> {
scenery(
input[x..].iter().step_by(width + 1),
score[x..].iter_mut().step_by(width),
&mut tree_stack,
);
// Bottom to top
scenery(
input[x..].iter().step_by(width + 1).rev(),
score[x..].iter_mut().step_by(width).rev(),
&mut tree_stack,
)
}

View File

@@ -1,122 +1,9 @@
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;
use crate::common::parse_input;
use crate::common::Vec2;
#[derive(Copy, Clone)]
enum Direction {
Up,
Left,
Right,
Down,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,131 +1,9 @@
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;
#[derive(Copy, Clone)]
enum Instruction {
AddX(i32),
Noop,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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);
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,189 +1,9 @@
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;
use crate::common::parse_input;
#[derive(Debug, Copy, Clone)]
enum Operation {
Mul(u64),
Add(u64),
Square,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,109 +1,9 @@
use std::collections::VecDeque;
use anyhow::Context;
use anyhow::Result;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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")
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,135 +1,9 @@
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;
#[derive(Debug, PartialEq, Eq, Clone)]
enum Signal {
Number(u32),
List(Vec<Signal>),
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,155 +1,9 @@
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;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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")
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,178 +1,9 @@
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;
use crate::common::parse_input;
use crate::common::Vec2;
struct Beacon {
pos: Vec2,
closest: Vec2,
range: i32,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,166 +1,9 @@
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;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,239 +1,9 @@
use anyhow::Result;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,148 +1,9 @@
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;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,297 +1,9 @@
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;
use crate::common::parse_input;
#[repr(usize)]
#[derive(Clone, Copy)]
enum Mineral {
Ore,
Clay,
Obsidian,
Geode,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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);
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,133 +1,9 @@
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;
use crate::common::parse_input;
fn parse_encrypted(input: &[u8]) -> IResult<&[u8], Vec<i64>> {
many0(terminated(nom::character::complete::i64, newline))(input)
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
// 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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,191 +1,9 @@
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;
use crate::common::parse_input;
type Input<'a> = AHashMap<&'a [u8], Monkey<'a>>;
#[derive(Clone, Copy)]
enum Operation {
Mul,
Div,
Add,
Sub,
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,456 +1,9 @@
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;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
#[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}");
}
}
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,205 +1,9 @@
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;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,214 +1,9 @@
use std::collections::VecDeque;
use std::mem;
use ahash::AHashSet;
use anyhow::Context;
use anyhow::Result;
use strength_reduce::StrengthReducedUsize;
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 part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}
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");
}
pub fn part2(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

@@ -1,71 +1,5 @@
use anyhow::Result;
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");
}
pub fn part1(_input: &[u8]) -> Result<String> {
anyhow::bail!("not implemented")
}

View File

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

View File

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

View File

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

View File

@@ -1,146 +0,0 @@
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

View File

@@ -1,27 +0,0 @@
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

View File

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

View File

@@ -1,23 +0,0 @@
[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]

View File

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

View File

@@ -1,14 +0,0 @@
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

View File

@@ -1,10 +0,0 @@
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

View File

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

View File

@@ -1,13 +0,0 @@
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

View File

@@ -1,11 +0,0 @@
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.

View File

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

View File

@@ -1,15 +0,0 @@
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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,23 +0,0 @@
[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"] }
nom = "7.1.3"
[dev-dependencies]
criterion = "0.5.1"
[profile.release]
# Keep debug information in release for better flamegraphs
debug = true
[[bench]]
name = "days"
harness = false

View File

@@ -1,44 +0,0 @@
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 = 3;
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);

View File

View File

View File

@@ -1,236 +0,0 @@
//! 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;
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.
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.
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
T: PartialOrd,
{
if a < b {
(a, b)
} else {
(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);
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))
}
}
#[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,74 +0,0 @@
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());
}
}

View File

@@ -1,98 +0,0 @@
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");
}
}

View File

@@ -1,179 +0,0 @@
use std::collections::HashMap;
use std::ops::Index;
use anyhow::Context;
struct Grid<'a> {
width: usize,
data: &'a [u8],
}
impl<'a> Grid<'a> {
pub fn new(data: &'a [u8]) -> anyhow::Result<Self> {
let width = 1 + data
.iter()
.position(|&c| c == b'\n')
.context("Failed to find end of line in grid")?;
anyhow::ensure!(
data.len() % width == 0,
"Grid should divide equally into rows"
);
Ok(Self { width, data })
}
pub fn height(&self) -> usize {
self.data.len() / self.width
}
pub fn width(&self) -> usize {
self.width - 1
}
pub fn rows(&self) -> impl Iterator<Item = &'a [u8]> {
let width = self.width();
self.data
.chunks_exact(self.width)
.map(move |row| &row[..width])
}
}
impl<'a> Index<usize> for Grid<'a> {
type Output = [u8];
fn index(&self, y: usize) -> &Self::Output {
let offset = y * self.width;
&self.data[offset..(offset + self.width())]
}
}
fn is_surrounded(grid: &Grid<'_>, 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<'_>, 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");
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,91 +0,0 @@
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}"),
}
}
}

View File

@@ -1,61 +0,0 @@
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(())
}

View File

@@ -1,4 +0,0 @@
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet

View File

@@ -1,7 +0,0 @@
two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen

View File

@@ -1,5 +0,0 @@
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green

View File

@@ -1,10 +0,0 @@
467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..