Compare commits

..

10 Commits

12 changed files with 92 additions and 110 deletions

View File

@ -1,4 +1,4 @@
[alias] [alias]
scaffold = "run -p scaffold --release --quiet --" scaffold = "run -p scaffold --release --quiet --"
download = "run -p download --release --quiet --" download = "run -p download --release --quiet --"
solve = "run --release --bin" solve = "run --bin"

View File

@ -1,2 +1,2 @@
TOKEN=secret TOKEN=secret
YEAR=2022 YEAR=year

4
.gitignore vendored
View File

@ -11,6 +11,6 @@ target/
.env .env
# downloaded inputs # downloaded inputs
/src/inputs/* /data/inputs/*
!/src/inputs/.keep !/data/inputs/.keep

24
Cargo.lock generated
View File

@ -19,10 +19,7 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "aoc" name = "aoc"
version = "36.0.0" version = "46.0.0"
dependencies = [
"itertools",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
@ -105,19 +102,13 @@ checksum = "03d8c417d7a8cb362e0c37e5d815f5eb7c37f79ff93707329d5a194e42e54ca0"
[[package]] [[package]]
name = "download" name = "download"
version = "36.0.0" version = "46.0.0"
dependencies = [ dependencies = [
"dotenvy", "dotenvy",
"pico-args", "pico-args",
"reqwest", "reqwest",
] ]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.31" version = "0.8.31"
@ -360,15 +351,6 @@ version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e"
[[package]]
name = "itertools"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
dependencies = [
"either",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.5" version = "1.0.5"
@ -643,7 +625,7 @@ checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]] [[package]]
name = "scaffold" name = "scaffold"
version = "36.0.0" version = "46.0.0"
dependencies = [ dependencies = [
"dotenvy", "dotenvy",
"pico-args", "pico-args",

View File

@ -1,3 +1,15 @@
[workspace.package]
description = "template for advent of code"
readme = "README.md"
version = "46.0.0"
edition = "2021"
license = "MIT"
authors = ["Matej Janežič <janezic.mj@gmail.com>"]
repository = "https://github.com/janezicmatej/aoc-template.git"
[workspace]
members = ["utils/download", "utils/scaffold"]
[package] [package]
name = "aoc" name = "aoc"
description.workspace = true description.workspace = true
@ -9,19 +21,4 @@ authors.workspace = true
repository.workspace = true repository.workspace = true
[dependencies] [dependencies]
# many cool stuff for iterators
itertools = "0.12.0"
[workspace]
members = ["utils/download", "utils/scaffold"]
[workspace.package]
description = "template for advent of code"
readme = "README.md"
version = "36.0.0"
edition = "2021"
license = "MIT"
authors = ["Matej Janežič <janezic.mj@gmail.com>"]
repository = "https://github.com/janezicmatej/aoc-template.git"

View File

@ -5,15 +5,16 @@
## Project overview ## Project overview
### Project structure ### Project structure
- `data/` :
- `examples/`: example files go here; you can push this as test are run in ci
- `inputs/`: this directory is gitignored, input files go here
- `src/` : - `src/` :
- `bin/`: - `bin/`:
- `<day>.rs`: solution files - `<day>.rs`: solution files
- `inputs/`: this directory is gitignored, input files go here - `lib.rs`: library entrypoint, reusable code goes here
- `examples/`: example files go here; you can push this as test are run in ci - `template.rs`: contains template code
- `utils/`: utils files go here
- `lib.rs`: contains framework code
- `.env.example`: example dotenv file
- `utils/`: binary packages with convenience scripts structured using cargo workspaces - `utils/`: binary packages with convenience scripts structured using cargo workspaces
- `.env.example`: example dotenv file
### Cli ### Cli
- `cargo scaffold <day>`: prepare solution files for `day` - `cargo scaffold <day>`: prepare solution files for `day`

View File

@ -1,49 +1 @@
/* pub mod template;
* This file contains template code.
* There is no need to edit this file unless you want to change template functionality.
* Prefer `./helpers.rs` if you want to extract code from your solutions.
*/
use std::env;
use std::fs;
pub const ANSI_ITALIC: &str = "\x1b[3m";
pub const ANSI_BOLD: &str = "\x1b[1m";
pub const ANSI_RESET: &str = "\x1b[0m";
#[macro_export]
macro_rules! solve {
($part:expr, $solver:ident, $input:expr) => {{
use aoc::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET};
use std::fmt::Display;
use std::time::Instant;
fn print_result<T: Display>(func: impl FnOnce(&str) -> Option<T>, input: &str) {
let timer = Instant::now();
let result = func(input);
let elapsed = timer.elapsed();
match result {
Some(result) => {
println!(
"{} {}(elapsed: {:.2?}){}",
result, ANSI_ITALIC, elapsed, ANSI_RESET
);
}
None => {
println!("not solved.")
}
}
}
println!("🎄 {}Part {}{} 🎄", ANSI_BOLD, $part, ANSI_RESET);
print_result($solver, $input);
}};
}
pub fn read_file(folder: &str, day: u8) -> String {
let cwd = env::current_dir().unwrap();
let filepath = cwd.join("src").join(folder).join(format!("{day:02}.txt"));
let f = fs::read_to_string(filepath);
f.expect("could not open input file").trim().to_string()
}

56
src/template.rs Normal file
View File

@ -0,0 +1,56 @@
/*
* This file contains template code.
* There is no need to edit this file unless you want to change template functionality.
*/
use std::env;
use std::fs;
pub const ANSI_ITALIC: &str = "\x1b[3m";
pub const ANSI_BOLD: &str = "\x1b[1m";
pub const ANSI_RESET: &str = "\x1b[0m";
use std::fmt::Display;
use std::time::Duration;
use std::time::Instant;
fn time_solution<T>(func: impl FnOnce(&str) -> Option<T>, input: &str) -> Option<(T, Duration)> {
let timer = Instant::now();
let result = func(input);
let elapsed = timer.elapsed();
result.map(|result| (result, elapsed))
}
pub fn print_result<T: Display>(func: impl FnOnce(&str) -> Option<T>, input: &str, part: u8) {
match time_solution(func, input) {
Some((result, elapsed)) => {
println!(
"{}Part {}{}: {} {}(elapsed: {:.2?}){}",
ANSI_BOLD, part, ANSI_RESET, result, ANSI_ITALIC, elapsed, ANSI_RESET
);
}
None => {
println!("{}Part {}{}: not solved.", ANSI_BOLD, part, ANSI_RESET)
}
}
}
#[macro_export]
macro_rules! solution {
($day:expr) => {
fn main() {
let input = aoc::template::read_file("inputs", $day);
aoc::template::print_result(part_one, &input, 1);
aoc::template::print_result(part_two, &input, 2);
}
};
}
#[must_use]
pub fn read_file(folder: &str, day: u8) -> String {
let cwd = env::current_dir().unwrap();
let filepath = cwd.join("data").join(folder).join(format!("{day:02}.txt"));
let f = fs::read_to_string(filepath);
f.expect("could not open input file").trim().to_string()
}

View File

@ -39,7 +39,7 @@ fn main() {
.text() .text()
.unwrap(); .unwrap();
let input_path = format!("src/inputs/{day_padded}.txt"); let input_path = format!("data/inputs/{day_padded}.txt");
let mut file = match OpenOptions::new() let mut file = match OpenOptions::new()
.write(true) .write(true)
.create(true) .create(true)

View File

@ -11,26 +11,23 @@ use std::{
const MODULE_TEMPLATE: &str = r#"pub fn part_one(input: &str) -> Option<u32> { const MODULE_TEMPLATE: &str = r#"pub fn part_one(input: &str) -> Option<u32> {
None None
} }
pub fn part_two(input: &str) -> Option<u32> { pub fn part_two(input: &str) -> Option<u32> {
None None
} }
fn main() {
let input = &aoc::read_file("inputs", DAY); aoc::solution!(DAY);
aoc::solve!(1, part_one, input);
aoc::solve!(2, part_two, input);
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_part_one() { fn test_part_one() {
let input = aoc::read_file("examples", DAY); assert_eq!(part_one(&aoc::template::read_file("examples", DAY)), None);
assert_eq!(part_one(&input), None);
} }
#[test] #[test]
fn test_part_two() { fn test_part_two() {
let input = aoc::read_file("examples", DAY); assert_eq!(part_two(&aoc::template::read_file("examples", DAY)), None);
assert_eq!(part_two(&input), None);
} }
} }
"#; "#;
@ -59,8 +56,8 @@ fn main() {
let day_padded = format!("{day:02}"); let day_padded = format!("{day:02}");
let input_path = format!("src/inputs/{day_padded}.txt"); let input_path = format!("data/inputs/{day_padded}.txt");
let example_path = format!("src/examples/{day_padded}.txt"); let example_path = format!("data/examples/{day_padded}.txt");
let module_path = format!("src/bin/{day_padded}.rs"); let module_path = format!("src/bin/{day_padded}.rs");
let mut file = match safe_create_file(&module_path) { let mut file = match safe_create_file(&module_path) {
@ -102,8 +99,5 @@ fn main() {
} }
println!("---"); println!("---");
println!( println!("Type `cargo solve {}` to run your solution.", &day_padded);
"🎄 Type `cargo solve {}` to run your solution.",
&day_padded
);
} }