Crates.io | elvish |
lib.rs | elvish |
version | 0.1.1 |
source | src |
created_at | 2024-11-30 22:25:31.417583 |
updated_at | 2024-12-01 09:16:09.317207 |
description | Overengineered Advent of Code framework - not quite Santa's elves |
homepage | https://github.com/odilf/elvish |
repository | https://github.com/odilf/elvish |
max_upload_size | |
id | 1467020 |
size | 14,754 |
Overengineered Advent of Code framework for Rust - not quite Santa's elves.
elvish is a framework for writing your Advent of Code solutions with the least amount of boilerplate as possible.
This is my solution for day 1 of 2023 using elvish:
struct Solutions;
#[elvish::solution(day = 1, example = 142)]
fn part1(input: &str) -> u32 {
input
.lines()
.filter(|line| !line.is_empty())
.map(|line| {
let mut iter = line.chars().filter_map(|c| c.to_digit(10));
let a = iter.next().unwrap();
let b = iter.last().unwrap_or(a);
a * 10 + b
})
.sum()
}
#[elvish::solution(day = 1, example = 281)]
fn part2(input: &str) -> u32 {
let parse_slice = |slice: &str| {
let digits = [
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
];
let digit = slice.chars().next().unwrap().to_digit(10);
let named = || {
digits
.iter()
.enumerate()
.find(|(_, &digit)| slice.starts_with(digit))
.map(|(i, _)| i as u32 + 1)
};
digit.or_else(named)
};
input
.lines()
.filter(|line| !line.is_empty())
.map(|line| {
let mut iter = (0..line.len()).filter_map(|i| parse_slice(&line[i..]));
let a = iter.next().unwrap();
let b = iter.last().unwrap_or(a);
a * 10 + b
})
.sum()
}
elvish::example!(
part1: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
part2: "
two1nine
eightwothree
abcone2threexyz
xtwone3four
4nineeightseven2
zoneight234
7pqrstsixteen
"
);
Note: The examples directory has a full implementation of the 2023 advent of code using elvish, for reference.
Clone the template repo:
git clone https://github.com/odilf/elvish-template
If you want to use a remote, change the url:
git remote set-url origin your-repo-url
Then, edit the .env.example
by setting your session token and the year, and make it the primary .env
file.
mv .env.example .env
To use elvish, first add it as a dependency
cargo add elvish
Then, declare a Solutions
struct in the root of the crate:
// in main.rs
struct Solutions;
And add a main function:
// in main.rs
struct Solutions;
elvish::declare::run_fn!();
fn main() -> eyre::Result<()> {
tracing_subscriber::fmt().init();
dotenvy::dotenv()?;
elvish::run::<2023>(&elvish::available_days!(), run_day_part)?;
Ok(())
}
For the data fetching to work you need to add your session token and year in a .env
file (make sure to .gitignore
it).
SESSION_TOKEN=something
YEAR=202X
Finally, you need to add some cargo features to conditionally compile each day:
[features]
# You can add your own features here
# Detected by `elvish`
today = []
generate-docs = []
part1 = []
part2 = []
both = ["part1", "part2"]
1 = ["part1"]
2 = ["part2"]
b = ["both"]
day01 = []
day02 = []
day03 = []
day04 = []
day05 = []
day06 = []
day07 = []
day08 = []
day09 = []
day10 = []
day11 = []
day12 = []
day13 = []
day14 = []
day15 = []
day16 = []
day17 = []
day18 = []
day19 = []
day20 = []
day21 = []
day22 = []
day23 = []
day24 = []
day25 = []
d01 = ["day01"]
d02 = ["day02"]
d03 = ["day03"]
d04 = ["day04"]
d05 = ["day05"]
d06 = ["day06"]
d07 = ["day07"]
d08 = ["day08"]
d09 = ["day09"]
d10 = ["day10"]
d11 = ["day11"]
d12 = ["day12"]
d13 = ["day13"]
d14 = ["day14"]
d15 = ["day15"]
d16 = ["day16"]
d17 = ["day17"]
d18 = ["day18"]
d19 = ["day19"]
d20 = ["day20"]
d21 = ["day21"]
d22 = ["day22"]
d23 = ["day23"]
d24 = ["day24"]
d25 = ["day25"]
all = [
"day01",
"day02",
"day03",
"day04",
"day05",
"day06",
"day07",
"day08",
"day09",
"day10",
"day11",
"day12",
"day13",
"day14",
"day15",
"day16",
"day17",
"day18",
"day19",
"day20",
"day21",
"day22",
"day23",
"day24",
"day25",
]
By default it compiles a binary that includes all days and runs it. To specify a day, you can use feature flags:
cargo run --no-default-features --features "day01 part1" # or part2
or, to run both parts,
cargo run --no-default-features --features "day01 both"
and, as a shorthand
cargo run --no-default-features --features "d01 b" # p1/p2 for part1/2
elvish provides convinient macros to declare example inputs for 90% of cases:
#[elvish::solution(day = 1, example = 142)]
fn part1(input: &str) -> i32 {
// --snip--
}
#[elvish::solution(day = 1, example = 281)]
fn part2(input: &str) -> i32 {
// --snip--
}
elvish::example!(
part1: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
part2: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
);
elvish::example!("
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
");
elvish::example!(
part1: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
part1: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
part2: "
1abc2
pqr3stu8vwx
a1b2c3d4e5f
treb7uchet
",
);