diff --git a/.github/workflows/readme-stars.yml b/.github/workflows/readme-stars.yml index 1dec447..3de260e 100644 --- a/.github/workflows/readme-stars.yml +++ b/.github/workflows/readme-stars.yml @@ -21,4 +21,4 @@ jobs: year: ${{ secrets.AOC_YEAR }} - uses: stefanzweifel/git-auto-commit-action@v5 with: - commit_message: "update readme progess" + commit_message: "update readme progress" diff --git a/Cargo.lock b/Cargo.lock index ea86ba4..e80576a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "advent_of_code" -version = "0.9.3" +version = "0.9.4" dependencies = [ "pico-args", ] diff --git a/Cargo.toml b/Cargo.toml index 692fc58..e47e1fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "advent_of_code" -version = "0.9.3" +version = "0.9.4" authors = ["Felix Spöttel <1682504+fspoettel@users.noreply.github.com>"] edition = "2021" default-run = "advent_of_code" diff --git a/README.md b/README.md index 85aba56..3e51634 100644 --- a/README.md +++ b/README.md @@ -49,18 +49,17 @@ cargo scaffold Individual solutions live in the `./src/bin/` directory as separate binaries. _Inputs_ and _examples_ live in the the `./data` directory. -Every [solution](https://github.com/fspoettel/advent-of-code-rust/blob/main/src/template/commands/scaffold.rs#L9-L35) has _tests_ referencing its _example_ file in `./data/examples`. Use these tests to develop and debug your solutions against the example input. +Every [solution](https://github.com/fspoettel/advent-of-code-rust/blob/main/src/template/commands/scaffold.rs#L9-L35) has _tests_ referencing its _example_ file in `./data/examples`. Use these tests to develop and debug your solutions against the example input. In VS Code, `rust-analyzer` will display buttons for running / debugging these unit tests above the unit test blocks. > [!TIP] > If a day has different example inputs for both parts, you can use the `read_file_part()` helper in your tests instead of `read_file()`. For example, if this applies to day 1, you can create a second example file `01-2.txt` and invoke the helper like `let result = part_two(&advent_of_code::template::read_file_part("examples", DAY, 2));` to read it in `test_part_two`. -> [!TIP] -> when editing a solution, `rust-analyzer` will display buttons for running / debugging unit tests above the unit test blocks. - ### Download input & description for a day > [!IMPORTANT] -> This command requires [installing the aoc-cli crate](#configure-aoc-cli-integration). +> This requires [installing the aoc-cli crate](#configure-aoc-cli-integration). + +You can automatically download puzzle inputs and description by either appending the `--download` flag to `scaffold` (e.g. `cargo scaffold 4 --download`) or with the separate `download` command: ```sh # example: `cargo download 1` @@ -97,7 +96,7 @@ For example, running a benchmarked, optimized execution of day 1 would look like #### Submitting solutions > [!IMPORTANT] -> This command requires [installing the aoc-cli crate](#configure-aoc-cli-integration). +> This requires [installing the aoc-cli crate](#configure-aoc-cli-integration). In order to submit part of a solution for checking, append the `--submit ` option to the `solve` command. @@ -121,7 +120,7 @@ This runs all solutions sequentially and prints output to the command-line. Same #### Update readme benchmarks -The template can output a table with solution times to your readme. In order to generate a benchmarking table, run `cargo all --release --time`. If everything goes well, the command will output "_Successfully updated README with benchmarks._" after the execution finishes and the readme will be updated. +The template can output a table with solution times to your readme. In order to generate a benchmarking table, run `cargo time`. If everything goes well, the command will output "_Successfully updated README with benchmarks._" after the execution finishes and the readme will be updated. Please note that these are not "scientific" benchmarks, understand them as a fun approximation. 😉 Timings, especially in the microseconds range, might change a bit between invocations. diff --git a/src/lib.rs b/src/lib.rs index 04f64f0..612b5b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1 @@ -mod day; pub mod template; - -pub use day::*; diff --git a/src/main.rs b/src/main.rs index 23ba03c..80ac450 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,10 +2,9 @@ use advent_of_code::template::commands::{all, download, read, scaffold, solve}; use args::{parse, AppArguments}; mod args { + use advent_of_code::template::Day; use std::process; - use advent_of_code::Day; - pub enum AppArguments { Download { day: Day, @@ -15,6 +14,7 @@ mod args { }, Scaffold { day: Day, + download: bool, }, Solve { day: Day, @@ -44,6 +44,7 @@ mod args { }, Some("scaffold") => AppArguments::Scaffold { day: args.free_from_str()?, + download: args.contains("--download"), }, Some("solve") => AppArguments::Solve { day: args.free_from_str()?, @@ -80,7 +81,12 @@ fn main() { AppArguments::All { release, time } => all::handle(release, time), AppArguments::Download { day } => download::handle(day), AppArguments::Read { day } => read::handle(day), - AppArguments::Scaffold { day } => scaffold::handle(day), + AppArguments::Scaffold { day, download } => { + scaffold::handle(day); + if download { + download::handle(day); + } + } AppArguments::Solve { day, release, diff --git a/src/template/aoc_cli.rs b/src/template/aoc_cli.rs index e7aab8b..a9ff3b0 100644 --- a/src/template/aoc_cli.rs +++ b/src/template/aoc_cli.rs @@ -4,7 +4,7 @@ use std::{ process::{Command, Output, Stdio}, }; -use crate::Day; +use crate::template::Day; #[derive(Debug)] pub enum AocCommandError { diff --git a/src/template/commands/all.rs b/src/template/commands/all.rs index 7443322..a183445 100644 --- a/src/template/commands/all.rs +++ b/src/template/commands/all.rs @@ -1,10 +1,10 @@ use std::io; use crate::template::{ + all_days, readme_benchmarks::{self, Timings}, - ANSI_BOLD, ANSI_ITALIC, ANSI_RESET, + Day, ANSI_BOLD, ANSI_ITALIC, ANSI_RESET, }; -use crate::{all_days, Day}; pub fn handle(is_release: bool, is_timed: bool) { let mut timings: Vec = vec![]; @@ -65,7 +65,7 @@ pub fn get_path_for_bin(day: Day) -> String { /// This module encapsulates interaction with these binaries, both invoking them as well as parsing the timing output. mod child_commands { use super::{get_path_for_bin, Error}; - use crate::Day; + use crate::template::Day; use std::{ io::{BufRead, BufReader}, path::Path, diff --git a/src/template/commands/download.rs b/src/template/commands/download.rs index 76ad635..9274f05 100644 --- a/src/template/commands/download.rs +++ b/src/template/commands/download.rs @@ -1,5 +1,4 @@ -use crate::template::aoc_cli; -use crate::Day; +use crate::template::{aoc_cli, Day}; use std::process; pub fn handle(day: Day) { diff --git a/src/template/commands/read.rs b/src/template/commands/read.rs index 01316f8..3e1a307 100644 --- a/src/template/commands/read.rs +++ b/src/template/commands/read.rs @@ -1,7 +1,6 @@ use std::process; -use crate::template::aoc_cli; -use crate::Day; +use crate::template::{aoc_cli, Day}; pub fn handle(day: Day) { if aoc_cli::check().is_err() { diff --git a/src/template/commands/scaffold.rs b/src/template/commands/scaffold.rs index 2a992bc..138e124 100644 --- a/src/template/commands/scaffold.rs +++ b/src/template/commands/scaffold.rs @@ -4,7 +4,7 @@ use std::{ process, }; -use crate::Day; +use crate::template::Day; const MODULE_TEMPLATE: &str = r#"advent_of_code::solution!(DAY_NUMBER); diff --git a/src/template/commands/solve.rs b/src/template/commands/solve.rs index 50b7000..c2c3d89 100644 --- a/src/template/commands/solve.rs +++ b/src/template/commands/solve.rs @@ -1,6 +1,6 @@ use std::process::{Command, Stdio}; -use crate::Day; +use crate::template::Day; pub fn handle(day: Day, release: bool, time: bool, submit_part: Option) { let mut cmd_args = vec!["run".to_string(), "--bin".to_string(), day.to_string()]; diff --git a/src/day.rs b/src/template/day.rs similarity index 98% rename from src/day.rs rename to src/template/day.rs index 5148797..fe1f66a 100644 --- a/src/day.rs +++ b/src/template/day.rs @@ -126,7 +126,7 @@ macro_rules! day { "`, expecting a value between 1 and 25" ), ); - $crate::Day::__new_unchecked($day) + $crate::template::Day::__new_unchecked($day) }}; } diff --git a/src/template/mod.rs b/src/template/mod.rs index d1533e1..49402b2 100644 --- a/src/template/mod.rs +++ b/src/template/mod.rs @@ -1,11 +1,13 @@ -use crate::Day; use std::{env, fs}; pub mod aoc_cli; pub mod commands; +mod day; pub mod readme_benchmarks; pub mod runner; +pub use day::*; + pub const ANSI_ITALIC: &str = "\x1b[3m"; pub const ANSI_BOLD: &str = "\x1b[1m"; pub const ANSI_RESET: &str = "\x1b[0m"; @@ -32,11 +34,13 @@ pub fn read_file_part(folder: &str, day: Day, part: u8) -> String { } /// Creates the constant `DAY` and sets up the input and runner for each part. +/// +/// The optional, second parameter (1 or 2) allows you to only run a single part of the solution. #[macro_export] macro_rules! solution { ($day:expr) => { /// The current day. - const DAY: advent_of_code::Day = advent_of_code::day!($day); + const DAY: advent_of_code::template::Day = advent_of_code::day!($day); fn main() { use advent_of_code::template::runner::*; @@ -45,4 +49,24 @@ macro_rules! solution { run_part(part_two, &input, DAY, 2); } }; + ($day:expr, 1) => { + /// Allows solving part one in isolation + const DAY: advent_of_code::template::Day = advent_of_code::day!($day); + + fn main() { + use advent_of_code::template::runner::*; + let input = advent_of_code::template::read_file("inputs", DAY); + run_part(part_one, &input, DAY, 1); + } + }; + ($day:expr, 2) => { + /// Allows solving part two in isolation + const DAY: advent_of_code::template::Day = advent_of_code::day!($day); + + fn main() { + use advent_of_code::template::runner::*; + let input = advent_of_code::template::read_file("inputs", DAY); + run_part(part_two, &input, DAY, 2); + } + }; } diff --git a/src/template/readme_benchmarks.rs b/src/template/readme_benchmarks.rs index c564aa4..b282196 100644 --- a/src/template/readme_benchmarks.rs +++ b/src/template/readme_benchmarks.rs @@ -2,7 +2,7 @@ /// The approach taken is similar to how `aoc-readme-stars` handles this. use std::{fs, io}; -use crate::Day; +use crate::template::Day; static MARKER: &str = ""; diff --git a/src/template/runner.rs b/src/template/runner.rs index 5e6a9b3..4b47332 100644 --- a/src/template/runner.rs +++ b/src/template/runner.rs @@ -1,7 +1,7 @@ /// Encapsulates code that interacts with solution functions. -use crate::template::{aoc_cli, ANSI_ITALIC, ANSI_RESET}; -use crate::Day; +use crate::template::{aoc_cli, Day, ANSI_ITALIC, ANSI_RESET}; use std::fmt::Display; +use std::hint::black_box; use std::io::{stdout, Write}; use std::process::Output; use std::time::{Duration, Instant}; @@ -65,7 +65,7 @@ fn bench(func: impl Fn(I) -> T, input: I, base_time: &Duration) -> // need a clone here to make the borrow checker happy. let cloned = input.clone(); let timer = Instant::now(); - func(cloned); + black_box(func(black_box(cloned))); timers.push(timer.elapsed()); }