Add missing documentation lints.
This commit is contained in:
parent
1030c6f60f
commit
3c9bfef10a
|
@ -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"
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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![];
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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<_>>();
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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![];
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in New Issue