Compare commits
11 Commits
36608db7b3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| bc3ea85dae | |||
| ee116e4c52 | |||
|
|
c89b57bb47 | ||
|
|
4bf768288d | ||
|
|
a939163268 | ||
|
|
b67460e2b9 | ||
|
|
ead6e2ccf7 | ||
|
|
012c8e1286 | ||
|
|
1f140f6047 | ||
|
|
8d92a20cde | ||
|
|
6d4f9b50c8 |
@@ -9,4 +9,4 @@ all = "run --quiet --release -- all"
|
|||||||
time = "run --quiet --release -- time"
|
time = "run --quiet --release -- time"
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
AOC_YEAR = "2024"
|
AOC_YEAR = "2025"
|
||||||
|
|||||||
@@ -15,3 +15,7 @@ trim_trailing_whitespace = false
|
|||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.nix]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -28,3 +28,6 @@ dhat-heap.json
|
|||||||
# Benchmarks
|
# Benchmarks
|
||||||
|
|
||||||
data/timings.json
|
data/timings.json
|
||||||
|
|
||||||
|
# Direnv stuff
|
||||||
|
.direnv/
|
||||||
|
|||||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
@@ -19,7 +19,7 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advent_of_code"
|
name = "advent_of_code"
|
||||||
version = "0.11.0"
|
version = "0.12.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"dhat",
|
"dhat",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "advent_of_code"
|
name = "advent_of_code"
|
||||||
version = "0.11.0"
|
version = "0.12.0"
|
||||||
authors = ["Felix Spöttel <1682504+fspoettel@users.noreply.github.com>"]
|
authors = ["Felix Spöttel <1682504+fspoettel@users.noreply.github.com>"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
default-run = "advent_of_code"
|
default-run = "advent_of_code"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
|
|||||||
@@ -282,14 +282,10 @@ You can pass the report a tool like [dh-view](https://nnethercote.github.io/dh_v
|
|||||||
- [itertools](https://crates.io/crates/itertools): Extends iterators with extra methods and adaptors. Frequently useful for aoc puzzles.
|
- [itertools](https://crates.io/crates/itertools): Extends iterators with extra methods and adaptors. Frequently useful for aoc puzzles.
|
||||||
- [regex](https://crates.io/crates/regex): Official regular expressions implementation for Rust.
|
- [regex](https://crates.io/crates/regex): Official regular expressions implementation for Rust.
|
||||||
|
|
||||||
A curated list of popular crates can be found on [blessred.rs](https://blessed.rs/crates).
|
A curated list of popular crates can be found on [blessed.rs](https://blessed.rs/crates).
|
||||||
|
|
||||||
Do you have aoc-specific crate recommendations? [Share them!](https://github.com/fspoettel/advent-of-code-rust/edit/main/README.md)
|
Do you have aoc-specific crate recommendations? [Share them!](https://github.com/fspoettel/advent-of-code-rust/edit/main/README.md)
|
||||||
|
|
||||||
## Common pitfalls
|
|
||||||
|
|
||||||
- **Integer overflows:** This template uses 32-bit integers by default because it is generally faster - for example when packed in large arrays or structs - than using 64-bit integers everywhere. For some problems, solutions for real input might exceed 32-bit integer space. While this is checked and panics in `debug` mode, integers [wrap](https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-overflow) in `release` mode, leading to wrong output when running your solution.
|
|
||||||
|
|
||||||
## Footnotes
|
## Footnotes
|
||||||
|
|
||||||
[^1]: The session cookie might expire after a while (~1 month) which causes the downloads to fail. To fix this issue, refresh the `.adventofcode.session` file.
|
[^1]: The session cookie might expire after a while (~1 month) which causes the downloads to fail. To fix this issue, refresh the `.adventofcode.session` file.
|
||||||
|
|||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765311797,
|
||||||
|
"narHash": "sha256-mSD5Ob7a+T2RNjvPvOA1dkJHGVrNVl8ZOrAwBjKBDQo=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "09eb77e94fa25202af8f3e81ddc7353d9970ac1b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-25.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
31
flake.nix
Normal file
31
flake.nix
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.11";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
utils,
|
||||||
|
}:
|
||||||
|
utils.lib.eachDefaultSystem (
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShell =
|
||||||
|
with pkgs;
|
||||||
|
mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
rustc
|
||||||
|
cargo
|
||||||
|
clippy
|
||||||
|
rustfmt
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use advent_of_code::template::commands::{all, download, read, scaffold, solve, time};
|
use advent_of_code::template::commands::{all, download, read, scaffold, solve, time};
|
||||||
use args::{parse, AppArguments};
|
use args::{AppArguments, parse};
|
||||||
|
|
||||||
#[cfg(feature = "today")]
|
#[cfg(feature = "today")]
|
||||||
use advent_of_code::template::Day;
|
use advent_of_code::template::Day;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
advent_of_code::solution!(%DAY_NUMBER%);
|
advent_of_code::solution!(%DAY_NUMBER%);
|
||||||
|
|
||||||
pub fn part_one(input: &str) -> Option<u32> {
|
pub fn part_one(input: &str) -> Option<u64> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn part_two(input: &str) -> Option<u32> {
|
pub fn part_two(input: &str) -> Option<u64> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
use crate::template::{aoc_cli, Day};
|
use crate::template::{Day, aoc_cli};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
pub fn handle(day: Day) {
|
pub fn handle(day: Day) {
|
||||||
if aoc_cli::check().is_err() {
|
if aoc_cli::check().is_err() {
|
||||||
eprintln!("command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it.");
|
eprintln!(
|
||||||
|
"command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it."
|
||||||
|
);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use crate::template::{aoc_cli, Day};
|
use crate::template::{Day, aoc_cli};
|
||||||
|
|
||||||
pub fn handle(day: Day) {
|
pub fn handle(day: Day) {
|
||||||
if aoc_cli::check().is_err() {
|
if aoc_cli::check().is_err() {
|
||||||
eprintln!("command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it.");
|
eprintln!(
|
||||||
|
"command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it."
|
||||||
|
);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use crate::template::run_multi::run_multi;
|
use crate::template::run_multi::run_multi;
|
||||||
use crate::template::timings::Timings;
|
use crate::template::timings::Timings;
|
||||||
use crate::template::{all_days, readme_benchmarks, Day};
|
use crate::template::{Day, all_days, readme_benchmarks};
|
||||||
|
|
||||||
pub fn handle(day: Option<Day>, run_all: bool, store: bool) {
|
pub fn handle(day: Option<Day>, run_all: bool, store: bool) {
|
||||||
let stored_timings = Timings::read_from_file();
|
let stored_timings = Timings::read_from_file();
|
||||||
|
|||||||
@@ -24,19 +24,13 @@ pub struct Day(u8);
|
|||||||
impl Day {
|
impl Day {
|
||||||
/// Creates a [`Day`] from the provided value if it's in the valid range,
|
/// Creates a [`Day`] from the provided value if it's in the valid range,
|
||||||
/// returns [`None`] otherwise.
|
/// returns [`None`] otherwise.
|
||||||
pub fn new(day: u8) -> Option<Self> {
|
pub const fn new(day: u8) -> Option<Self> {
|
||||||
if day == 0 || day > 25 {
|
if day == 0 || day > 25 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(Self(day))
|
Some(Self(day))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not part of the public API
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub const fn __new_unchecked(day: u8) -> Self {
|
|
||||||
Self(day)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the [`Day`] into an [`u8`].
|
/// Converts the [`Day`] into an [`u8`].
|
||||||
pub fn into_inner(self) -> u8 {
|
pub fn into_inner(self) -> u8 {
|
||||||
self.0
|
self.0
|
||||||
@@ -137,24 +131,19 @@ impl Iterator for AllDays {
|
|||||||
/// Creates a [`Day`] value in a const context.
|
/// Creates a [`Day`] value in a const context.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! day {
|
macro_rules! day {
|
||||||
($day:expr) => {{
|
($day:expr) => {
|
||||||
const _ASSERT: () = assert!(
|
const {
|
||||||
$day != 0 && $day <= 25,
|
$crate::template::Day::new($day)
|
||||||
concat!(
|
.expect("invalid day number, expecting a value between 1 and 25")
|
||||||
"invalid day number `",
|
}
|
||||||
$day,
|
};
|
||||||
"`, expecting a value between 1 and 25"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
$crate::template::Day::__new_unchecked($day)
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
#[cfg(feature = "test_lib")]
|
#[cfg(feature = "test_lib")]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{all_days, Day};
|
use super::{Day, all_days};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn all_days_iterator() {
|
fn all_days_iterator() {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
/// The approach taken is similar to how `aoc-readme-stars` handles this.
|
/// The approach taken is similar to how `aoc-readme-stars` handles this.
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
|
|
||||||
use crate::template::timings::Timings;
|
|
||||||
use crate::template::Day;
|
use crate::template::Day;
|
||||||
|
use crate::template::timings::Timings;
|
||||||
|
|
||||||
static MARKER: &str = "<!--- benchmarking table --->";
|
static MARKER: &str = "<!--- benchmarking table --->";
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ pub fn update(timings: Timings) -> Result<(), Error> {
|
|||||||
|
|
||||||
#[cfg(feature = "test_lib")]
|
#[cfg(feature = "test_lib")]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{update_content, MARKER};
|
use super::{MARKER, update_content};
|
||||||
use crate::{day, template::timings::Timing, template::timings::Timings};
|
use crate::{day, template::timings::Timing, template::timings::Timings};
|
||||||
|
|
||||||
fn get_mock_timings() -> Timings {
|
fn get_mock_timings() -> Timings {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{collections::HashSet, io};
|
use std::{collections::HashSet, io};
|
||||||
|
|
||||||
use crate::template::{Day, ANSI_BOLD, ANSI_ITALIC, ANSI_RESET};
|
use crate::template::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET, Day};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
all_days,
|
all_days,
|
||||||
@@ -67,7 +67,7 @@ pub fn get_path_for_bin(day: Day) -> String {
|
|||||||
/// All solutions live in isolated binaries.
|
/// All solutions live in isolated binaries.
|
||||||
/// This module encapsulates interaction with these binaries, both invoking them as well as parsing the timing output.
|
/// This module encapsulates interaction with these binaries, both invoking them as well as parsing the timing output.
|
||||||
pub mod child_commands {
|
pub mod child_commands {
|
||||||
use super::{get_path_for_bin, Error};
|
use super::{Error, get_path_for_bin};
|
||||||
use crate::template::Day;
|
use crate::template::Day;
|
||||||
use std::{
|
use std::{
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
@@ -174,7 +174,7 @@ pub mod child_commands {
|
|||||||
.split(" samples)")
|
.split(" samples)")
|
||||||
.next()?
|
.next()?
|
||||||
.split('(')
|
.split('(')
|
||||||
.last()?
|
.next_back()?
|
||||||
.split('@')
|
.split('@')
|
||||||
.next()?
|
.next()?
|
||||||
.trim();
|
.trim();
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/// Encapsulates code that interacts with solution functions.
|
/// Encapsulates code that interacts with solution functions.
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::hint::black_box;
|
use std::hint::black_box;
|
||||||
use std::io::{stdout, Write};
|
use std::io::{Write, stdout};
|
||||||
use std::process::Output;
|
use std::process::Output;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use std::{cmp, env, process};
|
use std::{cmp, env, process};
|
||||||
|
|
||||||
use crate::template::ANSI_BOLD;
|
use crate::template::ANSI_BOLD;
|
||||||
use crate::template::{aoc_cli, Day, ANSI_ITALIC, ANSI_RESET};
|
use crate::template::{ANSI_ITALIC, ANSI_RESET, Day, aoc_cli};
|
||||||
|
|
||||||
pub fn run_part<I: Copy, T: Display>(func: impl Fn(I) -> Option<T>, input: I, day: Day, part: u8) {
|
pub fn run_part<I: Copy, T: Display>(func: impl Fn(I) -> Option<T>, input: I, day: Day, part: u8) {
|
||||||
let part_str = format!("Part {part}");
|
let part_str = format!("Part {part}");
|
||||||
@@ -156,7 +156,9 @@ fn submit_result<T: Display>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if aoc_cli::check().is_err() {
|
if aoc_cli::check().is_err() {
|
||||||
eprintln!("command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it.");
|
eprintln!(
|
||||||
|
"command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it."
|
||||||
|
);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user