44 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
79387b5f14 Slightly more efficient O(kn) implementation 2022-12-08 22:40:39 +01:00
a05dc588db Implement 2022 day 8 part 2 2022-12-08 12:09:04 +01:00
b080859356 Replace todo with error, bench everything 2022-12-08 11:06:59 +01:00
fead587b2a Implement 2022 day 8 part 1 2022-12-08 11:01:48 +01:00
eec886b5e2 Slightly cleaner parser 2022-12-07 16:01:09 +01:00
45a6c78d77 Remove most allocations 2022-12-07 15:27:30 +01:00
e80b5bde68 Implement 2022 day 7 2022-12-07 10:27:06 +01:00
1cd5579bf6 Use iterators instead of explicit indexing 2022-12-06 18:37:38 +01:00
7c7c69255d Replace indirect indexing
230 byte overhead is worth it to avoid conversions and potential
indexing errors
2022-12-06 18:23:43 +01:00
391bba24c5 Use enumerate combinator 2022-12-06 18:19:42 +01:00
e887a8ad0d Implement 2022 day 6 2022-12-06 08:29:26 +01:00
38a024d095 Implement 2022 day 5 2022-12-05 11:14:36 +01:00
6802a7bf33 Refactor common parts 2022-12-04 11:18:03 +01:00
9d23e80256 Implement 2022 day 4 2022-12-04 11:14:23 +01:00
e1b3b9d179 Implement 2022 day 3 2022-12-03 20:23:14 +01:00
30d1a16075 Collect into vec for nicer vectorization 2022-12-02 09:52:09 +01:00
256d351f8e Implement day 2 2022 2022-12-02 09:06:59 +01:00
48594a75e6 Make parsers more robust 2022-12-01 11:28:59 +01:00
85a51b13c1 Implement 2022 day 1 2022-12-01 09:40:00 +01:00
2ae2d6baa8 Merge pull request #4 from bertptrs/setup-2022 2022-11-30 18:08:54 +01:00
4a55e53182 Update README and references 2022-11-24 08:23:58 +01:00
af0897300d Add caching to CI pipeline for speed 2022-11-05 16:17:47 +01:00
cabae7b1fd Convert 2021 CI to 2022 2022-11-05 16:17:47 +01:00
0635141ac6 Add skeleton for 2022 2022-11-05 16:17:47 +01:00
d9d5947c3b Replace unnecessary Vec with slice 2022-06-07 08:32:59 +02:00
cc8b4ce353 Update vulnerable dependencies
Not that this will affect anyone, but it's nice anyway.
2022-06-07 08:25:30 +02:00
0b91da04b3 Add benchmarking plots 2022-01-09 18:41:02 +01:00
dba146b299 Avoid instantiating translated sets 2022-01-09 15:45:22 +01:00
33111615be Directly infer matched pivot 2022-01-09 14:22:41 +01:00
04e8a41d98 Use pre-matching strategy
Ensure that both scanners to be matched have a set of enough distances
in common to avoid matching between groups that cannot possibly be
related.
2022-01-08 19:50:16 +01:00
36d76018ba Correct width calculation
The original worked by accident
2022-01-06 23:35:38 +01:00
4172fd0463 Slightly more efficiently pre-allocate bitsets 2022-01-06 23:22:10 +01:00
ad0b4a4659 Use running masks instead of computing one by one 2022-01-06 23:05:41 +01:00
2dab7342f8 Replace sparse map with bitset 2022-01-06 22:52:57 +01:00
edd14a0e3d Update to Clap 3.0.0! 2022-01-02 23:06:32 +01:00
4d7188e1ff Replace hashset with bitset 2022-01-02 22:38:28 +01:00
255edaca79 Implement day 24 2022-01-02 21:47:07 +01:00
8ea716cba8 Properly use TryFrom 2022-01-02 18:49:25 +01:00
601de2c565 Readability 2022-01-02 18:30:13 +01:00
894524bc81 Implement part 2
Turns out you can incorrectly implement the problem and still get the
right answer for part 1. If you then correct it, it's a lot faster.
2022-01-02 18:28:04 +01:00
f19bf28f34 Properly implemented A* estimate 2022-01-02 16:17:01 +01:00
de3a24a87c Implementation day 23 2022-01-02 16:17:01 +01:00
69 changed files with 10159 additions and 142 deletions

View File

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

View File

@@ -4,4 +4,4 @@ version = "0.1.0"
authors = ["Bert Peters <bert.ljpeters@gmail.com>"]
[dependencies]
regex = "0.1"
regex = "1"

View File

@@ -73,10 +73,10 @@ fn main() {
let door_label = line.unwrap();
let caps = room_pattern.captures(&door_label).unwrap();
let name = caps.at(1).unwrap();
let checksum = caps.at(4).unwrap();
let name = caps.get(1).unwrap().as_str();
let checksum = caps.get(4).unwrap().as_str();
if is_valid(name, checksum) {
let sector_id = caps.at(3).unwrap().parse().unwrap();
let sector_id = caps.get(3).unwrap().as_str().parse().unwrap();
cur_sum += sector_id;
let decoded: String = name.chars()

View File

@@ -4,5 +4,5 @@ version = "0.1.0"
authors = ["Bert Peters <bert.ljpeters@gmail.com>"]
[dependencies]
regex = "^0.1"
lazy_static = "^0.2"
regex = "1"
lazy_static = "1"

View File

@@ -4,4 +4,4 @@ version = "0.1.0"
authors = ["Bert Peters <bert.ljpeters@gmail.com>"]
[dependencies]
regex="^0.1"
regex="1"

View File

@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
clap = { version = "3.0.0-rc.0", features = ["derive"] }
clap = { version = "3", features = ["derive"] }
itertools = "0.10"
nom = "7"

View File

@@ -20,3 +20,15 @@ OPTIONS:
-i, --input <INPUT> Read input from the given file instead of stdin
-t, --time Print time taken
```
## That goal was achieved
Runtime benchmarked with [Criterion], reading input directly from memory to avoid disk IO
inconsistencies.
![Cumulative time](./cumulative-time.svg)
![Time by day](./individual-time.svg)
[Criterion]: https://github.com/bheisler/criterion.rs

97
2021/create_timing_plots.py Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
import json
from pathlib import Path
from typing import Dict
import numpy as np
import matplotlib.pyplot as plt
def read_timings() -> Dict[int, Dict]:
timings = {}
for day in Path('target/criterion/part1').iterdir():
with open(day / 'new' / 'estimates.json', mode='rb') as f:
timings[int(day.parts[-1])] = {
1: json.load(f)
}
for day in Path('target/criterion/part2').iterdir():
with open(day / 'new' / 'estimates.json', mode='rb') as f:
timings[int(day.parts[-1])][2] = json.load(f)
return timings
def plot_cumulative_time(timings: Dict[int, Dict]):
plt.clf()
times = [0]
for day in range(min(timings.keys()), max(timings.keys()) + 1):
times.append(timings[day][1]['mean']['point_estimate'])
if day < 25:
times.append(timings[day][2]['mean']['point_estimate'])
else:
times.append(0)
cumulative = np.cumsum(times)
# Convert from nanoseconds to seconds
cumulative /= 1e9
x = np.arange(0.0, 25.5, 0.5)
plt.plot(x, cumulative, label="Cumulative time", drawstyle='steps-post')
plt.plot([0, 25], [0, 0.5], label="Target time")
plt.ylabel('Cumulative time (s)')
plt.xlabel('Days completed')
plt.legend()
plt.tight_layout()
plt.xlim(0, 25)
plt.ylim(0, 0.5)
plt.savefig('cumulative-time.svg')
def plot_individual_times(timings: Dict[int, Dict]):
plt.clf()
def plot(parts, **kwargs):
x = np.arange(1, len(parts) + 1)
values = np.array(list(part['mean']['point_estimate'] for part in parts))
upper = np.array(list(part['mean']['confidence_interval']['upper_bound'] for part in parts))
lower = np.array(list(part['mean']['confidence_interval']['lower_bound'] for part in parts))
# Convert from ns to s
yerr = np.array([upper - values, lower - values]) / 1e9
values = values / 1e9
plt.bar(x, values, yerr=yerr, align='edge', log=True, **kwargs)
pass
plot(list(timings[day][1] for day in range(1, 26)), label="Part 1", width=-0.4)
plot(list(timings[day][2] for day in range(1, 25)), label="Part 2", width=0.4)
plt.ylabel('Runtime (s)')
plt.xlabel('Day')
plt.xlim(0, 26)
plt.xticks(np.arange(1, 26))
plt.legend()
plt.tight_layout()
plt.savefig('individual-time.svg')
def main():
timings = read_timings()
plot_cumulative_time(timings)
plot_individual_times(timings)
if __name__ == '__main__':
main()

1
2021/cumulative-time.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

1
2021/individual-time.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -90,7 +90,65 @@ where
let mut buffer = Vec::new();
input.read_to_end(&mut buffer).unwrap();
let (_, output) = parser(&buffer).finish().unwrap();
output
match parser(&buffer).finish() {
Ok((_, output)) => output,
Err(err) => {
panic!(
"Failed to parse input with error {:?} at \"{}\"",
err.code,
String::from_utf8_lossy(err.input)
);
}
}
}
#[derive(Default)]
pub struct BitSet {
buffer: Vec<u32>,
}
impl BitSet {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
let buffer = vec![0; capacity / 32];
Self { buffer }
}
fn convert_value(value: usize) -> (usize, u32) {
let chunk = value / 32;
let bit = 1 << (31 - (value % 32));
(chunk, bit)
}
pub fn insert(&mut self, value: usize) -> bool {
let (chunk, bit) = Self::convert_value(value);
if self.buffer.len() <= chunk + 1 {
self.buffer.resize(chunk + 1, 0);
}
let not_present = self.buffer[chunk] & bit;
self.buffer[chunk] |= bit;
not_present == 0
}
pub fn len(&self) -> usize {
self.buffer.iter().map(|c| c.count_ones() as usize).sum()
}
pub fn contains(&self, value: usize) -> bool {
let (chunk, bit) = Self::convert_value(value);
self.buffer
.get(chunk)
.map(|&c| c & bit != 0)
.unwrap_or(false)
}
}

View File

@@ -1,69 +1,95 @@
use std::collections::HashMap;
use std::io::Read;
use std::iter::repeat;
use nom::bytes::complete::tag;
use nom::sequence::tuple;
use nom::Finish;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::separated_list1;
use nom::sequence::separated_pair;
use nom::IResult;
use crate::common::ordered;
use crate::common::LineIter;
use crate::common::read_input;
use crate::common::BitSet;
type Coord = (u16, u16);
fn coordinates(input: &str) -> IResult<&str, Coord> {
use nom::character::complete;
fn coordinates(input: &[u8]) -> IResult<&[u8], Coord> {
use nom::character::complete::char;
use nom::character::complete::u16;
let (input, (x, _, y)) = tuple((complete::u16, complete::char(','), complete::u16))(input)?;
Ok((input, (x, y)))
separated_pair(u16, char(','), u16)(input)
}
fn line_definition(input: &str) -> IResult<&str, (Coord, Coord)> {
let (input, (begin, _, end)) = tuple((coordinates, tag(" -> "), coordinates))(input)?;
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<(Coord, Coord)>> {
let read_line = map(
separated_pair(coordinates, tag(" -> "), coordinates),
|(begin, end)| ordered(begin, end),
);
// Sorting the coordinates saves trouble later
Ok((input, ordered(begin, end)))
separated_list1(newline, read_line)(input)
}
fn stripe(
map: &mut HashMap<Coord, u16>,
once: &mut BitSet,
twice: &mut BitSet,
width: usize,
xs: impl Iterator<Item = u16>,
ys: impl Iterator<Item = u16>,
) {
for (x, y) in xs.zip(ys) {
*map.entry((x, y)).or_default() += 1;
let index = x as usize + y as usize * width;
if !once.insert(index) {
twice.insert(index);
}
}
}
fn part_common(input: &mut dyn Read, diagonals: bool) -> String {
let mut reader = LineIter::new(input);
let mut map = HashMap::new();
let lines = read_input(input, parse_input);
while let Some(line) = reader.next() {
let (begin, end) = line_definition(line).finish().unwrap().1;
let width = lines
.iter()
.map(|&(_, (x, _))| x as usize + 1)
.max()
.unwrap();
let mut once_map = BitSet::new();
let mut twice_map = BitSet::new();
for (begin, end) in lines {
if begin.0 == end.0 {
let y_range = begin.1..=end.1;
stripe(&mut map, repeat(begin.0), y_range);
stripe(
&mut once_map,
&mut twice_map,
width,
repeat(begin.0),
y_range,
);
} else if begin.1 == end.1 {
let x_range = begin.0..=end.0;
stripe(&mut map, x_range, repeat(begin.1));
stripe(
&mut once_map,
&mut twice_map,
width,
x_range,
repeat(begin.1),
);
} else if diagonals {
let x_range = begin.0..=end.0;
let y_range = (begin.1.min(end.1))..=(begin.1.max(end.1));
if begin.1 > end.1 {
// For a downward slope we need to reverse Y
stripe(&mut map, x_range, y_range.rev());
stripe(&mut once_map, &mut twice_map, width, x_range, y_range.rev());
} else {
stripe(&mut map, x_range, y_range);
stripe(&mut once_map, &mut twice_map, width, x_range, y_range);
}
}
}
map.values().filter(|&&v| v > 1).count().to_string()
twice_map.len().to_string()
}
pub fn part1(input: &mut dyn Read) -> String {
@@ -82,11 +108,6 @@ mod tests {
const SAMPLE: &[u8] = include_bytes!("samples/05.txt");
#[test]
fn test_parser() {
assert_eq!(line_definition("6,4 -> 2,0"), Ok(("", ((2, 0), (6, 4)))));
}
#[test]
fn sample_part1() {
test_implementation(part1, SAMPLE, 5)

View File

@@ -48,7 +48,7 @@ fn parse_fold(input: &[u8]) -> IResult<&[u8], Fold> {
)(input)
}
fn apply_fold(dots: &mut Vec<Coords>, fold: Fold) {
fn apply_fold(dots: &mut [Coords], fold: Fold) {
match fold {
Fold::X(coord) => dots.iter_mut().for_each(|(x, _)| {
if *x >= coord {

View File

@@ -182,7 +182,7 @@ mod tests {
fn sample_part1() {
let answers = [16, 12, 23, 31];
for (&sample, answer) in SAMPLE.into_iter().zip(answers) {
for (&sample, answer) in SAMPLE.iter().zip(answers) {
test_implementation(part1, sample, answer);
}
}

View File

@@ -1,6 +1,8 @@
use std::collections::HashMap;
use std::collections::HashSet;
use std::io::Read;
use std::ops::Add;
use std::ops::Deref;
use std::ops::Sub;
use nom::bytes::complete::tag;
@@ -23,6 +25,10 @@ impl Point3 {
pub fn manhattan(&self) -> i32 {
self.0.into_iter().map(i32::abs).sum()
}
pub fn euler_square(&self) -> i32 {
self.0.into_iter().map(|c| c * c).sum()
}
}
impl Sub for Point3 {
@@ -49,6 +55,44 @@ impl Add for Point3 {
}
}
struct Scanner {
visible: Vec<Point3>,
distances: HashMap<i32, (Point3, Point3)>,
}
impl Scanner {
pub fn new(visible: Vec<Point3>) -> Self {
let distances = visible
.iter()
.enumerate()
.flat_map(|(skip, &a)| {
visible[(skip + 1)..]
.iter()
.map(move |&b| ((a - b).euler_square(), (a, b)))
})
.collect();
Self { visible, distances }
}
pub fn can_overlap(&self, other: &Self) -> bool {
other
.distances
.keys()
.filter(|&k| self.distances.contains_key(k))
.count()
>= 11
}
}
impl Deref for Scanner {
type Target = [Point3];
fn deref(&self) -> &Self::Target {
&self.visible
}
}
struct Rotations<'a> {
points: &'a [Point3],
axes: [usize; 3],
@@ -119,32 +163,56 @@ fn parse_point(input: &[u8]) -> IResult<&[u8], Point3> {
)(input)
}
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<Vec<Point3>>> {
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<Scanner>> {
use nom::character::complete::i32;
let parse_header = delimited(tag("--- scanner "), i32, tag(" ---\n"));
let parse_scanner = preceded(parse_header, many1(terminated(parse_point, newline)));
let parse_scanner = map(
preceded(parse_header, many1(terminated(parse_point, newline))),
Scanner::new,
);
separated_list1(newline, parse_scanner)(input)
}
fn try_overlap(
correct: &[(Point3, HashSet<Point3>)],
candidate: &[Point3],
) -> Option<(Point3, Vec<Point3>)> {
let mut relative = HashSet::new();
fn find_pivot(group: &Scanner, related: &Scanner) -> Option<Point3> {
let mut counter = HashMap::new();
for (distance, &(a, b)) in &group.distances {
if related.distances.contains_key(distance) {
*counter.entry(a).or_insert(0) += 1;
*counter.entry(b).or_insert(0) += 1;
}
}
counter
.into_iter()
.max_by_key(|(_, count)| *count)
.map(|t| t.0)
}
fn try_overlap(matched: &Scanner, candidate: &Scanner) -> Option<(Point3, Scanner)> {
if !matched.can_overlap(candidate) {
return None;
}
let matched_pivot = find_pivot(matched, candidate)?;
let correct: HashSet<_> = matched.iter().map(|&base| base - matched_pivot).collect();
for rot in Rotations::new(candidate) {
for &start in &rot {
relative.clear();
let translated_iter = rot.iter().map(|&other| other - start);
relative.extend(rot.iter().map(|&other| other - start));
if let Some((base, _)) = correct.iter().find(|(_, correct_relative)| {
correct_relative.intersection(&relative).count() >= 12
}) {
if translated_iter
.clone()
.filter(|p| correct.contains(p))
.count()
>= 12
{
// Found a solution, build the correct output
let translated = relative.drain().map(|point| point + *base).collect();
let translated = translated_iter.map(|point| point + matched_pivot).collect();
return Some((start - *base, translated));
return Some((start - matched_pivot, Scanner::new(translated)));
}
}
}
@@ -157,33 +225,30 @@ fn parts_common(input: &mut dyn Read) -> (HashSet<Point3>, Vec<Point3>) {
let mut points: HashSet<_> = scanners[0].iter().copied().collect();
let mut todo = vec![std::mem::take(&mut scanners[0])];
let mut todo = vec![scanners.remove(0)];
let mut scanners_found = vec![Point3::default()];
while let Some(matched) = todo.pop() {
if scanners.iter().all(Vec::is_empty) {
if scanners.is_empty() {
break;
}
let relative: Vec<(Point3, HashSet<Point3>)> = matched
.iter()
.map(|&base| (base, matched.iter().map(|&other| (other - base)).collect()))
.collect();
let mut i = 0;
for candidate in &mut scanners {
if candidate.is_empty() {
continue;
}
if let Some((scanner, result)) = try_overlap(&relative, candidate) {
while i < scanners.len() {
if let Some((scanner, result)) = try_overlap(&matched, &scanners[i]) {
scanners.remove(i);
scanners_found.push(scanner);
points.extend(result.iter().copied());
todo.push(result);
candidate.clear();
} else {
i += 1;
}
}
}
assert!(scanners.is_empty());
(points, scanners_found)
}

View File

@@ -1,10 +1,124 @@
use std::collections::HashSet;
use std::fmt::Display;
use std::io::Read;
use std::mem::swap;
use std::ops::Index;
use crate::common::BitSet;
type Translation = [bool; 512];
type Point = (i32, i32);
type Field = HashSet<Point>;
struct Field {
width: usize,
height: usize,
infinity: bool,
finite: BitSet,
}
impl Field {
pub fn from_input<'a>(input: impl Iterator<Item = &'a [u8]>) -> Self {
let mut input = input.peekable();
let width = input.peek().unwrap().len();
let mut finite = BitSet::new();
let len = input
.flatten()
.enumerate()
.map(|(index, &c)| {
if c == b'#' {
finite.insert(index);
}
})
.count();
debug_assert_eq!(len % width, 0);
let height = len / width;
Self {
width,
height,
finite,
infinity: false,
}
}
pub fn advance(&mut self, translation: &[bool; 512]) {
const INDEX_MASK: usize = (1 << 9) - 1;
let new_width = self.width + 2;
let new_height = self.height + 2;
let mut new_finite = BitSet::with_capacity(new_width * new_height);
for y in 0..new_height {
let mut mask = if self.infinity { INDEX_MASK } else { 0 };
for x in 0..new_width {
const COLUMN_MASK: usize = 0b001001001;
let mut submask = if self.infinity { COLUMN_MASK } else { 0 };
for y in y.saturating_sub(2)..=y {
submask = (submask << 3) | (self[(x, y)] as usize);
}
mask <<= 1;
mask &= !COLUMN_MASK;
mask |= submask;
mask &= INDEX_MASK;
if translation[mask] {
let index = x + y * new_width;
new_finite.insert(index);
}
}
}
self.width += 2;
self.height += 2;
self.finite = new_finite;
self.infinity = translation[if self.infinity { INDEX_MASK } else { 0 }];
}
pub fn len(&self) -> usize {
assert!(!self.infinity);
self.finite.len()
}
}
impl Index<(usize, usize)> for Field {
type Output = bool;
#[inline]
fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
if x >= self.width || y >= self.height {
return &self.infinity;
}
let index = x + y * self.width;
if self.finite.contains(index) {
&true
} else {
&false
}
}
}
impl Display for Field {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for y in 0..self.height {
for x in 0..self.width {
if self[(x, y)] {
write!(f, "#")?
} else {
write!(f, ".")?
}
}
writeln!(f)?;
}
Ok(())
}
}
fn read_input(input: &mut dyn Read) -> (Translation, Field) {
let mut buffer = Vec::new();
@@ -19,67 +133,16 @@ fn read_input(input: &mut dyn Read) -> (Translation, Field) {
.zip(it.next().unwrap())
.for_each(|(t, &c)| *t = c == b'#');
let mut field = Field::default();
for (y, line) in it.skip(1).enumerate() {
for (x, _) in line.iter().enumerate().filter(|(_, &c)| c == b'#') {
field.insert((x as i32, y as i32));
}
}
let field = Field::from_input(it.skip(1));
(translation, field)
}
fn find_dimensions(field: &Field) -> ((i32, i32), (i32, i32)) {
field
.iter()
.fold(((0, 0), (0, 0)), |((xmin, xmax), (ymin, ymax)), &(x, y)| {
((xmin.min(x), xmax.max(x)), (ymin.min(y), ymax.max(y)))
})
}
fn advance(translation: &Translation, field: &Field, new_field: &mut Field, infinity: &mut bool) {
const INDEX_MASK: usize = (1 << 9) - 1;
new_field.clear();
let ((xmin, xmax), (ymin, ymax)) = find_dimensions(field);
for x in (xmin - 1)..=(xmax + 1) {
let mut index = if *infinity { INDEX_MASK } else { 0 };
for y in (ymin - 1)..=(ymax + 1) {
for dx in -1..=1 {
index <<= 1;
let nx = x + dx;
let ny = y + 1;
if nx < xmin || nx > xmax || ny < ymin || ny > ymax {
index |= *infinity as usize;
} else if field.contains(&(nx, ny)) {
index |= 1;
}
}
index &= INDEX_MASK;
if translation[index] {
new_field.insert((x, y));
}
}
}
*infinity = translation[if *infinity { 511 } else { 0 }]
}
fn parts_common(input: &mut dyn Read, count: usize) -> String {
let (translation, mut field) = read_input(input);
let mut new_field = Field::new();
let mut infinity = false;
for _ in 0..count {
advance(&translation, &field, &mut new_field, &mut infinity);
swap(&mut field, &mut new_field);
field.advance(&translation);
}
field.len().to_string()

View File

@@ -1,9 +1,451 @@
use std::cmp::Reverse;
use std::collections::hash_map::Entry;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::fmt::Display;
use std::io::Read;
use std::mem::swap;
pub fn part1(_input: &mut dyn Read) -> String {
todo!()
use crate::common::LineIter;
type Item<const S: usize> = (u32, State<S>);
type Todo<const S: usize> = BinaryHeap<Reverse<Item<S>>>;
type Visited<const S: usize> = HashMap<State<S>, u32>;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
enum Pod {
A,
B,
C,
D,
}
pub fn part2(_input: &mut dyn Read) -> String {
todo!()
impl Pod {
pub fn cost(self) -> u32 {
match self {
Pod::A => 1,
Pod::B => 10,
Pod::C => 100,
Pod::D => 1000,
}
}
pub fn dest(self) -> usize {
self as usize
}
}
impl TryFrom<usize> for Pod {
type Error = usize;
fn try_from(index: usize) -> Result<Self, Self::Error> {
match index {
0 => Ok(Pod::A),
1 => Ok(Pod::B),
2 => Ok(Pod::C),
3 => Ok(Pod::D),
_ => Err(index),
}
}
}
impl TryFrom<char> for Pod {
type Error = &'static str;
fn try_from(c: char) -> Result<Self, Self::Error> {
match c {
'A' => Ok(Pod::A),
'B' => Ok(Pod::B),
'C' => Ok(Pod::C),
'D' => Ok(Pod::D),
_ => Err("Invalid pod"),
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
struct State<const S: usize> {
hallway: [Option<Pod>; 11],
rooms: [[Option<Pod>; S]; 4],
}
fn room_hallway_pos(room: usize) -> usize {
room * 2 + 2
}
fn abs_delta(a: usize, b: usize) -> usize {
if a < b {
b - a
} else {
a - b
}
}
impl<const S: usize> State<S> {
const VALID_HALLWAY_POS: [usize; 7] = [0, 1, 3, 5, 7, 9, 10];
pub fn is_done(&self) -> bool {
self == &State {
hallway: Default::default(),
rooms: [
[Some(Pod::A); S],
[Some(Pod::B); S],
[Some(Pod::C); S],
[Some(Pod::D); S],
],
}
}
fn add_to_queue(self, cost: u32, todo: &mut Todo<S>, visited: &mut Visited<S>) {
let entry = visited.entry(self.clone());
if matches!(&entry, Entry::Occupied(entry) if *entry.get() <= cost) {
// Already got a better one
return;
}
// nightly only :'(
// entry.insert(cost);
*entry.or_default() = cost;
todo.push(Reverse((cost + self.estimate(), self)))
}
fn estimate(&self) -> u32 {
// A* estimate. For every entry that is not already "at rest", the cost is the cost
// required to get it to the top of its intended room.
// Cost to enter the hole for all pods that still need to
let enter_estimate: u32 = self
.rooms
.iter()
.enumerate()
.map(|(index, room)| {
let pod = Pod::try_from(index).unwrap();
room.iter()
.enumerate()
.rev()
.skip_while(|&(_, &entry)| entry == Some(pod))
.map(|(index, _)| index as u32 + 1)
.sum::<u32>()
* pod.cost()
})
.sum();
// Cost for all of the hallway to move to above their intended rooms
let hallway_estimate: u32 = self
.hallway
.iter()
.enumerate()
.filter_map(|(pos, &pod)| {
let pod = pod?;
let destination_pos = room_hallway_pos(pod.dest());
Some(abs_delta(pos, destination_pos) as u32 * pod.cost())
})
.sum();
// Cost to move out of the room and above the correct rooms
let rooms_estimate: u32 = self
.rooms
.iter()
.enumerate()
.map(|(room_index, room)| {
let hallway_pos = room_hallway_pos(room_index);
room.iter()
.enumerate()
.rev()
.skip_while(|&(_, &entry)| {
entry.map(|pod| pod.dest() == room_index).unwrap_or(false)
})
.filter_map(|(room_pos, &pod)| {
let pod = pod?;
let destination_pos = room_hallway_pos(pod.dest());
let steps = 1 + room_pos + abs_delta(hallway_pos, destination_pos).max(2);
Some(steps as u32 * pod.cost())
})
.sum::<u32>()
})
.sum();
enter_estimate + hallway_estimate + rooms_estimate
}
pub fn generate_next(&self, cost: u32, todo: &mut Todo<S>, visited: &mut Visited<S>) {
self.room_to_hallway(cost, todo, visited);
self.hallway_to_room(cost, todo, visited);
}
fn room_to_hallway(&self, cost: u32, todo: &mut Todo<S>, visited: &mut Visited<S>) {
for (index, room) in self.rooms.iter().enumerate() {
// Check if we even want to move anything out of this room
if room
.iter()
.all(|entry| entry.map(|pod| pod.dest() == index).unwrap_or(true))
{
continue;
}
let (pos, pod) = room
.iter()
.enumerate()
.find_map(|(pos, entry)| entry.map(|pod| (pos, pod)))
.unwrap(); // Safe unwrap, we know it exists from above.
let base_cost = 1 + pos;
let hallway_pos = room_hallway_pos(index);
let mut queue_new = |new_pos, new_cost| {
let mut new_state = self.clone();
swap(
&mut new_state.hallway[new_pos],
&mut new_state.rooms[index][pos],
);
new_state.add_to_queue(new_cost + cost, todo, visited)
};
// Check positions to the left
for new_pos in (0..hallway_pos).rev() {
if self.hallway[new_pos].is_some() {
// Hit an occupied room
break;
}
if !Self::VALID_HALLWAY_POS.contains(&new_pos) {
// Not allowed to stop here
continue;
}
let new_cost = (base_cost + hallway_pos - new_pos) as u32 * pod.cost();
queue_new(new_pos, new_cost);
}
// And to the right
for new_pos in hallway_pos..self.hallway.len() {
if self.hallway[new_pos].is_some() {
// Hit an occupied room
break;
}
if !Self::VALID_HALLWAY_POS.contains(&new_pos) {
// Not allowed to stop here
continue;
}
let new_cost = (base_cost + new_pos - hallway_pos) as u32 * pod.cost();
queue_new(new_pos, new_cost);
}
}
}
fn hallway_to_room(&self, cost: u32, todo: &mut Todo<S>, visited: &mut Visited<S>) {
for (pos, pod) in self
.hallway
.iter()
.enumerate()
.filter_map(|(pos, pod)| pod.map(|pod| (pos, pod)))
{
let room = pod.dest();
let new_hallway_pos = room_hallway_pos(room);
// Check if the path is free
let in_between = if new_hallway_pos < pos {
&self.hallway[(new_hallway_pos + 1)..pos]
} else {
&self.hallway[(pos + 1)..new_hallway_pos]
};
if in_between.iter().any(Option::is_some) {
// Something's in the way
continue;
}
// Check if we can move into the room
if self.rooms[room]
.iter()
.copied()
.flatten()
.any(|other| other != pod)
{
// Scared of other pods
continue;
}
let room_pos = if let Some(pos) = self.rooms[room].iter().rposition(Option::is_none) {
pos
} else {
continue;
};
let new_cost = (abs_delta(pos, new_hallway_pos) + room_pos + 1) as u32 * pod.cost();
let mut new_state = self.clone();
swap(
&mut new_state.hallway[pos],
&mut new_state.rooms[room][room_pos],
);
new_state.add_to_queue(cost + new_cost, todo, visited);
}
}
pub fn solve(&self) -> u32 {
let mut todo = Todo::new();
let mut visited = HashMap::new();
visited.insert(self.clone(), 0);
todo.push(Reverse((self.estimate(), self.clone())));
while let Some(Reverse((_, state))) = todo.pop() {
let cost = *visited.get(&state).unwrap_or(&0);
if state.is_done() {
return cost;
}
state.generate_next(cost, &mut todo, &mut visited);
}
panic!("No route found!")
}
}
impl<const S: usize> Display for State<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let helper = |opt_pod| match opt_pod {
Some(Pod::A) => 'A',
Some(Pod::B) => 'B',
Some(Pod::C) => 'C',
Some(Pod::D) => 'D',
None => '.',
};
writeln!(f, "#############")?;
write!(f, "#")?;
for entry in self.hallway {
write!(f, "{}", helper(entry))?;
}
writeln!(f, "#")?;
for i in 0..S {
writeln!(
f,
" #{}#{}#{}#{}#",
helper(self.rooms[0][i]),
helper(self.rooms[1][i]),
helper(self.rooms[2][i]),
helper(self.rooms[3][i])
)?;
}
write!(f, " #########")
}
}
fn read_input(input: &mut dyn Read) -> State<2> {
let mut reader = LineIter::new(input);
let mut state = State {
hallway: Default::default(),
rooms: Default::default(),
};
let _ = reader.next();
let _ = reader.next();
let mut helper = |idx: usize| {
reader
.next()
.unwrap()
.chars()
.filter_map(|c| Pod::try_from(c).ok())
.zip(&mut state.rooms)
.for_each(|(pod, room)| room[idx] = Some(pod))
};
helper(0);
helper(1);
state
}
pub fn part1(input: &mut dyn Read) -> String {
let state = read_input(input);
state.solve().to_string()
}
pub fn part2(input: &mut dyn Read) -> String {
let state2 = read_input(input);
let state4 = State {
hallway: Default::default(),
rooms: [
[
state2.rooms[0][0],
Some(Pod::D),
Some(Pod::D),
state2.rooms[0][1],
],
[
state2.rooms[1][0],
Some(Pod::C),
Some(Pod::B),
state2.rooms[1][1],
],
[
state2.rooms[2][0],
Some(Pod::B),
Some(Pod::A),
state2.rooms[2][1],
],
[
state2.rooms[3][0],
Some(Pod::A),
Some(Pod::C),
state2.rooms[3][1],
],
],
};
state4.solve().to_string()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_implementation;
const SAMPLE: &[u8] = include_bytes!("samples/23.txt");
#[test]
fn test_is_done() {
let state = State {
hallway: Default::default(),
rooms: [
[Some(Pod::A); 2],
[Some(Pod::B); 2],
[Some(Pod::C); 2],
[Some(Pod::D); 2],
],
};
assert!(state.is_done());
}
#[test]
fn sample_part1() {
test_implementation(part1, SAMPLE, 12521);
}
#[test]
fn sample_part2() {
test_implementation(part2, SAMPLE, 44169);
}
}

View File

@@ -1,9 +1,159 @@
//! Very input-specific reverse-engineered solution
//!
//! # General implementation
//!
//! The code in the examples is a series of 14 times this:
//!
//! ```txt
//! inp w -> read digit
//! mul x 0
//! add x z
//! mod x 26 -> x = z % 26
//! div z $A -> pop Z (see below)
//! add x $B
//! eql x w -> x = ((z + $B) == w)
//! eql x 0 -> x = ((z + $B) != w)
//! mul y 0
//! add y 25
//! mul y x
//! add y 1 -> if x { 26 } else { 1 }
//! mul z y -> if x { z *= 26 } (push z, see below)
//! mul y 0
//! add y w
//! add y $C -> y = w + $C
//! mul y x
//! add z y -> if x { z += w + $C }
//! ```
//!
//! `$A` is either `1` or `26` which we can translate to a bool `$A == 26` for convenience. This
//! simplifies to the following rust.
//!
//! ```
//! fn validate<const A: bool, const B: i32, const C: i32>(mut z: i32, digit: i32) -> i32 {
//! let x = (z % 26 + B) != digit;
//! if A {
//! z /= 26;
//! }
//!
//! if x {
//! z = 26 * z + digit + C;
//! }
//!
//! z
//! }
//! ```
//!
//! In human terms, `z` is used to hold a base 26 number. When `$A` is `true`, we pop off the least
//! significant digit by dividing by 26. Then, depending on whether `(z + $B) % 26` is equal to our
//! digit, we push `digit + $C`. Ideally, we should pop as often as we push in order to arrive at `z
//! == 0` in the end. The input contains 7 pops, so we want each of those to not push.
//!
//! To solve this problem, we use a backtracking memoizing algorithm, where we cancel every sequence
//! that fails to pop at some point. A pop is failed whenever we execute a validation pop where we
//! can pop if `x` happened to be set to `0` at the time of the check. We can memoize this over the
//! running value of `z`.
//!
//! This implementation probably doesn't work on other people's input; to fix it, you'll want to
//! update the `parse_step` function. Good luck with that.
use std::collections::HashMap;
use std::io::Read;
pub fn part1(_input: &mut dyn Read) -> String {
todo!()
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::separated_list1;
use nom::sequence::delimited;
use nom::sequence::preceded;
use nom::sequence::tuple;
use nom::IResult;
use crate::common::read_input;
type Cache = HashMap<(usize, i32), Option<i64>>;
#[derive(Debug)]
struct Step(bool, i32, i32);
impl Step {
fn evaluate(&self, digit: i32, z: i32) -> Option<i32> {
if self.0 {
(z % 26 + self.1 == digit).then(|| z / 26)
} else {
Some(z * 26 + digit + self.2)
}
}
}
pub fn part2(_input: &mut dyn Read) -> String {
todo!()
fn parse_step(input: &[u8]) -> IResult<&[u8], Step> {
use nom::character::complete::i32;
let parse_pop = preceded(
tag("inp w\nmul x 0\nadd x z\nmod x 26\ndiv z "),
alt((map(tag("1"), |_| false), map(tag("26"), |_| true))),
);
let parse_a = preceded(tag("\nadd x "), i32);
let parse_b = delimited(
tag("\neql x w\neql x 0\nmul y 0\nadd y 25\nmul y x\nadd y 1\nmul z y\nmul y 0\nadd y w\nadd y "),
i32,
tag("\nmul y x\nadd z y"),
);
map(tuple((parse_pop, parse_a, parse_b)), |(pop, a, b)| {
Step(pop, a, b)
})(input)
}
fn parse_input(input: &[u8]) -> IResult<&[u8], Vec<Step>> {
separated_list1(newline, parse_step)(input)
}
fn optimize(
current: usize,
steps: &[Step],
digits: &[i32],
z: i32,
cache: &mut Cache,
) -> Option<i64> {
if current >= steps.len() {
return (z == 0).then(|| 0);
}
if let Some(&memoized) = cache.get(&(current, z)) {
return memoized;
}
let result = digits.iter().find_map(|&digit| {
let z = steps[current].evaluate(digit, z)?;
let result = optimize(current + 1, steps, digits, z, cache)?;
Some(result + digit as i64 * 10i64.pow(13 - current as u32))
});
cache.insert((current, z), result);
result
}
fn parts_common(input: &mut dyn Read, digits: &[i32]) -> String {
let steps = read_input(input, parse_input);
let mut cache = Cache::new();
optimize(0, &steps, digits, 0, &mut cache)
.unwrap()
.to_string()
}
pub fn part1(input: &mut dyn Read) -> String {
let digits = [9, 8, 7, 6, 5, 4, 3, 2, 1];
parts_common(input, &digits)
}
pub fn part2(input: &mut dyn Read) -> String {
let digits = [1, 2, 3, 4, 5, 6, 7, 8, 9];
parts_common(input, &digits)
}

View File

@@ -92,7 +92,7 @@ pub fn get_implementation(day: usize, part2: bool) -> Solution {
#[cfg(test)]
fn test_implementation(solution: Solution, data: &[u8], answer: impl ToString) {
let result = solution(&mut &data[..]);
let result = solution(&mut &*data);
assert_eq!(answer.to_string(), result);
}

5
2021/src/samples/23.txt Normal file
View File

@@ -0,0 +1,5 @@
#############
#...........#
###B#C#B#D###
#A#D#C#A#
#########

27
2022/Cargo.toml Normal file
View File

@@ -0,0 +1,27 @@
[package]
name = "aoc_2022"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.66"
clap = { version = "4.0.19", features = ["derive"] }
itertools = "0.10.5"
nom = "7.1.1"
[dev-dependencies]
criterion = "0.4.0"
[profile.release]
# Keep debug information in release for better flamegraphs
debug = true
[profile.bench]
# And same for benchmarking
debug = true
[[bench]]
name = "days"
harness = false

20
2022/README.md Normal file
View File

@@ -0,0 +1,20 @@
# Advent of Code 2022
Another year and another Advent of Code in Rust. Because last year went so well, this time we'll be
aiming for a total time of under 250ms.
```console
$ target/release/aoc_2022 --help
Advent of Code 2022 runner
Usage: aoc_2022 [OPTIONS] <DAY>
Arguments:
<DAY> Which day to run
Options:
-t, --time Print time taken
-2, --part2 Run part 2 instead of part 1
-i, --input <INPUT> Read input from the given file instead of stdin
-h, --help Print help information
```

46
2022/benches/days.rs Normal file
View File

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

0
2022/inputs/.gitkeep Normal file
View File

2259
2022/inputs/01.txt Normal file

File diff suppressed because it is too large Load Diff

2500
2022/inputs/02.txt Normal file

File diff suppressed because it is too large Load Diff

300
2022/inputs/03.txt Normal file
View File

@@ -0,0 +1,300 @@
NJvhJcQWTJWTNTFFMTqqGqfTmB
VwVzPldRZVLVRmfsvfjvqfmm
ZDPDHZHVcvDhbvnv
FHHwHBzzVCWWmmCzCPrVmgBwbLTtRFFbbbttRGRLjTcLpbbT
vhZZvdsNSdSMdNvjncppCLcLnGnj
CDZZsNZMZqdNSdlNZCqrzPHDzgrgzwVVWwmwwm
ndlndntsFJntFvccLjjLrjBShcBBfc
GpCGHzVwmmzqQWSSSfWHBhQL
mpCMGGCZVzVwGGVwmJsZnFtZnTSTJtdsvl
nCnPDGmDNmVCsVQDmGSWqvzchWSjjcWGqS
gTnBRLpfTRnrTdZgdLfRdrThvqcvWWhFFWvcFSSgjqqzjv
pfZfTMwrbLTTfsbmQtlVtHHnbs
wNdSdsbTvTZMTvTv
rrdRWdWQhFVdHWBGWQmmmnnMvCfmnhvmCmtZ
rJrVDRWpGddpbSlNSlspPP
chTNrthMMwWMTjfsmRzZszJpwm
BLnFFCngbcBnbbldDlpRjGpmsCzGsGsRGmmG
dqvnvlgbqtcPPMhH
QcLNqZbCzJDQBJJRpwzRpdnRldgnpf
GmmmvVGsHrWffrlwdCWd
CMsFVVFjCmFStGQbbLZNBbJBcTjc
LQVggbQvcLbQLHgvVLhWGGsChssrMWfzGccc
qDnRTTRqJttPfWMChJhGslWlzh
qRTRwPBTBtRZdnjnqqqnQVbjbNLFbbfLgVmgHLQm
cZbzwCwZPlJcMLrNSNfHWNBBNZ
vsQsDCqtsDhmtjVrBNWNjBHrhr
TtDTGnvTlgbbRCGg
BgBlplHlsgNNsJlVpBtPwJhMPRRQSSttRtSP
bvhTnmdFTzddStwStQRddt
ZnZDLvnvqZzbbhFzzmTbnFsVjVlNgsCCNVsVLpNWVgsB
TdptqrrcVGhhzFtw
DRnSfwJlDmmDDVGv
RCSQNSCQZndwbcMqQrBB
wvRlrlwVwwqzgbZRdCJBWfmdzCWfBdhf
cFcsQpNtLLsGTtNGpMdPmDdPBmmBvJPWvDtC
TpjssTFFvLLLcFFQpwbwwHngjHRrZRqZVH
mqqddrPPcPmqPDlrQnjTrbvMvbHzzsjjpTvz
gtBWgGgVhLGWHzMDztzstDHj
hfWRhBBNBGgLNQDPwdNPcPdw
LhQzdhhbTzpMhddhhhTzhnZcBFllHZFtrrHZHMHFjlHr
mwwssqDvjptrvplr
NCSgVDPDwmDgVJVpLfTznQJdhfLhnhQQ
GzjzDhjhhZzcrRgQCBjBPBBjQCgT
vHHHmntsbSgLwbsSmNHbwNbvpqPCBVppCpFTpTPTBtqWBCqV
NJbwNSwdndvmvwhGhgzcfMcDJfgJ
GncgDvvcMGnttjDvrgRRFSZZLZFWdJFJwGQwZBWZ
bPqpChPfsshfZZBdZdLTFZ
lNqqsClmbsNlPbHqPsmblmsrHdvdMngcVrjggvrvggRDcn
bDvtgVVVpMQvjQWmQL
rwTflmlfZJBBdQWQWjQqdM
HsJJmZZwscHrwTrcRbzpcbPgtCSbgz
CsCsRvshMjpbqCqf
ncblgDBgtDmmmTlBgwlgbHHqMFHLqPDMHPHHpqWfFM
TcBctSmTZTtSTzsZvsvJZRsGVb
znznvngttwltzlLwhtThHbqHPvNbNHSSHmmNWHjP
FBcLrRMFQpPqpPSpqHHW
fRQMJZJfrcMcMVrQJJftnwCzVCltgTnstTVnVL
MfLlRfCMrLzRlQgwNqQFcsGd
jtTjjBTvbdqcGjqFcj
vvShDSBDppzhCmzq
plWMptTvfrnncvcRfwqzqLGhzhzThNzNNJqD
jSdSHFPQQbdPCQCssjSbBmhJGNZZNGNqqJNBlJqqLh
VCCCVCQgjdddjCgljCjbbwgRRttgrpftfWrgvpwpnf
MWlbBcPjjvvjPWWMPqgRQZfJZDGGbRZJffQQwh
HrHrnncHpzrJQJfVDQVR
zzsSTtSTLzsspSdtTmHHmpmtFgqcgPlgFqWBqqqBMdWWvFlg
nSqBbJbqlnBBClVZcMgZVgcP
FQwrwHrRwWWFBRPNgNgcCGZZZC
rWFWFTwpwwWzHrnDbfJDLDbBBbbz
BMmNtLMMtFCNFNMvvLmcndpgcdgppPrgrGPPrgJD
WVWWhbTtVnGpjrrPhr
HWssSTHWfRHRsQQFLvfvFFCLCNMNlt
sTmDsQffVrrLCjTFltTFWL
BnwwQBJbJndMMRzMwCLlWlLWWCWLLtRlWF
cqqBMcMqwnznMGzcvDmQhrvssHmPDVssrP
pQGQGJDDrDVJbbfVzvvgPcCZwhZhncscZWWc
SqMMlBBljMmRlchhPTqThCZnPs
FMjMBmjRNFHQJJpHVhVDhG
tHNNdBdNtBBBMgsMpsZm
wVPzVvbwqzhrVqvjqzzsZpDsZDsZmsCPCgZgCM
bVbvLThvvbrWqHmmnJLdHdJQLn
PzTspPZpdLLDZTplPLpPDpvbfhnqNvqzfvNMzQQfNwnQ
GWRHmjmFWMMSnhbhHw
JWWcmtBrBtWBFWGJpsgTgldhLVLpJl
DwLMDzLMhvMcwvgdVqWWlCVgvlqF
TTSBBRpbStHZVgjWFldjRVlV
SnbTBdJBmnpQzMPDMcMznr
nNlMNBPPNtJQnbZhZsgSbh
czzCjcwTdvSbgQNcgNQq
VTdNdGDTzDTdlFFPtBrtLtDr
FMbbfMlzvFsmgVZmmg
SrNTHGmdSQDqLhtQhhgggs
dRDTSDPPcHRdHGDHlwJBbmwljmMcfjbW
sQgWLtqLtWhdqlpNZRpG
blTHTjlvTCJnJvRZdGGhHHGZhFGV
CCDlJclnCmbrmBMgcwcLWtcBsB
vqPWWvqwwCFvFZfZPRFRrcGQrQwsDrNcrwnbDNcQ
LVgJLSBBVtzTLzBMmTMJmLnnDNQcrsGbsQbNbrbDjs
zggVSmmhVdfqFhvHWG
WwdndGGmmmLwwwmRwWSncLRnZqZqhqZthBtqtBqZBgtdtvMH
FfHHzlQQDsFzzrNsVTfttZvTvttTqqtbqb
lQjFDNQFPjCsVCCDjGCwwSGGnccwcHppGp
mrjggcFsFMjdjZRpSZpn
NCqfLCFNbQPzPPlPzNfSRTRZdSdWWwndpqRSSd
vDvzzbPQFNCFtllLLNMBhMcDHGBGMggMmcBc
jhjlBvvnjbtDNPjtSjBDBbDNgHggrQrhghRQrqRrZcRwwqVg
pLdTMsWdLLmpMdqZZdPdVqZgHPwH
WLTCGmMLfPSlbGjlnnJD
gtbwhgHbHgqqbgQthgQLtZZCRjMcjjnRnrRNJmMRJrNhRc
bGWVTTvDvfpVFFBpvvVTdRDMJcrccCrJnMRnNnNCcc
FVWTBsdvdTzTBFWssVQtLgSQtHqqPzPbqHbw
dlzrPTSSjSrllzWhsvVmVtTRTWtf
bJMpLGcqGhNbJQttVQmmvRWWsp
qLbMwqqbGHFGzrlZrjhPHCrj
rNrrffVlqqrfLlPpltcBBTTGRzzZRPRsBTcJ
msbsmWSsMmQwjdMbWMhMhQmcRZRzGjTBGTBcBJBjCHJGcC
FwWbvdhbmrsFrfrgsN
rHjrQHdhdQrvSddcHWLssBSVVpBSWWWWWf
JNfTGtqDwVWBMBMpwM
qlltZgfJFvcRgcRjvc
CqfcwfDqwwmRnnqmRdNRBTRTRrdGdNpTvF
WVbzsZszBbrsvpdMpdQM
tJhbVZHWLLHDgnSwnSSgHB
TZCqqlTsqpZVVsZQJSBSLpLmppnJzmFz
brSgNtGjjRjRRjDddDtrRJcJJbJmmwcmBmnPcJFwFB
jgdRtMjNNjfqlMvShvSZSZ
dJTdqCwMNCgqTQllGBdlGBmmmZ
fcVfVcnbVfrwDLWVfncZBQPlBHRGljLZQjHGQl
brwnnfSFDvfzCTqFzgMJTh
njnsPBjjsrrnGLnbTTjGvcldQPCMllNzMvRQPCdd
ggZgfZtmZVpqZqZWDgFmgqfCcQRcRcWhQcccQddMcvRQdQ
tfqgggVgHpDwDtfwbGLJRjbLjsrLTj
JmrfrmTlDWTfgQCdHCdpqBvQdD
jsZtVzNsSNVQQHnBlVQR
PljljFjPljSsLPtFLTTgTcFrrfMJmrrmrr
hmGcmmndhmGnfmtGnDzFLwrFJQsQFzNFrNJG
ZSqPlSWcWlbgqWVTVWRVZPrjQqjzjFNJzLsNJsLJNqNL
RHcWTZbSMMMPgZcWgSWPPbVMDnBffmtdpDBddfnnvmCdfC
vSJvsbFfJfvqCsTHJswssJnLTZjjhzrrzLrzLMrzhdjM
pBNQDPcpmWDcBNgMMnZPVjdddnndhH
QWlDgmpmgDBlGRgDDgffSqwSwGCwHfvqwSFJ
jvlgvMJclPdGdtdcjMVmMHbFHFVHWHbZHZ
CwhLzLhzQpnqfpfqDVHCHbsbDFZDmHmj
LnBzfQjSzQrPvJvdSSrr
wpcvcsqclDCnVCVvWfnZ
BLRMRtbnbbBLNCjNCjVVZhbC
rFgMPSRnrRpmqpJwqFDs
LZQNQbMrZppLNLQplvlGLNvVmmmfjbwVCfjbwJwCmBCwfj
ShTPRFtTHZPCsnwswsFwCF
WtHRPdThSqZTRtDqtdRWTdpGDLLzrNczvzMGLlQLGDDM
hdcffBvldjhCMljqPwWwWNwWdwqHZr
LtQmbQRVsZQZMZPQSN
tmMRsJMpDhjJzJhv
wNQCMFCDQDBmrHmmRWrrHN
SShLnfqpcqpSZSfrzJvRVrvfrrJH
cRpqdGclpScltTQQtsFQMQsTCT
NCjggZmgfBgnBmgWbcwcTFctcWWfvb
HsDGthRGrtppSQpbFFJTVcJdFbTRvd
rPDGhDDrSzZLtzBLZMCB
RsBBMBsCBlFFCgRsBJzlMjMPNSdPhSrSrzLbmSDrDNmDSd
pZHZZJpGHHHpTTHvTncZqVLdqLbhLrDLdhrSLLbLDDdD
tGtwnJccvCtCffMBgt
wbddvVjfwPhbjjbDbbvbjvTNCNmfHZfpCZRJNzCmJmnJNC
BslcLtclZWsZJWNrRRNRpRmR
BSLBlScGtFMcssMBBFGLlQZTDZQjPddVwwbTdvvdhTZb
NSZHzmLZBnzHmLLzLSntDttDDtddhDtttDWW
QgfjsrrvNNJwtMddcvcvtq
jrfgfQpQrTTVLSNBClFV
GQWcWWPPQRcrJQNDdRcDmmLCFSnqNSmqhCNvFnql
zHfwjzpMjwZmCLqvvnlljC
ZgtVZBtHHZtgQGgPrbPRJdPv
TWdWpJTJTdgLWfWLlLFLrfrgBGsNqhGslBGHqSNqqBNshnws
ZpQmjzbZZCjZCCCPZtttRCCwsBnHNssBHbShsshHqsGBqN
RDRRPpPCzmZCtRpVVJFrfTfWFLLJggJrDv
pDDFlglsvFMgntlTMMqNffmTdfddRM
jhGJLVCHQpHGQCCzLjWdTTdZZdNdcRWNccWfNN
jQjSGjrjCQLhzVSLSCSHGDpngbrnDFtFBwBglBnBvg
wsLzstsgszcpcGLHGpcgcghlDBvQvjQvbFbQCbJBtCCJJv
mnSqRSSqSRThWRnmWWRSJDFTFCFCblbBCFQFCjFj
rZRRWqSSdZZfMVnZLspPsMgHpzMhHGPg
mwHrCLSWWwrsHCHDDsVrsmhfFZFnSSBlFlgZbbgBglbggj
GJdpcRtGJvNRdcPtdpJJdbQZfjfQBlnQBjnBtbfFnB
qcPpqqzFzJqvPVCCmWrVwhrWrz
jjMbvbhDvnRjNRGMmjbMZftSSwwwthJSffStctcwqd
lTQrVlpCVvCcfdcSJqLVcw
srHFWCHrFlrHlrsBsprljjRmDZZnmbDngNBgbNZv
MgTlQJlTQJZWpgLrRssrVqqqpRts
bBNbbzSSjMBPjzhMjsPtRVVRVPRqLttGGs
SjHBbfjNCDfjZgTlZdMJnDJW
lpThgTwtplhghgwhThqnnrdZctSZSjSZcRSRfbdrrc
RBVBGvmBmfdrcvrbbr
PmVGNGmmGRLLQwwLqTnglQ
nHwnBwBTnFHQwRsMhwghmzcm
GtprdCpdtqWdbqbrfdnPPszsWmRzRnShPszS
dGptbCfCrlnVDBJNLDLLVDLQ
CZtCjhTndCzqbCNq
dwpGvpsmwGslDszrNNrzqDMzWMgJ
vmcGccvpBVPTVTjTdTTTdZ
jWZhvZLjZfCZDwrDrSSzJGhVdJccscGsgV
blMBlRqqqgSJLBLcsJ
blmHLmFMMMnRqLmMMFqHmfPDfjQDnCDDQrZvfCjvDr
rnvnHrDLFZmMFLvrHQBMGQggBztzglplRl
sbWWhdNzsshsfhcsjJJPPbWdtQGVGllRTRjRRgBgQlpRlppB
PPCCwNWhPhNfWCzbqmFnDFFnCDLSrvZS
GChNjwWlWJWTJZBggvdgnQgdhdnd
HPsHfHHrpHDpFFrcSfsfpCMmQdntLBMgtmtBgDdLLC
SqpPscpPzpSWzjlCjjCGjl
nvgLvcLgvgvngbLprpJNTDCCRNVJrNPlDDTV
WZsMtsffGQtMzWFqFmWmWsVNJNlDwwCDVRTwJlCCDVLz
BQfGZGmmsMWFstWFmfMsfBccdncbpbSbvbbvHnLbpc
tsmDsvswNZmcZTccfh
zCTpGCbWBRWFWHGRFZJbMbJfnrhnhfMnnZ
TzFGFBRLdpHHNNQddDQDvwQN
fhBBpJgdHddjZQfmVmNzNNLmFN
qvMRrvlbwqlbTTMBMvLssFNmVzzwFDmLLzVD
TRSRWqRRMcBHhGHcdGgPGp
lSjHmtmnpHStblnpSlHSrtmMzLWzqzqCZDDTzTTWqMFqCqVV
sLRLLfPPRQfCTqqVVqFT
dNJgRPNQNsJJhBRvdJvQvNNsjSrrSmrcctpbpHtBrBjLjmSH
nwFwpppjfwSlpLTsqsTgNshhjM
ccBRGvtsmgGNPqNNGP
BCcJHvssdcWBCVmVHSSrZrwVzblpwbzZnf
rcfQRrBPPczjcRBctZDNlnVNHbgZGjVDjN
TvMsFJGSFMhJnNZlwVVnDNTZ
qhSqqmqLCLhFdJLqSvLhmQRQRWcRPczPtzrCrWGRBp
JVhdPhsFPFqLDBHVdHLPvhHDCMwcgJJwbwRgnnCMbwGwcmGC
fzjzpTZTQQQLwCbgGgbMmQcR
jzNpTzfSZtfNSWZlVVtdFFFDHHqLHVqv
TwSNnSnSGVTpNppGlPTlTcVqQrRhVBqdqBRqZqQZqQ
DcDCMfDbCMHJdrRBqbdjRBRZ
gvftMCJHcHfCDmDLgfMmMmmWlwWnWsTTwlGTlWTwppNlGL
pbGMbllDQPhhWWQDpPgVGlMCvRRrQLcCCcfBBQzLBcvQBv
wqnJjSmjrstdqwwFBLcRsBRRszzLFC
qwdddTJTdHtjndqJqHZHmwVWGpDbGTlbWWpWWrPGhhhM
WGllqLjjLCpSffmBmvfpHs
dnrQwZzRTdZwnCThdzzFTVmcBHBJBmsHfBPHcfvcSVHs
QgQrzCdrTRCZzrZLbjGLqNMWGgNNLt
sgPnhPPTTPTTwlJfwNHlqcfs
LMCpFbLLbRpMGbMcCFLVlNlNqrHqVfbHHwNDwr
GjBcCCtWMtMRZTSvgWQTngvg
BCMtJJMpRDlMMvBJBBnfjtcjPhPmZgnhgdcf
NrsrsqFNvrVLVGVrsHsqFgfmcPGdcmhfjdPgfjcnZd
zFTzsNqHqFssLVLQqNTFbsBDwCCwvWlDwRMRCTRBDMDS
zQtLgvggSRtgvVRtLvvnzdnjnGwGdmmrlpnlGz
JssBFpqsDqPNnlWWjrrjqrnj
DHDFBNDfPbJBsFHNMPvpvStQvMRVTtgVTVtv
FvzttFvBTJJzLbvwhCnnVnWwjCnBNC
mQdZgZPDPdPPSsMSQPdZgCwVGmnwnWpGnGhqNWjWCG
ggdDgfQSdcjtFHjlLJfF
ghcgScNNSsCvGSzmpVFlZbrzcFcV
MWWRLRqqqdQwTtLjjmqMlFpFlzVnbFVDwplFzlDr
LHMHqdHWjdQMdMtLHHLtWjJRsGCGSNghmSvPBJBNhsGfvfGP
CbVqqqDbcbMHnnDqcCbrRFCfBvvwGjzrBwQGzrwwBjGwBQ
sTPmpNWdWPTJssSSLPfNljjBvflGtjwwBzMG
mmWgmgSZLTLMZWpnhqZbhFFCnhqnnn
QQmjmZqnmQrfTZlbbcVbBcfbHfzf
vpdSNShNppFdSRtdGBqvJBDlDzqbPPHVBH
tRNSNRFhNpSRhFRMFtGhRGswLZZsZqWnmrmZwqwsTZmmmQ
gGWCllFCGWtGGWdlGlWNZdwpnnSbwpMvpphZpndn
RsshDDLcQVMSJQwJwnvw
HVPzrPcDNhPFGhPC
jtHQGHjGGtdTLjnqTQlmvRPRPBBwRBnFPPWP
hZbzNzVrczZzcbNssVspZZVvBwbmPmJPWmvbBRvPlmvRJF
fzNVDsZMhzpVhpVhlZcMNfcDDdQTLTjGDTCqGCjtSQHdHL
GrbFggGrTrzSrgfwJjdTmwmNJZJd
VMPQplPDptchwdsjmlml
MqMWtBDPPWDWHQtvqQtWPjbzCGLgSBgGbzgrzFgnnz
fcJccCcwcDfcpbRnCfWJnQJqtqtqPQdsGdgPsgTQqg
LSjVMhzSFFrljdNbltNGtgdqQq
MMhSHFFMLzBWDcHHcfcHwb
rwmWtJWMwSNRJMtwNmMrrSsmtTjjlgqnTqZZZPlHnTngTTgn
BGqGqqFBFggjjdGHlj
QDhhLbDQCDFMNcmhRhqJNW
BnRnRvMnLGLSCHvvSnlRfWbbTNQJsJsbNbJTBfQT
tzMmmMwjhcpFjDmMcptrcjzFQggfQPTsWsfgNbbgfhJbPhQT
FdzcrtDwDMtcwtFGRZdRLvdnHRSZZv
HVpsSpvjpNjsBmbGFBnMNnDM
WRRWhZtfrVtLJrBZMnDmDbnZBTGF
thhPLzWzhzwPtLRLWrQlpPvvClcVcCppSvpl
lZPbhnZLRPnnPZZPdlGMBWcBMgMQHBBcvvvzBL
jpFjmwwwCDDbsjvjjgcvQgcNBQ
rbFmppbwhqhGRGZr
ggrLwFgWCBwbMWBbFwLMgNBZdmZHclJPllnJlNRPmSNZRR
ppszzDfhDfhsqpnvDVTfGpSPlPmclHcdRcZmmmdPPGSP
pvtDDVDVpqDfzDfngBLCwQrgCtCwFwrg
pbGjFFGGDjpbsGsmNhNFNRBBBtRhhhHv
JnczJVCvwWJvhPgghgNtNtNJ
nwVSSzdzzqSpvQSZQG
mssLLttQrsMrMzLCRmMmrrSQpvWpDNlBTBDlvNTccDQl
HdHJwJqVPwHnqJwbjJbGjnSgSTWPpNgWWpgBBgcvDWWN
ZHVwVZGwwdndqJVJqfHbGwnwrRLtLMftMvMMRrhmLMthhLmz
RgHGLbTqlZlPRZPHfvvfZttJnvfvjnzr
sVcChDVDccwNhhvjTvVzWJjnzFff
mpNcCMTCGmLqBLGH
wVJwHJHVMtMpBmDDWPQVPWDGDD
zCrlZzCblBvnCDWNGLmvGDLPNG
dqZglgbzrzbbgZqzTFSBHHFJSSSfjjSMfwhj
NMWJSjLMCnHHNMNNHWCHMbVVGBPZTrPVPBVDrBSDGTTr
zvttlFpgdtldwwvftPDPTWQdBZrsrWrGBZ
hFlFmhRFvfCbmWJWHcnj

1000
2022/inputs/04.txt Normal file

File diff suppressed because it is too large Load Diff

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

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

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

@@ -0,0 +1 @@
grvrnvrnnjljbjqjpqjjvhhzwwrbwwbblrltrrpbbbbqnnqbbbbsvbvmbvmbbrsrqrzrllwbbbqzqrqnqrnrjnnjccdggwqqhrrjcjmjmllgrlglhlclmlvlvsshwwsggmfmdfddgdfftrrczrcczhzppgdgrdggghmmdwwqgggslglfgfcgccmjcjwjrwjrjcrjjsgjjvddpwpgpbbgwbgwwhnhfftbffhpfphhfqfrqfrfnfpprvrsrhrfrllfhhrsrhssvfsvsnvsnsswtwtlthllrjjwddtggzczgcchwcwppfbbdvdrdzrdrvrwwsbsfbssqfsfjsjcscttlztllgjjlbbdsdtssvvvwlvlqqnhqqtdqtddjcdcjjpbphhgtgtqtzqqzhqqtgtvtmvtvrvqrvvfmfmppzzbwwnddzttfpfrrlddbppfqppnwnswwdhwdwjjqljqqthtnhnddgmgcmgcmgcmmfmfttrzzfdzztllmjlllgcgbbcqcvccpnndbdjbjmmzbztzptzpprpddptpprhhvlvmlmpmmljjnnjsjfjjvgjjvzzfgfzfbftbftttgstgstgtpggflfcfqqtctltgltldlzdlzzmmlddnvddzfddppmnpptzptpvttwstwswvwrvvbfbjjjbmjjdvdvrvdddrwrhrzrqqhghhrwhwhrrmppsgpsgszzdfdfwwmtwtvwvgvffmqqqtqntqnnjcncbnbwnnzggrdrqqjbqjjwjqqqwlqwlwzlljhhfsfsqsrqqhwqqwbbqbvvlflrrlglbbjhhjmhjjcmcjcgczcfcgcqqczcnnvjnnlddmpmcppgvgjgddvrrnsnmnqmqgmmnppwgwcgwgssbddgtdgdgmdgmgvvmjmvmjmvvsfssdgdghdggbfbqbdbjbsbmmrpmrprggbllwrwpwtppzvppzsssdnsdnnvnhvvvzvfzfqqnnmlnltldtdvdbdblddsmmlccmlmvlmvmmcsctctrtsrstsbsrshsddlmddmppgsscttnrtrqqcvcwwlnlznnnvcnvvtnvnbnmbmvmppjgjdjtddmpdmdvvmgvvdqdlqlhhzccsggjdjsdsttctjctjtfjttppdzpzzbjbwwmwbblslzslzszlzrrcbrrfggvcczjjtbbdnnggbwblwlbwlwqqfvfqfddrrfccvlllhmhhhrthrthrrnbnzbbpzplphprrrnbbghhnshnhbblqqqvwwffnmnmhhtccpqpvqvbvnvvfnfsnffdjdllwffcddgcgrgjrggchcpcddtbbdtdmtdmmhhtphtpppclcpcvcjvcjjfqfzqqphpnhnrnhhpdhhtfhhbbmqmfmsmvssgqqfssqgglnnqmnmbnmbbllrdrgdrdvrdvdsvvnddgtgddcdqdsqdqbqqlhhwdhdgdcgcdchchrchhpvvpgvgrrfggwfwgmpddbhfngtrwswfszgsggnpsntjpslrpjqsffzrlnbnzdtqpqtjzwlhhgrsrbvnccnsjmzcbqgcbtbqlzhnpnhhrrvqwjwzzvrlcrmjhcscrqhpqmfzbnvcwwqhcjjlnggmpbwztzfswmsbjshnsgfmdlzvzczhrdwgwbghszpnbfpctrshbfhspsczcqcrrqcpwwpfzhjqtpqgjbztrpzrlgfdjbmlwdvlvnfmdzbwsbbhlbszvwcpztlchjrqbmsftltmqpfgdpmdgjvwqqtjsqlfqrwmsnlqgsbqfwsdnfvzthmbplvszfcmlptlcjpnfpjsphsmmjplwjqphgvzbtbjtpttqhlwtgnrjvmvsfsztmsqszzlhqqhfslsvhzgtsssfctzgsqbgdzlpwbsmpcnjqshhhcwqdsdzdhnjfqzqnqdlrpddcgrgldgqbjmdtwgppdczzrjvmcfqjbpjzbtjmgdphlbwnsnpfdqlhwvvmpwzsrztnwvtlbphljmjwsgbphgmwhdmfhpvsmvsjccjhfvqtvfmmlnggncltvtrgmbtfqsvfnlvcmjnjwzcrpjnsgntvhjbtdlptshbhhchqmsprhqzdnfpjqccdfvnzjtlbsmmwvzlwlvmsbrnhqctvtvbfhntdctjnrbcrrlmsnwbbjbcbbgrrhfqwzwwfgvsvgbwnttghtgpspzwzfhffsqjvwwttntnvlwftsfvtttgnprzrzsghvjrdtsfdvzswhmrfcdqsgvrlhzbnvbmjlqrftnnbtwqtvlvwznfbslhdqjbntdgpprfqchjvgvzjssdztjlzwfljjmfvzrbbtczggzqwrnqqgzzcbqjcpfqfrbwtdjrrvbszsjdjcpdfjscsvnltcgwvqsgnhbfgnfnddnpmbzbptrmvqzpvbdpfdvtlmgnnjwflgdbfnmvsdnmlvgcpwflwvdbtbfwtfpsmqsplnzwlwgvbjrhghwrnrswsggbqpdjcjrgbgnsqdvwzzwftvjqgjzzcdvpbbjzpphmbcqmrjvgqwfgrsnqvhwflmhgrlvbpwdcsrlqwfrwppqbrdhwqtvczpclpsbsjcptgblbbsqmbhjjgzwvlcnhnzcttmpjsgchmppgphqlzlcsqcgbbjgtjjvmttdztfdptzgvmpnqrcmpmcdlpnbztllvqbggqbqhlqvdwsrwzsjwfrqvcbvsgfdptmrzpvdfblmhlzrvpmsljlqqzrhlnmwncpfhvqlsbtrjbfcrnfvjvddrhdbbczjdsrdvzlbqrccssdzcpmdsqbprjppfzdwfdswptgzcmjqfhcwsqfqhvrslffqfbcvhdzljzrmtwmfdwzdhhjcmbjtvjhzzwfqhrcslztdbnlwmmhbbbgdscjcdzftnchqfnflnsdqjscfrqpnfbftpzvtmrwncqfqqflschpfnjsjlqcjdjgtwpqhgcnjdmnnvmmpwdspmnrgqrptqwcvbtdwpqlbtwpqgwgfrzlrhtvrvzhmhmwhfdsrhpcczqfltsgtgrfwcvlcvtlhqqwnrqgzpnzbfmzbdwqwbsfvbshrgzqdbgvrhzhzlbqsfzttmsnmrqmwgtzbvdqdrbgcpclzjrhdbjtpcdbbznjgtbwbqrnpvffdmwtrbhhstcmnjcwbbnmpbvmjprtzgcptmtrffwhvfgdljnrbbrblbfbgdwtjrtgqgrpvpgjqrjzczvvlspgdbzftqgqvgdqlglbgvgjdcztznszcwfqhmwbrbjcfstzdcmdsssqfhtzpdgmzjscvbdzgbhhgdqgvfwrzmhdrhlsvlzjjzbzdljcbhncppwrtptjgszlqsrqpzqcsgvdvzmgvwgsncnbffttslphcstqvfwbwzbflmshcbnhpljgqwmmwwzlgpbcqnrtqlwcjcrclfdrnnmvtbfdztdfvtqrsgdptfcfpzpsldhzmrngggfvdqggtlfqqwsldprcffsstnnpmsbbvghdbpprqbssnprdbqclzqtgsrczwcvqwrrfmmfwsndvtvqljwwglrgbphdvvwgctbbmtrbpzqtspgrlhmnhjcdwhwvssgspzjbcfjttjqbdpdmptfzzjcfqljpqddfssmffqprvbptfvdshsdmfmdtmlbnmbmjjjsgmlmwmgcwhbrbgchrstptvdlqgddfzddlzhwjmsvvcjwvqtzjtsctfmzchlbrvlgdzbvdlbfpvhptpltrdmcgjghcpwvwqqnrzdtnmgdncplhdpsgpnbprbgshffwwsdhpgqsbmwdtpnhhltlcqfrjtswcchzvlhdgrmjwhgwppdjqlgmdhwbllqvzrchgclmqdlghjsvmwlflmhhmdzbfjhjnvwphnjbclmdpgflqgtfsmsjslntfcmtbphnrgpdcqtjzjttdtgjmvhzsrfnrjqssvwpcslpfstbpfsrsntmftmdgsqrrsnddqfmchrhtlhmqndvvllnvltdzfphjqnvmcdsgfpcmjftgdpntjzplqljhtthvnbzbzwvfnqsjvnfwhmtbsspjslgfjvdgfjpwrsgqwntntjcqtdgnhnsfwhhqfwbwhdrftj

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

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

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

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

118
2022/src/common.rs Normal file
View File

@@ -0,0 +1,118 @@
//! Common helper utilities to all days
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;
/// 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(|e| {
anyhow::anyhow!(
"Parser error {:?} to parse at {}",
e.code,
String::from_utf8_lossy(e.input)
)
})?;
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)
}
}

50
2022/src/day01.rs Normal file
View File

@@ -0,0 +1,50 @@
use std::ops::Add;
use anyhow::Result;
use nom::character::complete::newline;
use nom::multi::separated_list0;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::parse_input;
use crate::common::reduce_many1;
fn parse_elf(input: &[u8]) -> IResult<&[u8], i32> {
reduce_many1(terminated(nom::character::complete::i32, newline), Add::add)(input)
}
pub fn part1(input: &[u8]) -> Result<String> {
let elves = parse_input(input, parse_elf_list)?;
Ok(elves.into_iter().fold(0, Ord::max).to_string())
}
fn parse_elf_list(input: &[u8]) -> IResult<&[u8], Vec<i32>> {
separated_list0(newline, parse_elf)(input)
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut elves = parse_input(input, parse_elf_list)?;
let (first, third, _) = elves.select_nth_unstable_by(2, |a, b| Ord::cmp(b, a));
let result = first[1] + first[0] + *third;
Ok(result.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/01.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "24000");
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "45000");
}
}

125
2022/src/day02.rs Normal file
View File

@@ -0,0 +1,125 @@
use anyhow::Result;
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;
#[derive(Copy, Clone, Eq, PartialEq)]
enum Rps {
Rock,
Paper,
Scissors,
}
impl Rps {
/// Score we get by playing this move
fn score(self) -> u32 {
match self {
Rps::Rock => 1,
Rps::Paper => 2,
Rps::Scissors => 3,
}
}
/// Score we get from the result from playing given other
fn score_against(self, other: Self) -> u32 {
match (self, other) {
(a, b) if a == b => 3,
(Rps::Rock, Rps::Paper) | (Rps::Paper, Rps::Scissors) | (Rps::Scissors, Rps::Rock) => 0,
_ => 6,
}
}
/// Score if the result is according to the instruction
fn score_result(self) -> u32 {
match self {
Rps::Rock => 0, // Rock is lose
Rps::Paper => 3, // Paper is draw
Rps::Scissors => 6, // Scissors is win
}
}
/// Move we need to achieve the result indicated by self
fn needed(self, other: Self) -> Self {
match (self, other) {
(Rps::Paper, other) => other,
(Rps::Rock, Rps::Rock) => Rps::Scissors,
(Rps::Rock, Rps::Paper) => Rps::Rock,
(Rps::Rock, Rps::Scissors) => Rps::Paper,
(Rps::Scissors, Rps::Rock) => Rps::Paper,
(Rps::Scissors, Rps::Paper) => Rps::Scissors,
(Rps::Scissors, Rps::Scissors) => Rps::Rock,
}
}
}
impl TryFrom<u8> for Rps {
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
b'A' | b'X' => Ok(Rps::Rock),
b'B' | b'Y' => Ok(Rps::Paper),
b'C' | b'Z' => Ok(Rps::Scissors),
_ => Err(anyhow::anyhow!("Invalid RPS: {value}")),
}
}
}
fn parse_plan(input: &[u8]) -> IResult<&[u8], Vec<(Rps, Rps)>> {
fn parse_rps(input: &[u8]) -> IResult<&[u8], Rps> {
// Note: alpha1 also sort of works but is significantly slower
map_res(nom::bytes::complete::take(1usize), |v: &[u8]| {
Rps::try_from(v[0])
})(input)
}
fn parse_line(input: &[u8]) -> IResult<&[u8], (Rps, Rps)> {
separated_pair(parse_rps, nom::character::complete::char(' '), parse_rps)(input)
}
many0(terminated(parse_line, newline))(input)
}
pub fn part1(input: &[u8]) -> Result<String> {
let plan = parse_input(input, parse_plan)?;
let result: u32 = plan
.into_iter()
.map(|(them, us)| us.score() + us.score_against(them))
.sum();
Ok(result.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let plan = parse_input(input, parse_plan)?;
let result: u32 = plan
.into_iter()
.map(|(them, us)| us.score_result() + us.needed(them).score())
.sum();
Ok(result.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/02.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "15")
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "12")
}
}

79
2022/src/day03.rs Normal file
View File

@@ -0,0 +1,79 @@
use anyhow::Result;
use itertools::Itertools;
fn priority(item: u8) -> u32 {
match item {
b'a'..=b'z' => item - b'a' + 1,
b'A'..=b'Z' => item - b'A' + 27,
_ => 0,
}
.into()
}
fn seen(backpack: &[u8]) -> u64 {
let mut seen = 0;
for &b in backpack {
seen |= 1 << priority(b);
}
seen
}
pub fn part1(input: &[u8]) -> Result<String> {
let mut total = 0;
for line in input.split(|&b| b == b'\n') {
let (first, last) = line.split_at(line.len() / 2);
let seen = seen(first);
for &b in last {
let prio = priority(b);
if (seen & (1 << prio)) != 0 {
total += prio;
break;
}
}
}
Ok(total.to_string())
}
pub fn part2(input: &[u8]) -> Result<String> {
let mut total = 0;
for chunk in &input.split(|&b| b == b'\n').chunks(3) {
let mut mask = u64::MAX;
for backpack in chunk {
let seen = seen(backpack);
mask &= seen;
}
if mask != 0 {
debug_assert_eq!(1, mask.count_ones());
total += mask.trailing_zeros();
}
}
Ok(total.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(), "157")
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "70")
}
}

86
2022/src/day04.rs Normal file
View File

@@ -0,0 +1,86 @@
use anyhow::Result;
use nom::bytes::complete::tag;
use nom::character::complete::newline;
use nom::combinator::map;
use nom::multi::many0;
use nom::sequence::separated_pair;
use nom::sequence::terminated;
use nom::IResult;
use crate::common::minmax;
use crate::common::parse_input;
#[derive(Copy, Clone, PartialOrd, PartialEq)]
struct Assignment(u32, u32);
impl Assignment {
fn one_contains(self, other: Self) -> bool {
let (first, second) = minmax(self, other);
if second.0 == first.0 {
first.1 <= second.1
} else {
second.0 <= first.1 && second.1 <= first.1
}
}
fn one_overlaps(self, other: Self) -> bool {
let (first, second) = minmax(self, other);
if second.0 == first.0 {
first.1 <= second.1
} else {
second.0 <= first.1
}
}
}
fn parse_assignments(input: &[u8]) -> IResult<&[u8], Vec<(Assignment, Assignment)>> {
use nom::character::complete::u32;
fn parse_single(input: &[u8]) -> IResult<&[u8], Assignment> {
map(separated_pair(u32, tag("-"), u32), |(start, end)| {
Assignment(start, end)
})(input)
}
let parse_line = separated_pair(parse_single, tag(","), parse_single);
many0(terminated(parse_line, newline))(input)
}
fn parts_common(input: &[u8], filter: impl Fn(Assignment, Assignment) -> bool) -> Result<String> {
let assigments = parse_input(input, parse_assignments)?;
let overlapping = assigments
.into_iter()
.filter(|&(a, b)| filter(a, b))
.count();
Ok(overlapping.to_string())
}
pub fn part1(input: &[u8]) -> Result<String> {
parts_common(input, Assignment::one_contains)
}
pub fn part2(input: &[u8]) -> Result<String> {
parts_common(input, Assignment::one_overlaps)
}
#[cfg(test)]
mod tests {
use super::*;
const SAMPLE: &[u8] = include_bytes!("samples/04.txt");
#[test]
fn sample_part1() {
assert_eq!(part1(SAMPLE).unwrap(), "2")
}
#[test]
fn sample_part2() {
assert_eq!(part2(SAMPLE).unwrap(), "4")
}
}

166
2022/src/day05.rs Normal file
View File

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

68
2022/src/day06.rs Normal file
View File

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

124
2022/src/day07.rs Normal file
View File

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

163
2022/src/day08.rs Normal file
View File

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

9
2022/src/day09.rs Normal file
View File

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

9
2022/src/day10.rs Normal file
View File

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

9
2022/src/day11.rs Normal file
View File

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

9
2022/src/day12.rs Normal file
View File

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

9
2022/src/day13.rs Normal file
View File

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

9
2022/src/day14.rs Normal file
View File

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

9
2022/src/day15.rs Normal file
View File

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

9
2022/src/day16.rs Normal file
View File

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

9
2022/src/day17.rs Normal file
View File

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

9
2022/src/day18.rs Normal file
View File

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

9
2022/src/day19.rs Normal file
View File

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

9
2022/src/day20.rs Normal file
View File

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

9
2022/src/day21.rs Normal file
View File

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

9
2022/src/day22.rs Normal file
View File

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

9
2022/src/day23.rs Normal file
View File

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

9
2022/src/day24.rs Normal file
View File

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

5
2022/src/day25.rs Normal file
View File

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

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

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

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

@@ -0,0 +1,61 @@
use std::fs::File;
use std::io::Read;
use std::num::NonZeroU8;
use std::path::PathBuf;
use std::time::Instant;
use anyhow::Result;
use clap::Parser;
use aoc_2022::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

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

@@ -0,0 +1,14 @@
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000

3
2022/src/samples/02.txt Normal file
View File

@@ -0,0 +1,3 @@
A Y
B X
C Z

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

@@ -0,0 +1,6 @@
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

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

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

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

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

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

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

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

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

View File

@@ -1,6 +1,6 @@
# Advent of Code
[![Advent of Code 2021](https://github.com/bertptrs/adventofcode/actions/workflows/2021.yml/badge.svg)](https://github.com/bertptrs/adventofcode/actions/workflows/2021.yml)
[![Advent of Code 2021](https://github.com/bertptrs/adventofcode/actions/workflows/2022.yml/badge.svg)](https://github.com/bertptrs/adventofcode/actions/workflows/2022.yml)
This repository contains my solutions for Advent of Code. See:
@@ -11,3 +11,4 @@ This repository contains my solutions for Advent of Code. See:
- [2019 edition](./2019)
- [2020 edition](./2020)
- [2021 edition](./2021)
- [2022 edition](./2022)