diff --git a/.cargo/config.toml b/.cargo/config.toml index 66b873e..cf0d80d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,4 +9,4 @@ all = "run --quiet --release -- all" time = "run --quiet --release -- time" [env] -AOC_YEAR = "2023" +AOC_YEAR = "2024" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9eef218..b67acb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,13 +6,13 @@ env: CARGO_TERM_COLOR: always jobs: - test: + ci: runs-on: ubuntu-latest - name: CI + name: Continuous Integration steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up cargo cache - uses: actions/cache@v3 + uses: actions/cache@v4 continue-on-error: false with: path: | diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4ce7b67..996c817 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,7 +2,6 @@ "recommendations": [ "vadimcn.vscode-lldb", "rust-lang.rust-analyzer", - "serayuzgur.crates", "editorConfig.editorConfig" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f244cf..2aa7026 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,8 +12,10 @@ "args": [ "test", "--no-run", - // replace `01` here with the solution you like to debug. - "--bin=01", + // replace with binary name (e.g. "01") here if you always + // want to debug one file regardless of the active file in + // the editor. + "--bin=${fileBasenameNoExtension}", "--package=advent_of_code" ], }, @@ -27,8 +29,10 @@ "cargo": { "args": [ "build", - // replace `01` here with the solution you like to debug. - "--bin=01", + // replace with binary name (e.g. "01") here if you always + // want to debug one file regardless of the active file in + // the editor + "--bin=${fileBasenameNoExtension}", "--package=advent_of_code" ], }, diff --git a/Cargo.lock b/Cargo.lock index 1ae9464..9504be6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,16 +92,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -112,9 +112,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "dhat" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2aaf837aaf456f6706cb46386ba8dffd4013a757e36f4ea05c20dd46b209a3" +checksum = "98cd11d84628e233de0ce467de10b8633f4ddaecafadefc86e13b84b8739b827" dependencies = [ "backtrace", "lazy_static", @@ -267,7 +267,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -463,7 +463,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -472,13 +472,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -487,38 +503,86 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 3396495..038a1a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ test_lib = [] [dependencies] # Template dependencies -chrono = { version = "0.4.31", optional = true } -dhat = { version = "0.3.2", optional = true } +chrono = { version = "0.4.38", optional = true } +dhat = { version = "0.3.3", optional = true } pico-args = "0.5.0" tinyjson = "2.5.1" diff --git a/README.md b/README.md index a155efa..e3db903 100644 --- a/README.md +++ b/README.md @@ -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. - [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) -## 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 [^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. diff --git a/src/main.rs b/src/main.rs index 9322423..2a360fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod args { Scaffold { day: Day, download: bool, + overwrite: bool, }, Solve { day: Day, @@ -65,6 +66,7 @@ mod args { Some("scaffold") => AppArguments::Scaffold { day: args.free_from_str()?, download: args.contains("--download"), + overwrite: args.contains("--overwrite"), }, Some("solve") => AppArguments::Solve { day: args.free_from_str()?, @@ -104,8 +106,12 @@ fn main() { AppArguments::Time { day, all, store } => time::handle(day, all, store), AppArguments::Download { day } => download::handle(day), AppArguments::Read { day } => read::handle(day), - AppArguments::Scaffold { day, download } => { - scaffold::handle(day); + AppArguments::Scaffold { + day, + download, + overwrite, + } => { + scaffold::handle(day, overwrite); if download { download::handle(day); } @@ -120,7 +126,7 @@ fn main() { AppArguments::Today => { match Day::today() { Some(day) => { - scaffold::handle(day); + scaffold::handle(day, false); download::handle(day); read::handle(day) } diff --git a/src/template.txt b/src/template.txt index 11344df..87eac99 100644 --- a/src/template.txt +++ b/src/template.txt @@ -1,10 +1,10 @@ advent_of_code::solution!(%DAY_NUMBER%); -pub fn part_one(input: &str) -> Option { +pub fn part_one(input: &str) -> Option { None } -pub fn part_two(input: &str) -> Option { +pub fn part_two(input: &str) -> Option { None } diff --git a/src/template/commands/scaffold.rs b/src/template/commands/scaffold.rs index 4e7d7c0..fc3d950 100644 --- a/src/template/commands/scaffold.rs +++ b/src/template/commands/scaffold.rs @@ -9,20 +9,30 @@ use crate::template::Day; const MODULE_TEMPLATE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/template.txt")); -fn safe_create_file(path: &str) -> Result { - OpenOptions::new().write(true).create_new(true).open(path) +fn safe_create_file(path: &str, overwrite: bool) -> Result { + let mut file = OpenOptions::new(); + if overwrite { + file.create(true); + } else { + file.create_new(true); + } + file.truncate(true).write(true).open(path) } fn create_file(path: &str) -> Result { - OpenOptions::new().write(true).create(true).open(path) + OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path) } -pub fn handle(day: Day) { +pub fn handle(day: Day, overwrite: bool) { let input_path = format!("data/inputs/{day}.txt"); let example_path = format!("data/examples/{day}.txt"); let module_path = format!("src/bin/{day}.rs"); - let mut file = match safe_create_file(&module_path) { + let mut file = match safe_create_file(&module_path, overwrite) { Ok(file) => file, Err(e) => { eprintln!("Failed to create module file: {e}"); diff --git a/src/template/readme_benchmarks.rs b/src/template/readme_benchmarks.rs index 1498dbb..5c42ae4 100644 --- a/src/template/readme_benchmarks.rs +++ b/src/template/readme_benchmarks.rs @@ -7,6 +7,7 @@ use crate::template::Day; static MARKER: &str = ""; +#[allow(dead_code)] #[derive(Debug)] pub enum Error { Parser(String), diff --git a/src/template/run_multi.rs b/src/template/run_multi.rs index 5bafefb..c951faa 100644 --- a/src/template/run_multi.rs +++ b/src/template/run_multi.rs @@ -46,6 +46,7 @@ pub fn run_multi(days_to_run: &HashSet, is_release: bool, is_timed: bool) - } } +#[allow(dead_code)] #[derive(Debug)] pub enum Error { BrokenPipe, diff --git a/src/template/runner.rs b/src/template/runner.rs index b4e41bc..43a2bb4 100644 --- a/src/template/runner.rs +++ b/src/template/runner.rs @@ -9,7 +9,7 @@ use std::{cmp, env, process}; use crate::template::ANSI_BOLD; use crate::template::{aoc_cli, Day, ANSI_ITALIC, ANSI_RESET}; -pub fn run_part(func: impl Fn(I) -> Option, input: I, day: Day, part: u8) { +pub fn run_part(func: impl Fn(I) -> Option, input: I, day: Day, part: u8) { let part_str = format!("Part {part}"); let (result, duration, samples) = @@ -25,15 +25,13 @@ pub fn run_part(func: impl Fn(I) -> Option, input: I, d /// Run a solution part. The behavior differs depending on whether we are running a release or debug build: /// 1. in debug, the function is executed once. /// 2. in release, the function is benched (approx. 1 second of execution time or 10 samples, whatever take longer.) -fn run_timed( +fn run_timed( func: impl Fn(I) -> T, input: I, hook: impl Fn(&T), ) -> (T, Duration, u128) { let timer = Instant::now(); let result = { - let input = input.clone(); - #[cfg(feature = "dhat-heap")] let _profiler = dhat::Profiler::new_heap(); @@ -52,27 +50,20 @@ fn run_timed( (result, run.0, run.1) } -fn bench(func: impl Fn(I) -> T, input: I, base_time: &Duration) -> (Duration, u128) { +fn bench(func: impl Fn(I) -> T, input: I, base_time: &Duration) -> (Duration, u128) { let mut stdout = stdout(); print!(" > {ANSI_ITALIC}benching{ANSI_RESET}"); let _ = stdout.flush(); - let bench_iterations = cmp::min( - 10000, - cmp::max( - Duration::from_secs(1).as_nanos() / cmp::max(base_time.as_nanos(), 10), - 10, - ), - ); + let bench_iterations = + (Duration::from_secs(1).as_nanos() / cmp::max(base_time.as_nanos(), 10)).clamp(10, 10000); let mut timers: Vec = vec![]; for _ in 0..bench_iterations { - // need a clone here to make the borrow checker happy. - let cloned = input.clone(); let timer = Instant::now(); - black_box(func(black_box(cloned))); + black_box(func(black_box(input))); timers.push(timer.elapsed()); } diff --git a/src/template/timings.rs b/src/template/timings.rs index 194464e..fb79835 100644 --- a/src/template/timings.rs +++ b/src/template/timings.rs @@ -31,17 +31,10 @@ impl Timings { /// Rehydrate timings from a JSON file. If not present, returns empty timings. pub fn read_from_file() -> Self { - let s = fs::read_to_string(TIMINGS_FILE_PATH) + fs::read_to_string(TIMINGS_FILE_PATH) .map_err(|x| x.to_string()) - .and_then(Timings::try_from); - - match s { - Ok(timings) => timings, - Err(e) => { - eprintln!("{e}"); - Timings::default() - } - } + .and_then(Timings::try_from) + .unwrap_or_default() } /// Merge two sets of timings, overwriting `self` with `other` if present.