1
Fork 0

Add missing documentation lints.

This commit is contained in:
Bauke 2024-01-14 22:04:10 +01:00
parent 1030c6f60f
commit 3c9bfef10a
Signed by: Bauke
GPG Key ID: C1C0F29952BCF558
43 changed files with 356 additions and 2 deletions

View File

@ -27,5 +27,9 @@ rand = "0.8.5"
regex = "1.10.2" regex = "1.10.2"
ureq = { version = "2.8.0", features = ["cookie", "cookie_store"] } ureq = { version = "2.8.0", features = ["cookie", "cookie_store"] }
[lints.clippy]
missing_docs_in_private_items = "warn"
[lints.rust] [lints.rust]
missing_docs = "warn"
unsafe_code = "forbid" unsafe_code = "forbid"

View File

@ -15,6 +15,7 @@ pub mod utilities;
pub mod year_2020; pub mod year_2020;
pub mod year_2021; pub mod year_2021;
/// CLI arguments.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[clap(about, author, version)] #[clap(about, author, version)]
pub struct Args { pub struct Args {
@ -22,7 +23,7 @@ pub struct Args {
pub filter: Option<String>, pub filter: Option<String>,
} }
pub fn main() -> Result<()> { fn main() -> Result<()> {
color_eyre::install()?; color_eyre::install()?;
let args = Args::parse(); let args = Args::parse();

View File

@ -1,53 +1,72 @@
//! Functionality for [`Day`]s and [`Solution`]s.
use {color_eyre::Result, derivative::Derivative}; use {color_eyre::Result, derivative::Derivative};
/// The information for an advent day of a given year.
#[derive(Debug)] #[derive(Debug)]
pub struct Day { pub struct Day {
/// The advent day.
pub day: i32, pub day: i32,
/// The year for the advent.
pub year: i32, pub year: i32,
} }
impl Day { impl Day {
/// Create a new [`Day`] from a given day and year.
pub fn new(day: i32, year: i32) -> Self { pub fn new(day: i32, year: i32) -> Self {
Self { day, year } Self { day, year }
} }
/// Return the filter string as `YEAR::DAY` for this day.
pub fn filter_string(&self) -> String { pub fn filter_string(&self) -> String {
format!("{}::{:02}", self.year, self.day) format!("{}::{:02}", self.year, self.day)
} }
/// Return the link for this day on the Advent of Code website.
pub fn day_link(&self) -> String { pub fn day_link(&self) -> String {
format!("{}/day/{}", self.year_link(), self.day) format!("{}/day/{}", self.year_link(), self.day)
} }
/// Return the link for this year on the Advent of Code website.
pub fn year_link(&self) -> String { pub fn year_link(&self) -> String {
format!("https://adventofcode.com/{}", self.year) format!("https://adventofcode.com/{}", self.year)
} }
} }
/// Function type alias for the expected input and outputs of a day.
pub type DayFunction = fn(input: &str) -> Result<String>; pub type DayFunction = fn(input: &str) -> Result<String>;
/// The solution to one of the advent calendar days.
#[derive(Derivative)] #[derive(Derivative)]
#[derivative(Debug)] #[derivative(Debug)]
pub struct Solution { pub struct Solution {
/// Which day the solution applies to.
pub day: Day, pub day: Day,
/// The calculated result for part one.
pub part_1: String, pub part_1: String,
/// The calculated result for part two.
pub part_2: String, pub part_2: String,
/// The expected result for part one (for validation).
pub part_1_expected: String, pub part_1_expected: String,
/// The expected result for part two (for validation).
pub part_2_expected: String, pub part_2_expected: String,
/// The function for part one.
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
pub part_1_fn: DayFunction, pub part_1_fn: DayFunction,
/// The function for part two.
#[derivative(Debug = "ignore")] #[derivative(Debug = "ignore")]
pub part_2_fn: DayFunction, pub part_2_fn: DayFunction,
} }
impl Solution { impl Solution {
/// Create a new [`Solution`] with a given [`Day`] and two [`DayFunction`]s.
pub fn new(day: Day, part_1_fn: DayFunction, part_2_fn: DayFunction) -> Self { pub fn new(day: Day, part_1_fn: DayFunction, part_2_fn: DayFunction) -> Self {
Self { Self {
day, day,
@ -60,6 +79,7 @@ impl Solution {
} }
} }
/// Helper function to add the expected results for both parts.
pub fn with_expected<A: std::fmt::Display, B: std::fmt::Display>( pub fn with_expected<A: std::fmt::Display, B: std::fmt::Display>(
self, self,
part_1_expected: A, part_1_expected: A,
@ -72,6 +92,8 @@ impl Solution {
} }
} }
/// Run the [`DayFunction`]s for this [`Solution`] and put the results in
/// their respective fields.
pub fn solve(self, data: &str) -> Result<Self> { pub fn solve(self, data: &str) -> Result<Self> {
let (part_1, part_2) = ((self.part_1_fn)(data)?, (self.part_2_fn)(data)?); let (part_1, part_2) = ((self.part_1_fn)(data)?, (self.part_2_fn)(data)?);
Ok(Self { Ok(Self {

View File

@ -1,14 +1,20 @@
//! The templating code for [`askama`].
use askama::Template; use askama::Template;
use crate::solution::Solution; use crate::solution::Solution;
/// The HTML template for all solutions.
#[derive(Template)] #[derive(Template)]
#[template(path = "solutions.html")] #[template(path = "solutions.html")]
pub struct SolutionsTemplate { pub struct SolutionsTemplate {
/// All solutions grouped by year.
pub years: Vec<Vec<Solution>>, pub years: Vec<Vec<Solution>>,
} }
/// Custom [`askama`] filters.
pub mod filters { pub mod filters {
/// See [`crate::utilities::random_emoji`].
pub fn random_emoji(s: &str) -> askama::Result<String> { pub fn random_emoji(s: &str) -> askama::Result<String> {
Ok(format!("{s} {}", crate::utilities::random_emoji())) Ok(format!("{s} {}", crate::utilities::random_emoji()))
} }

View File

@ -1,3 +1,5 @@
//! Miscellaneous utility functions.
use std::{ use std::{
fs::{create_dir_all, read_to_string, write}, fs::{create_dir_all, read_to_string, write},
path::PathBuf, path::PathBuf,
@ -7,10 +9,12 @@ use {color_eyre::Result, dialoguer::Password, rand::seq::IteratorRandom};
use crate::{solution::Solution, year_2020, year_2021}; use crate::{solution::Solution, year_2020, year_2021};
/// Shorthand to get the solutions for all years.
pub fn get_solutions() -> Vec<Vec<Solution>> { pub fn get_solutions() -> Vec<Vec<Solution>> {
vec![year_2020::get_solutions(), year_2021::get_solutions()] vec![year_2020::get_solutions(), year_2021::get_solutions()]
} }
/// Return a random emoji from the [`emojis::Group::AnimalsAndNature`] set.
pub fn random_emoji() -> String { pub fn random_emoji() -> String {
emojis::iter() emojis::iter()
.filter(|emoji| emoji.group() == emojis::Group::AnimalsAndNature) .filter(|emoji| emoji.group() == emojis::Group::AnimalsAndNature)
@ -19,6 +23,8 @@ pub fn random_emoji() -> String {
.to_string() .to_string()
} }
/// Get the Advent of Code session cookie from an existing file or start an
/// interactive prompt to ask the user for it.
pub fn session_cookie() -> Result<String> { pub fn session_cookie() -> Result<String> {
let session_cookie_path = PathBuf::from("aoc/session.txt"); let session_cookie_path = PathBuf::from("aoc/session.txt");
@ -33,6 +39,8 @@ pub fn session_cookie() -> Result<String> {
} }
} }
/// Write the given contents to a path, ensuring the parent directory for the
/// location exists.
pub fn write_file(path: PathBuf, contents: String) -> Result<String> { pub fn write_file(path: PathBuf, contents: String) -> Result<String> {
create_dir_all(path.parent().unwrap())?; create_dir_all(path.parent().unwrap())?;
write(path, &contents)?; write(path, &contents)?;

View File

@ -1,12 +1,17 @@
//! Day 01 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 01 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(1, 2020), part_1, part_2) Solution::new(Day::new(1, 2020), part_1, part_2)
.with_expected(605364, 128397680) .with_expected(605364, 128397680)
} }
/// The target sum that two entries need to add up to.
const TARGET: i32 = 2020; const TARGET: i32 = 2020;
/// Parse the input lines into integers.
fn parse_lines(input: &str) -> Vec<i32> { fn parse_lines(input: &str) -> Vec<i32> {
input input
.lines() .lines()
@ -14,6 +19,7 @@ fn parse_lines(input: &str) -> Vec<i32> {
.collect() .collect()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
parse_lines(input) parse_lines(input)
@ -26,6 +32,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok( Ok(
parse_lines(input) parse_lines(input)

View File

@ -1,17 +1,26 @@
//! Day 02 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 02 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(2, 2020), part_1, part_2).with_expected(638, 699) Solution::new(Day::new(2, 2020), part_1, part_2).with_expected(638, 699)
} }
/// The data for each line of the puzzle input.
#[derive(Debug)] #[derive(Debug)]
struct Item { struct Item {
/// The minimum amount of times the letter has to be in the password.
min: usize, min: usize,
/// The maximum amount of times the letter has to be in the password.
max: usize, max: usize,
/// The letter that must be in the password.
letter: String, letter: String,
/// The password to check.
password: String, password: String,
} }
/// Parse all the [`Item`]s inside the puzzle input.
fn parse_items(input: &str) -> Vec<Item> { fn parse_items(input: &str) -> Vec<Item> {
let mut items = vec![]; let mut items = vec![];
@ -32,6 +41,7 @@ fn parse_items(input: &str) -> Vec<Item> {
items items
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
parse_items(input) parse_items(input)
@ -43,6 +53,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok( Ok(
parse_items(input) parse_items(input)

View File

@ -1,10 +1,15 @@
//! Day 03 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 03 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(3, 2020), part_1, part_2) Solution::new(Day::new(3, 2020), part_1, part_2)
.with_expected(198, 5140884672_i64) .with_expected(198, 5140884672_i64)
} }
/// Generic solver that takes in a horizontal and vertical movement for the
/// slope.
fn solve(data: &str, (horizontal, vertical): (usize, usize)) -> usize { fn solve(data: &str, (horizontal, vertical): (usize, usize)) -> usize {
let line_length = data.find('\n').unwrap(); let line_length = data.find('\n').unwrap();
let mut result = 0; let mut result = 0;
@ -28,10 +33,12 @@ fn solve(data: &str, (horizontal, vertical): (usize, usize)) -> usize {
result result
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok(solve(input, (3, 1)).to_string()) Ok(solve(input, (3, 1)).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok( Ok(
[(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)] [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]

View File

@ -1,21 +1,34 @@
//! Day 04 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 04 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(4, 2020), part_1, part_2).with_expected(237, 172) Solution::new(Day::new(4, 2020), part_1, part_2).with_expected(237, 172)
} }
/// The passport puzzle input.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Passport { struct Passport {
/// Birth year.
byr: Option<String>, byr: Option<String>,
/// Issue year.
iyr: Option<String>, iyr: Option<String>,
/// Expiration year.
eyr: Option<String>, eyr: Option<String>,
/// Height.
hgt: Option<String>, hgt: Option<String>,
/// Hair color.
hcl: Option<String>, hcl: Option<String>,
/// Eye color.
ecl: Option<String>, ecl: Option<String>,
/// Passport ID.
pid: Option<String>, pid: Option<String>,
/// Country ID.
cid: Option<String>, cid: Option<String>,
} }
/// Parse the puzzle input into a list of passports.
fn parse_passports(input: &str) -> Vec<Passport> { fn parse_passports(input: &str) -> Vec<Passport> {
let mut passports = vec![]; let mut passports = vec![];
let blank = Passport { let blank = Passport {
@ -59,6 +72,7 @@ fn parse_passports(input: &str) -> Vec<Passport> {
passports passports
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
parse_passports(input) parse_passports(input)
@ -77,6 +91,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let hcl_regex = Regex::new("^#[a-fA-F0-9]{6}$").unwrap(); let hcl_regex = Regex::new("^#[a-fA-F0-9]{6}$").unwrap();
let pid_regex = Regex::new("^[0-9]{9}$").unwrap(); let pid_regex = Regex::new("^[0-9]{9}$").unwrap();

View File

@ -1,12 +1,20 @@
//! Day 05 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 05 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(5, 2020), part_1, part_2).with_expected(850, 599) Solution::new(Day::new(5, 2020), part_1, part_2).with_expected(850, 599)
} }
/// The maximum range of rows.
const MAX_ROW_RANGE: i32 = 128; const MAX_ROW_RANGE: i32 = 128;
/// The maximum range of columns.
const MAX_COLUMN_RANGE: i32 = 8; const MAX_COLUMN_RANGE: i32 = 8;
/// Calculate the row and column from the input according to the puzzle's
/// instructions.
fn calculate_row_and_column(input: &str) -> (i32, i32) { fn calculate_row_and_column(input: &str) -> (i32, i32) {
let mut row_range = 0..MAX_ROW_RANGE; let mut row_range = 0..MAX_ROW_RANGE;
let mut column_range = 0..MAX_COLUMN_RANGE; let mut column_range = 0..MAX_COLUMN_RANGE;
@ -40,10 +48,12 @@ fn calculate_row_and_column(input: &str) -> (i32, i32) {
(row_range.start, column_range.start) (row_range.start, column_range.start)
} }
/// Calculate the sead ID by multiplying the row by 8 and adding the column.
fn calculate_seat_id((row, column): (i32, i32)) -> i32 { fn calculate_seat_id((row, column): (i32, i32)) -> i32 {
(row * 8) + column (row * 8) + column
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
input input
@ -56,6 +66,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let seat_ids = input let seat_ids = input
.lines() .lines()

View File

@ -1,9 +1,13 @@
//! Day 06 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 06 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(6, 2020), part_1, part_2).with_expected(6437, 3229) Solution::new(Day::new(6, 2020), part_1, part_2).with_expected(6437, 3229)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
input input
@ -20,6 +24,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok( Ok(
input input

View File

@ -1,11 +1,16 @@
//! Day 07 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 07 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(7, 2020), part_1, part_2).with_expected(169, 82372) Solution::new(Day::new(7, 2020), part_1, part_2).with_expected(169, 82372)
} }
/// The target bag to look for.
const TARGET: &str = "shiny gold"; const TARGET: &str = "shiny gold";
/// Parse the bags from the puzzle input.
fn parse_bags(input: &str) -> Vec<(&str, Vec<(usize, &str)>)> { fn parse_bags(input: &str) -> Vec<(&str, Vec<(usize, &str)>)> {
let mut bags = vec![]; let mut bags = vec![];
@ -29,6 +34,7 @@ fn parse_bags(input: &str) -> Vec<(&str, Vec<(usize, &str)>)> {
bags bags
} }
/// Find out which bags can hold the [`TARGET`] bag.
fn can_hold_target_bag<'a>( fn can_hold_target_bag<'a>(
target: &'a str, target: &'a str,
bags: &[(&'a str, Vec<(usize, &'a str)>)], bags: &[(&'a str, Vec<(usize, &'a str)>)],
@ -44,6 +50,7 @@ fn can_hold_target_bag<'a>(
can_hold can_hold
} }
/// Find out how many bags are required to be inside the [`TARGET`] bag.
fn target_bag_holds_amount<'a>( fn target_bag_holds_amount<'a>(
target: &'a str, target: &'a str,
bags: &[(&'a str, Vec<(usize, &'a str)>)], bags: &[(&'a str, Vec<(usize, &'a str)>)],
@ -64,6 +71,7 @@ fn target_bag_holds_amount<'a>(
count count
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
can_hold_target_bag(TARGET, &parse_bags(input)) can_hold_target_bag(TARGET, &parse_bags(input))
@ -74,6 +82,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok(target_bag_holds_amount("shiny gold", &parse_bags(input)).to_string()) Ok(target_bag_holds_amount("shiny gold", &parse_bags(input)).to_string())
} }

View File

@ -1,13 +1,20 @@
//! Day 08 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 08 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(8, 2020), part_1, part_2).with_expected(1814, 1056) Solution::new(Day::new(8, 2020), part_1, part_2).with_expected(1814, 1056)
} }
/// The possible operations an instruction can perform.
#[derive(Debug, Eq, PartialEq, Hash, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Clone)]
enum Operation { enum Operation {
/// Increase or decrease the accumulator.
Acc, Acc,
/// Jump to a new instruction.
Jmp, Jmp,
/// Do nothing, no operation.
Nop, Nop,
} }
@ -22,12 +29,17 @@ impl From<&str> for Operation {
} }
} }
/// Type alias for the arguments of operations.
type Argument = i32; type Argument = i32;
/// A single instruction.
#[derive(Debug, Eq, PartialEq, Hash, Clone)] #[derive(Debug, Eq, PartialEq, Hash, Clone)]
struct Instruction { struct Instruction {
/// The line the instruction was parsed from, used for debugging.
line: usize, line: usize,
/// The operation to perform.
op: Operation, op: Operation,
/// The argument for the operation.
arg: Argument, arg: Argument,
} }
@ -42,6 +54,8 @@ impl From<(usize, &str)> for Instruction {
} }
} }
/// Execute the list of instructions and return the accumulator and whether or
/// not an infinite loop was encountered.
fn execute(instructions: &[Instruction]) -> (i32, bool) { fn execute(instructions: &[Instruction]) -> (i32, bool) {
let mut seen_instructions = HashSet::new(); let mut seen_instructions = HashSet::new();
@ -69,14 +83,17 @@ fn execute(instructions: &[Instruction]) -> (i32, bool) {
(accumulator, encountered_infinite_loop) (accumulator, encountered_infinite_loop)
} }
/// Parse the list of instructions from the puzzle input.
fn parse_instructions(input: &str) -> Vec<Instruction> { fn parse_instructions(input: &str) -> Vec<Instruction> {
input.lines().enumerate().map(Into::into).collect() input.lines().enumerate().map(Into::into).collect()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok(execute(&parse_instructions(input)).0.to_string()) Ok(execute(&parse_instructions(input)).0.to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let instructions = parse_instructions(input); let instructions = parse_instructions(input);
let mut part_2_result = None; let mut part_2_result = None;

View File

@ -1,12 +1,17 @@
//! Day 09 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 09 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(9, 2020), part_1, part_2) Solution::new(Day::new(9, 2020), part_1, part_2)
.with_expected(22477624, 2980044) .with_expected(22477624, 2980044)
} }
/// The amount of numbers to consider as the preamble.
const PREAMBLE_LENGTH: usize = 25; const PREAMBLE_LENGTH: usize = 25;
/// Parse the puzzle input into a list of numbers.
fn parse_numbers(input: &str) -> Vec<usize> { fn parse_numbers(input: &str) -> Vec<usize> {
input input
.lines() .lines()
@ -14,6 +19,7 @@ fn parse_numbers(input: &str) -> Vec<usize> {
.collect() .collect()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let numbers = parse_numbers(input); let numbers = parse_numbers(input);
let mut result_one = 0; let mut result_one = 0;
@ -47,6 +53,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(result_one.to_string()) Ok(result_one.to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let numbers = parse_numbers(input); let numbers = parse_numbers(input);
let result_one = part_1(input)?; let result_one = part_1(input)?;

View File

@ -1,10 +1,14 @@
//! Day 10 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 10 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(10, 2020), part_1, part_2) Solution::new(Day::new(10, 2020), part_1, part_2)
.with_expected(2368, 1727094849536_i64) .with_expected(2368, 1727094849536_i64)
} }
/// Parse the puzzle input and return the intervals and streaks of the adapters.
fn parse_numbers(input: &str) -> (HashMap<usize, i32>, HashMap<i32, u32>) { fn parse_numbers(input: &str) -> (HashMap<usize, i32>, HashMap<i32, u32>) {
let mut numbers = input let mut numbers = input
.lines() .lines()
@ -35,11 +39,13 @@ fn parse_numbers(input: &str) -> (HashMap<usize, i32>, HashMap<i32, u32>) {
(intervals, streaks) (intervals, streaks)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let (intervals, _) = parse_numbers(input); let (intervals, _) = parse_numbers(input);
Ok((intervals.get(&1).unwrap() * intervals.get(&3).unwrap()).to_string()) Ok((intervals.get(&1).unwrap() * intervals.get(&3).unwrap()).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let (_, streaks) = parse_numbers(input); let (_, streaks) = parse_numbers(input);
Ok( Ok(

View File

@ -1,14 +1,24 @@
//! [`Grid`], [`Cell`] and [`Ruleset`] code.
/// The different types of cell available in the [`Grid`].
#[derive(Debug, Eq, PartialEq, Clone)] #[derive(Debug, Eq, PartialEq, Clone)]
pub enum Cell { pub enum Cell {
/// The cell is an edge of the grid.
Edge, Edge,
/// The cell is a floor tile.
Floor, Floor,
/// The cell is an empty seat.
Empty, Empty,
/// The cell is an occupied seat.
Occupied, Occupied,
} }
/// The different rulesets for part one and two.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum Ruleset { pub enum Ruleset {
/// The ruleset for part one.
PartOne, PartOne,
/// The ruleset for part two.
PartTwo, PartTwo,
} }
@ -24,16 +34,23 @@ impl From<char> for Cell {
} }
} }
/// The grid of seats.
#[derive(Debug)] #[derive(Debug)]
pub struct Grid { pub struct Grid {
/// The length of lines from the puzzle input.
pub line_length: isize, pub line_length: isize,
/// The amount of [`Cell`]s that are occupied.
pub occupied_cell_count: usize, pub occupied_cell_count: usize,
/// How tolerant people are for seats to become empty.
pub occupied_cell_tolerance: usize, pub occupied_cell_tolerance: usize,
/// The list of [`Cell`]s.
pub cells: Vec<Cell>, pub cells: Vec<Cell>,
/// Which [`Ruleset`] is being used.
pub ruleset: Ruleset, pub ruleset: Ruleset,
} }
impl Grid { impl Grid {
/// Create a new grid based on the puzzle input and which [`Ruleset`] to use.
pub fn new(input: &str, ruleset: Ruleset) -> Self { pub fn new(input: &str, ruleset: Ruleset) -> Self {
let line_length = input.find('\n').unwrap() + 2; let line_length = input.find('\n').unwrap() + 2;
@ -62,6 +79,7 @@ impl Grid {
} }
} }
/// Simulate a single step and return the new list of [`Cell`]s.
pub fn simulate_step(&self) -> Vec<Cell> { pub fn simulate_step(&self) -> Vec<Cell> {
let mut cells = self.cells.clone(); let mut cells = self.cells.clone();
@ -137,11 +155,12 @@ impl Grid {
cells cells
} }
/// Count the amount of [`Cell`]s matching a given target.
pub fn count_cells(&self, target: Cell) -> usize { pub fn count_cells(&self, target: Cell) -> usize {
self.cells.iter().filter(|cell| cell == &&target).count() self.cells.iter().filter(|cell| cell == &&target).count()
} }
// Useful for debugging. /// Draw the grid, used for debugging.
pub fn _draw(&self) -> String { pub fn _draw(&self) -> String {
let mut result = String::new(); let mut result = String::new();
for (index, cell) in self.cells.iter().enumerate() { for (index, cell) in self.cells.iter().enumerate() {

View File

@ -1,13 +1,17 @@
//! Day 11 of 2020.
use crate::prelude::*; use crate::prelude::*;
mod grid; mod grid;
use grid::*; use grid::*;
/// Get the solution for day 11 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(11, 2020), part_1, part_2).with_expected(2243, 2027) Solution::new(Day::new(11, 2020), part_1, part_2).with_expected(2243, 2027)
} }
/// Calculate the result based on the ruleset.
fn calculate(input: &str, ruleset: Ruleset) -> usize { fn calculate(input: &str, ruleset: Ruleset) -> usize {
let mut grid = Grid::new(input, ruleset); let mut grid = Grid::new(input, ruleset);
@ -28,10 +32,12 @@ fn calculate(input: &str, ruleset: Ruleset) -> usize {
previous_occupied_cell_count.unwrap() previous_occupied_cell_count.unwrap()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok(calculate(input, Ruleset::PartOne).to_string()) Ok(calculate(input, Ruleset::PartOne).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok(calculate(input, Ruleset::PartTwo).to_string()) Ok(calculate(input, Ruleset::PartTwo).to_string())
} }

View File

@ -1,11 +1,21 @@
//! [`Action`] and [`Instruction`] code.
/// The list of actions the ship can take.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum Action { pub enum Action {
/// Move North by a given value.
North, North,
/// Move East by a given value.
East, East,
/// Move South by a given value.
South, South,
/// Move West by a given value.
West, West,
/// Turn left by a given number of degrees.
Left, Left,
/// Turn right by a given number of degrees.
Right, Right,
/// Move forward by a given value in the direction the ship is facing.
Forward, Forward,
} }
@ -24,9 +34,12 @@ impl From<char> for Action {
} }
} }
/// The combination of an [`Action`] and the value for it.
#[derive(Debug)] #[derive(Debug)]
pub struct Instruction { pub struct Instruction {
/// Which action to take.
pub action: Action, pub action: Action,
/// The amount to use for that action.
pub value: i32, pub value: i32,
} }

View File

@ -1,17 +1,22 @@
//! Day 12 of 2020.
use crate::prelude::*; use crate::prelude::*;
mod extra; mod extra;
use extra::*; use extra::*;
/// Get the solution for day 12 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(12, 2020), part_1, part_2).with_expected(1496, 63843) Solution::new(Day::new(12, 2020), part_1, part_2).with_expected(1496, 63843)
} }
/// Parse the list of [`Instruction`]s based on the puzzle input.
fn parse_instructions(input: &str) -> Vec<Instruction> { fn parse_instructions(input: &str) -> Vec<Instruction> {
input.lines().map(Into::into).collect() input.lines().map(Into::into).collect()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let instructions = parse_instructions(input); let instructions = parse_instructions(input);
let mut horizontal = 0; let mut horizontal = 0;
@ -48,6 +53,7 @@ fn part_1(input: &str) -> Result<String> {
Ok((horizontal.abs() + vertical.abs()).to_string()) Ok((horizontal.abs() + vertical.abs()).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let instructions = parse_instructions(input); let instructions = parse_instructions(input);

View File

@ -1,10 +1,14 @@
//! Day 13 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 13 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(13, 2020), part_1, part_2) Solution::new(Day::new(13, 2020), part_1, part_2)
.with_expected(1895, 840493039281088_i64) .with_expected(1895, 840493039281088_i64)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let mut lines = input.lines(); let mut lines = input.lines();
@ -33,6 +37,7 @@ fn part_1(input: &str) -> Result<String> {
Ok((earliest_bus * difference).to_string()) Ok((earliest_bus * difference).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
// Skip the first line, as it isn't used for the second part of the puzzle. // Skip the first line, as it isn't used for the second part of the puzzle.
let input = input.lines().nth(1).unwrap(); let input = input.lines().nth(1).unwrap();

View File

@ -1,14 +1,18 @@
//! Day 14 of 2020.
use crate::prelude::*; use crate::prelude::*;
mod operation; mod operation;
use operation::*; use operation::*;
/// Get the solution for day 14 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(14, 2020), part_1, part_2) Solution::new(Day::new(14, 2020), part_1, part_2)
.with_expected(9967721333886_i64, 4355897790573_i64) .with_expected(9967721333886_i64, 4355897790573_i64)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let operations = input.lines().map(Into::into).collect::<Vec<Operation>>(); let operations = input.lines().map(Into::into).collect::<Vec<Operation>>();
@ -35,6 +39,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(memory.values().sum::<i64>().to_string()) Ok(memory.values().sum::<i64>().to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let operations = input.lines().map(Into::into).collect::<Vec<Operation>>(); let operations = input.lines().map(Into::into).collect::<Vec<Operation>>();
@ -95,6 +100,7 @@ fn part_2(input: &str) -> Result<String> {
Ok(memory.values().sum::<i64>().to_string()) Ok(memory.values().sum::<i64>().to_string())
} }
/// Loop over the input mask and replace any floating bits.
fn combine(input: String) -> Vec<String> { fn combine(input: String) -> Vec<String> {
let mut result = vec![]; let mut result = vec![];

View File

@ -1,6 +1,11 @@
//! [`Operation`] parsing code.
/// The list of operations to perform.
#[derive(Debug)] #[derive(Debug)]
pub enum Operation { pub enum Operation {
/// Set the mask using a given string.
SetMask(String), SetMask(String),
/// Set the memory of an address to a given value.
SetMemory(i64, i64), SetMemory(i64, i64),
} }

View File

@ -1,9 +1,13 @@
//! Day 15 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 15 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(15, 2020), part_1, part_2).with_expected(441, 10613991) Solution::new(Day::new(15, 2020), part_1, part_2).with_expected(441, 10613991)
} }
/// Solve the puzzle for a given target.
fn solve(input: &str, target: usize) -> isize { fn solve(input: &str, target: usize) -> isize {
let mut numbers = HashMap::new(); let mut numbers = HashMap::new();
let mut previous_number = (0, (0, 0)); let mut previous_number = (0, (0, 0));
@ -33,10 +37,12 @@ fn solve(input: &str, target: usize) -> isize {
*numbers.iter().max_by(|a, b| a.1 .1.cmp(&b.1 .1)).unwrap().0 *numbers.iter().max_by(|a, b| a.1 .1.cmp(&b.1 .1)).unwrap().0
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok(solve(input, 2020).to_string()) Ok(solve(input, 2020).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok(solve(input, 30000000).to_string()) Ok(solve(input, 30000000).to_string())
} }

View File

@ -1,10 +1,14 @@
//! Day 16 of 2020.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 16 of 2020.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(16, 2020), part_1, part_2) Solution::new(Day::new(16, 2020), part_1, part_2)
.with_expected(26980, 3021381607403_i64) .with_expected(26980, 3021381607403_i64)
} }
/// Solve the puzzle.
fn solve(input: &str, return_part_1: bool) -> Result<String> { fn solve(input: &str, return_part_1: bool) -> Result<String> {
let mut parts = input.trim().split("\n\n"); let mut parts = input.trim().split("\n\n");
let mut ranges = vec![]; let mut ranges = vec![];
@ -133,10 +137,12 @@ fn solve(input: &str, return_part_1: bool) -> Result<String> {
Ok(result_two) Ok(result_two)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
solve(input, true) solve(input, true)
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
solve(input, false) solve(input, false)
} }

View File

@ -1,3 +1,5 @@
//! Solutions for Advent of Code 2020.
use crate::solution::Solution; use crate::solution::Solution;
mod day_01; mod day_01;
@ -17,6 +19,7 @@ mod day_14;
mod day_15; mod day_15;
mod day_16; mod day_16;
/// Get all the solutions of 2020 as a [`Vec<Solution>`].
pub fn get_solutions() -> Vec<Solution> { pub fn get_solutions() -> Vec<Solution> {
vec![ vec![
day_01::solution(), day_01::solution(),

View File

@ -1,9 +1,13 @@
//! Day 01 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 01 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(1, 2021), part_1, part_2).with_expected(1451, 1395) Solution::new(Day::new(1, 2021), part_1, part_2).with_expected(1451, 1395)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
parse_measurements(input)? parse_measurements(input)?
@ -15,6 +19,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
Ok( Ok(
parse_measurements(input)? parse_measurements(input)?
@ -26,6 +31,7 @@ fn part_2(input: &str) -> Result<String> {
) )
} }
/// Parse the measurements from the puzzle input.
fn parse_measurements(input: &str) -> Result<Vec<i32>> { fn parse_measurements(input: &str) -> Result<Vec<i32>> {
input input
.lines() .lines()

View File

@ -1,14 +1,21 @@
//! Day 02 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 02 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(2, 2021), part_1, part_2) Solution::new(Day::new(2, 2021), part_1, part_2)
.with_expected(1727835, 1544000595) .with_expected(1727835, 1544000595)
} }
/// The possible commands to execute.
#[derive(Debug)] #[derive(Debug)]
enum Command { enum Command {
/// Move forward a given amount.
Forward(i32), Forward(i32),
/// Move down a given amount.
Down(i32), Down(i32),
/// Move up a given amount.
Up(i32), Up(i32),
} }
@ -34,14 +41,19 @@ impl FromStr for Command {
} }
} }
/// The submarine data.
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct Submarine { struct Submarine {
/// The direction the submarine is aiming at.
aim: i32, aim: i32,
/// The depth of the submarine is at.
depth: i32, depth: i32,
/// The horizontal position of the submarine.
horizontal_position: i32, horizontal_position: i32,
} }
impl Submarine { impl Submarine {
/// Execute the [`Command`] according to the logic for part one.
fn execute_command_1(&mut self, command: Command) { fn execute_command_1(&mut self, command: Command) {
match command { match command {
Command::Forward(amount) => self.horizontal_position += amount, Command::Forward(amount) => self.horizontal_position += amount,
@ -50,6 +62,7 @@ impl Submarine {
} }
} }
/// Execute the [`Command`] according to the logic for part two.
fn execute_command_2(&mut self, command: Command) { fn execute_command_2(&mut self, command: Command) {
match command { match command {
Command::Forward(amount) => { Command::Forward(amount) => {
@ -61,15 +74,18 @@ impl Submarine {
} }
} }
/// Calculate the final result.
fn final_result(&self) -> i32 { fn final_result(&self) -> i32 {
self.horizontal_position * self.depth self.horizontal_position * self.depth
} }
} }
/// Parse the list of [`Command`]s from the puzzle input.
fn parse_commands(input: &str) -> Result<Vec<Command>> { fn parse_commands(input: &str) -> Result<Vec<Command>> {
input.lines().map(Command::from_str).collect::<Result<_>>() input.lines().map(Command::from_str).collect::<Result<_>>()
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let mut submarine = Submarine::default(); let mut submarine = Submarine::default();
@ -80,6 +96,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(submarine.final_result().to_string()) Ok(submarine.final_result().to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let mut submarine = Submarine::default(); let mut submarine = Submarine::default();

View File

@ -1,10 +1,14 @@
//! Day 03 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 03 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(3, 2021), part_1, part_2) Solution::new(Day::new(3, 2021), part_1, part_2)
.with_expected(1092896, 4672151) .with_expected(1092896, 4672151)
} }
/// Count the bits for each line of the puzzle input.
fn count_bits(input: &str) -> Result<Vec<(usize, i32)>> { fn count_bits(input: &str) -> Result<Vec<(usize, i32)>> {
let mut bits = HashMap::<usize, i32>::new(); let mut bits = HashMap::<usize, i32>::new();
@ -28,6 +32,7 @@ fn count_bits(input: &str) -> Result<Vec<(usize, i32)>> {
) )
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let bits = count_bits(input)?; let bits = count_bits(input)?;
@ -51,6 +56,7 @@ fn part_1(input: &str) -> Result<String> {
Ok((gamma_rate * epsilon_rate).to_string()) Ok((gamma_rate * epsilon_rate).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let mut most_common_lines = input.lines().collect::<Vec<_>>(); let mut most_common_lines = input.lines().collect::<Vec<_>>();
let mut least_common_lines = input.lines().collect::<Vec<_>>(); let mut least_common_lines = input.lines().collect::<Vec<_>>();

View File

@ -1,12 +1,17 @@
//! [`Bingo`] code and implementation.
use std::str::FromStr; use std::str::FromStr;
use color_eyre::eyre::{eyre, Error}; use color_eyre::eyre::{eyre, Error};
use super::board::Board; use super::board::Board;
/// The game of bingo to play with its boards and numbers.
#[derive(Debug)] #[derive(Debug)]
pub struct Bingo { pub struct Bingo {
/// The list of [`Board`]s to play bingo with.
pub boards: Vec<Board>, pub boards: Vec<Board>,
/// The list of numbers to play.
pub numbers: Vec<i32>, pub numbers: Vec<i32>,
} }

View File

@ -1,3 +1,5 @@
//! [`Board`] code and implementation.
use std::str::FromStr; use std::str::FromStr;
use color_eyre::eyre::Error; use color_eyre::eyre::Error;
@ -18,9 +20,13 @@ const WIN_MATRIX: &[&[usize]] = &[
&[4, 9, 14, 19, 24], &[4, 9, 14, 19, 24],
]; ];
/// A single bingo board.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Board { pub struct Board {
/// Whether this board has at least one line filled.
pub has_won: bool, pub has_won: bool,
/// The state of the board, with indexes determining the position and whether
/// that position has been filled.
pub state: Vec<(i32, bool)>, pub state: Vec<(i32, bool)>,
} }

View File

@ -1,3 +1,5 @@
//! Day 04 of 2021.
mod bingo; mod bingo;
mod board; mod board;
@ -5,16 +7,19 @@ use bingo::Bingo;
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 04 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(4, 2021), part_1, part_2).with_expected(8580, 9576) Solution::new(Day::new(4, 2021), part_1, part_2).with_expected(8580, 9576)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let (winning_board, latest_number) = let (winning_board, latest_number) =
Bingo::from_str(input)?.play_until_first_win(); Bingo::from_str(input)?.play_until_first_win();
Ok((winning_board.sum_unmarked() * latest_number).to_string()) Ok((winning_board.sum_unmarked() * latest_number).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let (winning_board, latest_number) = let (winning_board, latest_number) =
Bingo::from_str(input)?.play_until_last_win(); Bingo::from_str(input)?.play_until_last_win();

View File

@ -1,16 +1,23 @@
//! Day 05 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 05 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(5, 2021), part_1, part_2).with_expected(6687, 19851) Solution::new(Day::new(5, 2021), part_1, part_2).with_expected(6687, 19851)
} }
/// A vector of two sets of coordinates.
#[derive(Debug)] #[derive(Debug)]
struct Vector { struct Vector {
/// The starting coordinate.
a: (isize, isize), a: (isize, isize),
/// The ending coordinate.
b: (isize, isize), b: (isize, isize),
} }
impl Vector { impl Vector {
/// Calculate the covered diagonal coordinates of the [`Vector`].
fn diagonal_coordinates(&self) -> Vec<(isize, isize)> { fn diagonal_coordinates(&self) -> Vec<(isize, isize)> {
let x_coordinates = { let x_coordinates = {
let x_amount = (self.a.0 - self.b.0).abs(); let x_amount = (self.a.0 - self.b.0).abs();
@ -33,6 +40,7 @@ impl Vector {
x_coordinates.into_iter().zip(y_coordinates).collect() x_coordinates.into_iter().zip(y_coordinates).collect()
} }
/// Calculate the covered horizontal coordinates of the [`Vector`].
fn horizontal_coordinates(&self) -> Vec<(isize, isize)> { fn horizontal_coordinates(&self) -> Vec<(isize, isize)> {
let y = self.a.1; let y = self.a.1;
@ -45,6 +53,7 @@ impl Vector {
(x1..=x2).map(|x| (x, y)).collect() (x1..=x2).map(|x| (x, y)).collect()
} }
/// Calculate the covered vertical coordinates of the [`Vector`].
fn vertical_coordinates(&self) -> Vec<(isize, isize)> { fn vertical_coordinates(&self) -> Vec<(isize, isize)> {
let x = self.a.0; let x = self.a.0;
@ -79,6 +88,7 @@ impl FromStr for Vector {
} }
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let vectors = input let vectors = input
.lines() .lines()
@ -110,6 +120,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(count_result(travelled_coordinates).to_string()) Ok(count_result(travelled_coordinates).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let vectors = input let vectors = input
.lines() .lines()
@ -135,6 +146,7 @@ fn part_2(input: &str) -> Result<String> {
Ok(count_result(travelled_coordinates).to_string()) Ok(count_result(travelled_coordinates).to_string())
} }
/// Count the results of the coordinates that overlap at least two lines.
fn count_result(coordinates: HashMap<(isize, isize), isize>) -> usize { fn count_result(coordinates: HashMap<(isize, isize), isize>) -> usize {
coordinates coordinates
.into_iter() .into_iter()

View File

@ -1,12 +1,17 @@
//! Day 06 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Shorthand for a [`HashMap`] using [`isize`]s.
type FishMap = HashMap<isize, isize>; type FishMap = HashMap<isize, isize>;
/// Get the solution for day 06 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(6, 2021), part_1, part_2) Solution::new(Day::new(6, 2021), part_1, part_2)
.with_expected(343441, 1569108373832_i64) .with_expected(343441, 1569108373832_i64)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let mut fishes = parse_fishes(input)?; let mut fishes = parse_fishes(input)?;
@ -17,6 +22,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(count_fishes(fishes).to_string()) Ok(count_fishes(fishes).to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let mut fishes = parse_fishes(input)?; let mut fishes = parse_fishes(input)?;
@ -27,6 +33,7 @@ fn part_2(input: &str) -> Result<String> {
Ok(count_fishes(fishes).to_string()) Ok(count_fishes(fishes).to_string())
} }
/// Parse the [`FishMap`]s from the puzzle input.
fn parse_fishes(input: &str) -> Result<FishMap> { fn parse_fishes(input: &str) -> Result<FishMap> {
let mut fishes = FishMap::new(); let mut fishes = FishMap::new();
let individual_fishes = input let individual_fishes = input
@ -42,10 +49,12 @@ fn parse_fishes(input: &str) -> Result<FishMap> {
Ok(fishes) Ok(fishes)
} }
/// Get the sum of the [`FishMap`] values.
fn count_fishes(fishes: FishMap) -> isize { fn count_fishes(fishes: FishMap) -> isize {
fishes.values().sum() fishes.values().sum()
} }
/// Simulate the fishes according to the puzzle's instructions.
fn simulate_fishes(fishes: FishMap) -> FishMap { fn simulate_fishes(fishes: FishMap) -> FishMap {
let mut new_fishes = HashMap::new(); let mut new_fishes = HashMap::new();

View File

@ -1,10 +1,14 @@
//! Day 07 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 07 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(7, 2021), part_1, part_2) Solution::new(Day::new(7, 2021), part_1, part_2)
.with_expected(328318, 89791146) .with_expected(328318, 89791146)
} }
/// Parse the list and highest number of crabs from the puzzle input.
fn parse_crabs(input: &str) -> Result<(Vec<isize>, isize)> { fn parse_crabs(input: &str) -> Result<(Vec<isize>, isize)> {
let crabs = input let crabs = input
.split(',') .split(',')
@ -19,6 +23,7 @@ fn parse_crabs(input: &str) -> Result<(Vec<isize>, isize)> {
Ok((crabs, highest_crab)) Ok((crabs, highest_crab))
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let (crabs, highest_crab) = parse_crabs(input)?; let (crabs, highest_crab) = parse_crabs(input)?;
(0..=highest_crab) (0..=highest_crab)
@ -33,6 +38,7 @@ fn part_1(input: &str) -> Result<String> {
.ok_or_else(|| eyre!("Unable to find lowest fuel")) .ok_or_else(|| eyre!("Unable to find lowest fuel"))
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let (crabs, highest_crab) = parse_crabs(input)?; let (crabs, highest_crab) = parse_crabs(input)?;
(0..=highest_crab) (0..=highest_crab)

View File

@ -1,17 +1,23 @@
//! [`Display`] implementation.
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use color_eyre::Result; use color_eyre::Result;
/// Type alias for [`HashSet`] with [`char`]s.
pub type CharSet = HashSet<char>; pub type CharSet = HashSet<char>;
/// The display with a given size and set of characters.
#[derive(Debug)] #[derive(Debug)]
pub struct Display(pub isize, pub CharSet); pub struct Display(pub isize, pub CharSet);
impl Display { impl Display {
/// Parse a [`Display`] from a string.
pub fn parse(s: &str) -> Self { pub fn parse(s: &str) -> Self {
Self(s.len() as isize, CharSet::from_iter(s.chars())) Self(s.len() as isize, CharSet::from_iter(s.chars()))
} }
/// Calculate the remaining displays based on the existing other ones.
pub fn figure_out_from_others( pub fn figure_out_from_others(
others: Vec<Self>, others: Vec<Self>,
) -> Result<HashMap<isize, CharSet>> { ) -> Result<HashMap<isize, CharSet>> {

View File

@ -1,13 +1,17 @@
//! Day 08 of 2021.
mod display; mod display;
use display::{CharSet, Display}; use display::{CharSet, Display};
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 08 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(8, 2021), part_1, part_2).with_expected(521, 1016804) Solution::new(Day::new(8, 2021), part_1, part_2).with_expected(521, 1016804)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
Ok( Ok(
input input
@ -27,6 +31,7 @@ fn part_1(input: &str) -> Result<String> {
) )
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let mut sum = 0; let mut sum = 0;

View File

@ -1,13 +1,19 @@
//! Day 09 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 09 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(9, 2021), part_1, part_2).with_expected(600, 987840) Solution::new(Day::new(9, 2021), part_1, part_2).with_expected(600, 987840)
} }
/// Type alias for an [`isize`] tuple.
type Coordinate = (isize, isize); type Coordinate = (isize, isize);
/// Type alias for a [`HashMap`] with [`Coordinate`]s pointing to a value.
type HeightMap = HashMap<Coordinate, isize>; type HeightMap = HashMap<Coordinate, isize>;
/// Constants for coordinate offsets to adjacent positions.
const ADJACENT_OFFSETS: &[Coordinate] = &[ const ADJACENT_OFFSETS: &[Coordinate] = &[
(-1, 0), // Left (-1, 0), // Left
(1, 0), // Right (1, 0), // Right
@ -15,6 +21,7 @@ const ADJACENT_OFFSETS: &[Coordinate] = &[
(0, 1), // Down (0, 1), // Down
]; ];
/// Parse the [`HeightMap`] from the puzzle input.
fn parse_heightmap(input: &str) -> Result<HeightMap> { fn parse_heightmap(input: &str) -> Result<HeightMap> {
let mut height_map = HeightMap::new(); let mut height_map = HeightMap::new();
@ -32,6 +39,7 @@ fn parse_heightmap(input: &str) -> Result<HeightMap> {
Ok(height_map) Ok(height_map)
} }
/// Parse the map bounds uzing the puzzle input.
fn parse_map_bounds(input: &str) -> Result<Coordinate> { fn parse_map_bounds(input: &str) -> Result<Coordinate> {
Ok(( Ok((
input input
@ -44,6 +52,7 @@ fn parse_map_bounds(input: &str) -> Result<Coordinate> {
)) ))
} }
/// Discover all the basins according to the puzzle instructions.
fn discover_basins( fn discover_basins(
coordinate: Coordinate, coordinate: Coordinate,
discovered_coordinates: &mut Vec<Coordinate>, discovered_coordinates: &mut Vec<Coordinate>,
@ -74,6 +83,7 @@ fn discover_basins(
coordinates coordinates
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let height_map = parse_heightmap(input)?; let height_map = parse_heightmap(input)?;
let map_bounds = parse_map_bounds(input)?; let map_bounds = parse_map_bounds(input)?;
@ -103,6 +113,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(risk_level.to_string()) Ok(risk_level.to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let height_map = parse_heightmap(input)?; let height_map = parse_heightmap(input)?;
let map_bounds = parse_map_bounds(input)?; let map_bounds = parse_map_bounds(input)?;

View File

@ -1,10 +1,14 @@
//! Day 10 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 10 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(10, 2021), part_1, part_2) Solution::new(Day::new(10, 2021), part_1, part_2)
.with_expected(387363, 4330777059_i64) .with_expected(387363, 4330777059_i64)
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let mut syntax_error_score = 0; let mut syntax_error_score = 0;
@ -40,6 +44,7 @@ fn part_1(input: &str) -> Result<String> {
Ok(syntax_error_score.to_string()) Ok(syntax_error_score.to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let mut scores = vec![]; let mut scores = vec![];

View File

@ -1,22 +1,33 @@
//! [`Point`], [`Fold`] and [`Canvas`] implementation.
use std::{collections::HashSet, fmt::Display}; use std::{collections::HashSet, fmt::Display};
/// A point coordinate.
#[derive(Debug, Hash, PartialEq, Eq)] #[derive(Debug, Hash, PartialEq, Eq)]
pub struct Point(pub isize, pub isize); pub struct Point(pub isize, pub isize);
/// The types of fold that can be made.
#[derive(Debug)] #[derive(Debug)]
pub enum Fold { pub enum Fold {
/// A horizontal fold going left.
Horizontal(isize), Horizontal(isize),
/// A vertical fold going up.
Vertical(isize), Vertical(isize),
} }
/// The canvas of the paper.
#[derive(Debug)] #[derive(Debug)]
pub struct Canvas { pub struct Canvas {
/// The width of the canvas.
pub width: isize, pub width: isize,
/// The height of the canvas.
pub height: isize, pub height: isize,
/// The points on the canvas.
pub points: HashSet<Point>, pub points: HashSet<Point>,
} }
impl Canvas { impl Canvas {
/// Perform a fold on the canvas and return the resulting version of it.
pub fn fold(self, fold: &Fold) -> Self { pub fn fold(self, fold: &Fold) -> Self {
let (width, height) = match fold { let (width, height) = match fold {
Fold::Horizontal(amount) => (self.width, *amount), Fold::Horizontal(amount) => (self.width, *amount),

View File

@ -1,9 +1,12 @@
//! Day 13 of 2021.
mod canvas; mod canvas;
use canvas::{Canvas, Fold, Point}; use canvas::{Canvas, Fold, Point};
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 13 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(13, 2021), part_1, part_2).with_expected( Solution::new(Day::new(13, 2021), part_1, part_2).with_expected(
"712", "712",
@ -17,6 +20,7 @@ pub fn solution() -> Solution {
) )
} }
/// Parse the canvas and list of folds to perform from the puzzle input.
fn parse(input: &str) -> Result<(Canvas, Vec<Fold>)> { fn parse(input: &str) -> Result<(Canvas, Vec<Fold>)> {
let mut canvas = Canvas { let mut canvas = Canvas {
width: 0, width: 0,
@ -74,12 +78,14 @@ fn parse(input: &str) -> Result<(Canvas, Vec<Fold>)> {
Ok((canvas, folds)) Ok((canvas, folds))
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let (mut canvas, folds) = parse(input)?; let (mut canvas, folds) = parse(input)?;
canvas = canvas.fold(&folds[0]); canvas = canvas.fold(&folds[0]);
Ok(canvas.points.len().to_string()) Ok(canvas.points.len().to_string())
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let (mut canvas, folds) = parse(input)?; let (mut canvas, folds) = parse(input)?;

View File

@ -1,13 +1,19 @@
//! Day 14 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Type alias for a map of pairs.
type PairMap = HashMap<(char, char), char>; type PairMap = HashMap<(char, char), char>;
/// Type alias for a map of pair counts.
type PairCounts = HashMap<(char, char), isize>; type PairCounts = HashMap<(char, char), isize>;
/// Get the solution for day 14 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(14, 2021), part_1, part_2) Solution::new(Day::new(14, 2021), part_1, part_2)
.with_expected(3411, 7477815755570_i64) .with_expected(3411, 7477815755570_i64)
} }
/// Parse the puzzle input into the template and map of pairs.
fn parse(input: &str) -> Result<(String, PairMap)> { fn parse(input: &str) -> Result<(String, PairMap)> {
let mut lines = input.lines(); let mut lines = input.lines();
let template = lines let template = lines
@ -30,6 +36,7 @@ fn parse(input: &str) -> Result<(String, PairMap)> {
Ok((template, pairs)) Ok((template, pairs))
} }
/// Apply the counts to the pairs and return the new counts to add.
fn apply(counts: &PairCounts, pairs: &PairMap) -> PairCounts { fn apply(counts: &PairCounts, pairs: &PairMap) -> PairCounts {
let mut to_add = PairCounts::new(); let mut to_add = PairCounts::new();
@ -43,6 +50,7 @@ fn apply(counts: &PairCounts, pairs: &PairMap) -> PairCounts {
to_add to_add
} }
/// Count the totals of the pair counts.
fn count_totals(counts: &PairCounts) -> HashMap<char, isize> { fn count_totals(counts: &PairCounts) -> HashMap<char, isize> {
let mut totals = HashMap::new(); let mut totals = HashMap::new();
@ -55,6 +63,7 @@ fn count_totals(counts: &PairCounts) -> HashMap<char, isize> {
totals totals
} }
/// Solve the puzzle for a given amount of steps.
fn run(input: &str, steps: isize) -> Result<String> { fn run(input: &str, steps: isize) -> Result<String> {
let (template, pairs) = parse(input)?; let (template, pairs) = parse(input)?;
@ -80,10 +89,12 @@ fn run(input: &str, steps: isize) -> Result<String> {
Ok((max - min).to_string()) Ok((max - min).to_string())
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
run(input, 10) run(input, 10)
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
run(input, 40) run(input, 40)
} }

View File

@ -1,19 +1,26 @@
//! Day 15 of 2021.
use crate::prelude::*; use crate::prelude::*;
/// Get the solution for day 15 of 2021.
pub fn solution() -> Solution { pub fn solution() -> Solution {
Solution::new(Day::new(15, 2021), part_1, part_2).with_expected(386, 2806) Solution::new(Day::new(15, 2021), part_1, part_2).with_expected(386, 2806)
} }
/// Type alias for a map of coordinates and risk levels.
type Grid = HashMap<Coordinate, isize>; type Grid = HashMap<Coordinate, isize>;
/// A coordinate in the grid.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct Coordinate(isize, isize); struct Coordinate(isize, isize);
impl Coordinate { impl Coordinate {
/// Get the distance between two [`Coordinate`]s.
fn distance(&self, target: &Coordinate) -> usize { fn distance(&self, target: &Coordinate) -> usize {
self.0.abs_diff(target.0) + self.1.abs_diff(target.1) self.0.abs_diff(target.0) + self.1.abs_diff(target.1)
} }
/// Calculate the successors of the grid based on this [`Coordinate`].
fn successors(&self, grid: &Grid) -> Vec<(Coordinate, isize)> { fn successors(&self, grid: &Grid) -> Vec<(Coordinate, isize)> {
let &Coordinate(x, y) = self; let &Coordinate(x, y) = self;
let mut successors = vec![]; let mut successors = vec![];
@ -33,6 +40,7 @@ impl Coordinate {
} }
} }
/// Parse the [`Grid`] and end [`Coordinate`] from the puzzle input.
fn parse(input: &str) -> Result<(Grid, Coordinate)> { fn parse(input: &str) -> Result<(Grid, Coordinate)> {
let mut grid = Grid::new(); let mut grid = Grid::new();
let mut end = Coordinate(0, 0); let mut end = Coordinate(0, 0);
@ -53,6 +61,8 @@ fn parse(input: &str) -> Result<(Grid, Coordinate)> {
Ok((grid, end)) Ok((grid, end))
} }
/// Enlarge the grid by five times its size, accounting for the additional rules
/// specified in the puzzle.
fn enlarge_grid(grid: Grid, end: Coordinate) -> (Grid, Coordinate) { fn enlarge_grid(grid: Grid, end: Coordinate) -> (Grid, Coordinate) {
let Coordinate(width, height) = end; let Coordinate(width, height) = end;
let mut larger_grid = grid.clone(); let mut larger_grid = grid.clone();
@ -74,6 +84,7 @@ fn enlarge_grid(grid: Grid, end: Coordinate) -> (Grid, Coordinate) {
(larger_grid, Coordinate(width * 5, height * 5)) (larger_grid, Coordinate(width * 5, height * 5))
} }
/// Solve the grid using [`astar`].
fn run(grid: Grid, end: Coordinate) -> Result<String> { fn run(grid: Grid, end: Coordinate) -> Result<String> {
Ok( Ok(
astar( astar(
@ -88,11 +99,13 @@ fn run(grid: Grid, end: Coordinate) -> Result<String> {
) )
} }
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> { fn part_1(input: &str) -> Result<String> {
let (grid, end) = parse(input)?; let (grid, end) = parse(input)?;
run(grid, end) run(grid, end)
} }
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> { fn part_2(input: &str) -> Result<String> {
let (grid, end) = parse(input)?; let (grid, end) = parse(input)?;
let (grid, end) = enlarge_grid(grid, end); let (grid, end) = enlarge_grid(grid, end);

View File

@ -1,3 +1,5 @@
//! Solutions for Advent of Code 2021.
use crate::solution::Solution; use crate::solution::Solution;
mod day_01; mod day_01;
@ -14,6 +16,7 @@ mod day_13;
mod day_14; mod day_14;
mod day_15; mod day_15;
/// Get all the solutions of 2021 as a [`Vec<Solution>`].
pub fn get_solutions() -> Vec<Solution> { pub fn get_solutions() -> Vec<Solution> {
vec![ vec![
day_01::solution(), day_01::solution(),