mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Merge pull request #5 from bertptrs/setup-2023
This commit is contained in:
20
.github/workflows/2022.yml
vendored
20
.github/workflows/2022.yml
vendored
@@ -1,7 +1,7 @@
|
|||||||
on:
|
on:
|
||||||
- push
|
- push
|
||||||
|
|
||||||
name: Advent of Code 2022
|
name: Advent of Code 2023
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
@@ -20,33 +20,33 @@ jobs:
|
|||||||
continue-on-error: ${{ matrix.experimental }}
|
continue-on-error: ${{ matrix.experimental }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install toolchain
|
- name: Install toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: dtolnay/rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: ${{ matrix.toolchain }}
|
toolchain: ${{ matrix.toolchain }}
|
||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt
|
||||||
|
|
||||||
- name: Set up caching
|
- name: Set up caching
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
workspaces: >
|
workspaces: >
|
||||||
2022 -> target
|
2023 -> target
|
||||||
|
|
||||||
- name: Build binaries
|
- name: Build binaries
|
||||||
working-directory: 2022
|
working-directory: 2023
|
||||||
run: >
|
run: >
|
||||||
cargo build --all-targets
|
cargo build --all-targets
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
working-directory: 2022
|
working-directory: 2023
|
||||||
run: >
|
run: >
|
||||||
cargo test
|
cargo test
|
||||||
|
|
||||||
- name: Run clippy
|
- name: Check formatting
|
||||||
working-directory: 2022
|
working-directory: 2023
|
||||||
run: >
|
run: >
|
||||||
cargo clippy -- --deny warnings
|
cargo fmt --check
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -64,3 +64,6 @@ target/
|
|||||||
perf.data
|
perf.data
|
||||||
perf.data.old
|
perf.data.old
|
||||||
flamegraph.svg
|
flamegraph.svg
|
||||||
|
|
||||||
|
# Ignore saved inputs
|
||||||
|
inputs/
|
||||||
|
|||||||
14
2023/Cargo.toml
Normal file
14
2023/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "aoc-2023"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.75"
|
||||||
|
clap = { version = "4.4.8", features = ["derive"] }
|
||||||
|
nom = "7.1.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
criterion = "0.5.1"
|
||||||
44
2023/benches/days.rs
Normal file
44
2023/benches/days.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
use criterion::criterion_group;
|
||||||
|
use criterion::criterion_main;
|
||||||
|
use criterion::BenchmarkId;
|
||||||
|
use criterion::Criterion;
|
||||||
|
|
||||||
|
use aoc_2023::get_implementation;
|
||||||
|
|
||||||
|
/// Number of days we have an implementation to benchmark
|
||||||
|
const DAYS_IMPLEMENTED: u8 = 0;
|
||||||
|
|
||||||
|
fn read_input(day: u8) -> std::io::Result<Vec<u8>> {
|
||||||
|
let input_path = format!("inputs/{day:02}.txt");
|
||||||
|
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
File::open(input_path)?.read_to_end(&mut buffer)?;
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn benchmark_days(c: &mut Criterion) {
|
||||||
|
for day in 1..=DAYS_IMPLEMENTED {
|
||||||
|
if let Ok(input) = read_input(day) {
|
||||||
|
let part1 = get_implementation(day, false).unwrap();
|
||||||
|
|
||||||
|
c.bench_with_input(BenchmarkId::new("part1", day), &input, |b, i| {
|
||||||
|
b.iter(|| part1(i));
|
||||||
|
});
|
||||||
|
|
||||||
|
if day < 25 {
|
||||||
|
let part2 = get_implementation(day, true).unwrap();
|
||||||
|
|
||||||
|
c.bench_with_input(BenchmarkId::new("part2", day), &input, |b, i| {
|
||||||
|
b.iter(|| part2(i));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, benchmark_days);
|
||||||
|
criterion_main!(benches);
|
||||||
0
2023/inputs/.gitkeep
Normal file
0
2023/inputs/.gitkeep
Normal file
0
2023/samples/.gitkeep
Normal file
0
2023/samples/.gitkeep
Normal file
234
2023/src/common.rs
Normal file
234
2023/src/common.rs
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
//! Common helper utilities to all days
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::ops::Add;
|
||||||
|
use std::ops::Div;
|
||||||
|
use std::ops::Index;
|
||||||
|
use std::ops::IndexMut;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use nom::combinator::map;
|
||||||
|
use nom::error::ErrorKind;
|
||||||
|
use nom::error::ParseError;
|
||||||
|
use nom::Finish;
|
||||||
|
use nom::IResult;
|
||||||
|
use nom::InputLength;
|
||||||
|
use nom::Parser;
|
||||||
|
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Some magic to get two mutable references into the same slice
|
||||||
|
pub fn get_both<T>(slice: &mut [T], first: usize, second: usize) -> (&mut T, &mut T) {
|
||||||
|
match first.cmp(&second) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
let (begin, end) = slice.split_at_mut(first);
|
||||||
|
(&mut end[0], &mut begin[second])
|
||||||
|
}
|
||||||
|
Ordering::Less => {
|
||||||
|
let (begin, end) = slice.split_at_mut(second);
|
||||||
|
(&mut begin[first], &mut end[0])
|
||||||
|
}
|
||||||
|
Ordering::Equal => panic!("Tried to get the same index twice {first}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct IndexSet(Vec<u32>);
|
||||||
|
|
||||||
|
impl IndexSet {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self(Vec::with_capacity(
|
||||||
|
capacity / std::mem::size_of::<u32>() / 8,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_item(&mut self, item: usize) -> &mut u32 {
|
||||||
|
if self.0.len() <= item {
|
||||||
|
self.0.resize(item + 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&mut self.0[item]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(index: usize) -> (usize, u8) {
|
||||||
|
const PER_ENTRY: usize = 8 * std::mem::size_of::<u32>();
|
||||||
|
|
||||||
|
(index / PER_ENTRY, (index % PER_ENTRY) as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, index: usize) -> bool {
|
||||||
|
let (entry, pos) = Self::index(index);
|
||||||
|
|
||||||
|
let item = self.ensure_item(entry);
|
||||||
|
let old = *item;
|
||||||
|
|
||||||
|
*item |= 1 << pos;
|
||||||
|
|
||||||
|
old != *item
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, index: usize) -> bool {
|
||||||
|
let (entry, pos) = Self::index(index);
|
||||||
|
|
||||||
|
self.0
|
||||||
|
.get(entry)
|
||||||
|
.map_or(false, |&entry| (entry & (1 << pos) != 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Vec2(pub [i32; 2]);
|
||||||
|
|
||||||
|
impl Vec2 {
|
||||||
|
pub fn l1(self) -> i32 {
|
||||||
|
self.0.into_iter().map(i32::abs).sum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<Self> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self([self[0] + rhs[0], self[1] + rhs[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<Self> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self([self[0] - rhs[0], self[1] - rhs[1]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<i32> for Vec2 {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: i32) -> Self::Output {
|
||||||
|
Self(self.0.map(|v| v / rhs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<usize> for Vec2 {
|
||||||
|
type Output = i32;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<usize> for Vec2 {
|
||||||
|
#[inline]
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.0[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
7
2023/src/day01.rs
Normal file
7
2023/src/day01.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day02.rs
Normal file
7
2023/src/day02.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day03.rs
Normal file
7
2023/src/day03.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day04.rs
Normal file
7
2023/src/day04.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day05.rs
Normal file
7
2023/src/day05.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day06.rs
Normal file
7
2023/src/day06.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day07.rs
Normal file
7
2023/src/day07.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day08.rs
Normal file
7
2023/src/day08.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day09.rs
Normal file
7
2023/src/day09.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day10.rs
Normal file
7
2023/src/day10.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day11.rs
Normal file
7
2023/src/day11.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day12.rs
Normal file
7
2023/src/day12.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day13.rs
Normal file
7
2023/src/day13.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day14.rs
Normal file
7
2023/src/day14.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day15.rs
Normal file
7
2023/src/day15.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day16.rs
Normal file
7
2023/src/day16.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day17.rs
Normal file
7
2023/src/day17.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day18.rs
Normal file
7
2023/src/day18.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day19.rs
Normal file
7
2023/src/day19.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day20.rs
Normal file
7
2023/src/day20.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day21.rs
Normal file
7
2023/src/day21.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day22.rs
Normal file
7
2023/src/day22.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day23.rs
Normal file
7
2023/src/day23.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
7
2023/src/day24.rs
Normal file
7
2023/src/day24.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn part2(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
3
2023/src/day25.rs
Normal file
3
2023/src/day25.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub fn part1(_input: &[u8]) -> anyhow::Result<String> {
|
||||||
|
anyhow::bail!("Not implemented")
|
||||||
|
}
|
||||||
91
2023/src/lib.rs
Normal file
91
2023/src/lib.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
mod day01;
|
||||||
|
mod day02;
|
||||||
|
mod day03;
|
||||||
|
mod day04;
|
||||||
|
mod day05;
|
||||||
|
mod day06;
|
||||||
|
mod day07;
|
||||||
|
mod day08;
|
||||||
|
mod day09;
|
||||||
|
mod day10;
|
||||||
|
mod day11;
|
||||||
|
mod day12;
|
||||||
|
mod day13;
|
||||||
|
mod day14;
|
||||||
|
mod day15;
|
||||||
|
mod day16;
|
||||||
|
mod day17;
|
||||||
|
mod day18;
|
||||||
|
mod day19;
|
||||||
|
mod day20;
|
||||||
|
mod day21;
|
||||||
|
mod day22;
|
||||||
|
mod day23;
|
||||||
|
mod day24;
|
||||||
|
mod day25;
|
||||||
|
|
||||||
|
type Solution = fn(&[u8]) -> Result<String>;
|
||||||
|
|
||||||
|
pub fn get_implementation(day: u8, part2: bool) -> Result<Solution> {
|
||||||
|
if !part2 {
|
||||||
|
match day {
|
||||||
|
1 => Ok(day01::part1),
|
||||||
|
2 => Ok(day02::part1),
|
||||||
|
3 => Ok(day03::part1),
|
||||||
|
4 => Ok(day04::part1),
|
||||||
|
5 => Ok(day05::part1),
|
||||||
|
6 => Ok(day06::part1),
|
||||||
|
7 => Ok(day07::part1),
|
||||||
|
8 => Ok(day08::part1),
|
||||||
|
9 => Ok(day09::part1),
|
||||||
|
10 => Ok(day10::part1),
|
||||||
|
11 => Ok(day11::part1),
|
||||||
|
12 => Ok(day12::part1),
|
||||||
|
13 => Ok(day13::part1),
|
||||||
|
14 => Ok(day14::part1),
|
||||||
|
15 => Ok(day15::part1),
|
||||||
|
16 => Ok(day16::part1),
|
||||||
|
17 => Ok(day17::part1),
|
||||||
|
18 => Ok(day18::part1),
|
||||||
|
19 => Ok(day19::part1),
|
||||||
|
20 => Ok(day20::part1),
|
||||||
|
21 => Ok(day21::part1),
|
||||||
|
22 => Ok(day22::part1),
|
||||||
|
23 => Ok(day23::part1),
|
||||||
|
24 => Ok(day24::part1),
|
||||||
|
25 => Ok(day25::part1),
|
||||||
|
_ => anyhow::bail!("Invalid day for part 1: {day}"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match day {
|
||||||
|
1 => Ok(day01::part2),
|
||||||
|
2 => Ok(day02::part2),
|
||||||
|
3 => Ok(day03::part2),
|
||||||
|
4 => Ok(day04::part2),
|
||||||
|
5 => Ok(day05::part2),
|
||||||
|
6 => Ok(day06::part2),
|
||||||
|
7 => Ok(day07::part2),
|
||||||
|
8 => Ok(day08::part2),
|
||||||
|
9 => Ok(day09::part2),
|
||||||
|
10 => Ok(day10::part2),
|
||||||
|
11 => Ok(day11::part2),
|
||||||
|
12 => Ok(day12::part2),
|
||||||
|
13 => Ok(day13::part2),
|
||||||
|
14 => Ok(day14::part2),
|
||||||
|
15 => Ok(day15::part2),
|
||||||
|
16 => Ok(day16::part2),
|
||||||
|
17 => Ok(day17::part2),
|
||||||
|
18 => Ok(day18::part2),
|
||||||
|
19 => Ok(day19::part2),
|
||||||
|
20 => Ok(day20::part2),
|
||||||
|
21 => Ok(day21::part2),
|
||||||
|
22 => Ok(day22::part2),
|
||||||
|
23 => Ok(day23::part2),
|
||||||
|
24 => Ok(day24::part2),
|
||||||
|
_ => anyhow::bail!("Invalid day for part 2: {day}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
2023/src/main.rs
Normal file
61
2023/src/main.rs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::num::NonZeroU8;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
|
use aoc_2023::get_implementation;
|
||||||
|
|
||||||
|
/// Advent of Code 2022 runner
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Opts {
|
||||||
|
/// Which day to run
|
||||||
|
day: NonZeroU8,
|
||||||
|
|
||||||
|
/// Print time taken
|
||||||
|
#[clap(short, long)]
|
||||||
|
time: bool,
|
||||||
|
|
||||||
|
/// Run part 2 instead of part 1
|
||||||
|
#[clap(short = '2', long)]
|
||||||
|
part2: bool,
|
||||||
|
|
||||||
|
/// Read input from the given file instead of stdin
|
||||||
|
#[clap(short, long)]
|
||||||
|
input: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Opts {
|
||||||
|
fn input_data(&self) -> Result<Vec<u8>> {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
|
if let Some(input) = &self.input {
|
||||||
|
File::open(input)?.read_to_end(&mut buffer)?;
|
||||||
|
} else {
|
||||||
|
std::io::stdin().read_to_end(&mut buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let opts: Opts = Opts::parse();
|
||||||
|
|
||||||
|
let input = opts.input_data()?;
|
||||||
|
|
||||||
|
let implementation = get_implementation(opts.day.get(), opts.part2)?;
|
||||||
|
|
||||||
|
let begin = Instant::now();
|
||||||
|
let result = implementation(&input)?;
|
||||||
|
|
||||||
|
if opts.time {
|
||||||
|
eprintln!("Execution time: {:?}", Instant::now().duration_since(begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{result}");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user