This commit is contained in:
Andrew Glaze 2023-12-27 14:55:54 -05:00
commit 0005f4caff
9 changed files with 600 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/input

178
Cargo.lock generated Normal file
View File

@ -0,0 +1,178 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advent_of_code_2020"
version = "0.1.0"
dependencies = [
"aoc-runner",
"aoc-runner-derive",
"itertools",
"strum",
"strum_macros",
]
[[package]]
name = "aoc-runner"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d21ef9204ad206a5a3e918e9920da04e1118ad91ce4f23570be964b9d6b9dfcb"
[[package]]
name = "aoc-runner-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba8b944269d3fee645d281b1335e1797044db497bb02d0098cc3fdb8900069cc"
dependencies = [
"aoc-runner-internal",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "aoc-runner-internal"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "274b0ba7f3669a45ec0aaacf94eb032a749de880ab776091576cca94037c9982"
dependencies = [
"serde",
"serde_derive",
"serde_json",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "itertools"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "proc-macro2"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "ryu"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "serde"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "strum"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
[[package]]
name = "strum_macros"
version = "0.25.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.42",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

16
Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "advent_of_code_2020"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
bench = false
[dependencies]
aoc-runner = "0.3.0"
aoc-runner-derive = "0.3.0"
itertools = "0.12.0"
strum = "0.25.0"
strum_macros = "0.25"

46
src/day1.rs Normal file
View File

@ -0,0 +1,46 @@
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools;
#[aoc_generator(day1)]
fn parse(input: &str) -> Vec<u64> {
input.lines()
.map(str::parse::<u64>)
.map(Result::unwrap)
.collect_vec()
}
#[aoc(day1, part1)]
fn part1(input: &Vec<u64>) -> u64 {
input.iter().combinations(2)
.find(|x| x.iter().cloned().sum::<u64>() == 2020)
.map(|x| x.iter().cloned().product()).unwrap()
}
#[aoc(day1, part2)]
fn part2(input: &Vec<u64>) -> u64 {
input.iter().combinations(3)
.find(|x| x.iter().cloned().sum::<u64>() == 2020)
.map(|x| x.iter().cloned().product()).unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"1721
979
366
299
675
1456";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 514579);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX)), 241861950);
}
}

75
src/day2.rs Normal file
View File

@ -0,0 +1,75 @@
use aoc_runner_derive::{aoc, aoc_generator};
#[derive(Debug)]
struct Policy {
min: u32,
max: u32,
match_char: char,
}
#[aoc_generator(day2)]
fn parse(input: &str) -> Vec<(Policy, String)> {
let input = input.lines().map(|line| {
let line = line.split(": ").collect::<Vec<_>>();
let policy = line[0].split(' ').collect::<Vec<_>>();
let min = policy[0][0..policy[0].find('-').unwrap()].parse::<u32>().unwrap();
let max = policy[0][policy[0].find('-').unwrap() + 1..].parse::<u32>().unwrap();
let match_char = policy[1].chars().next().unwrap();
(Policy {min, max, match_char}, line[1].to_string())
}).collect::<Vec<_>>();
input
}
#[aoc(day2, part1)]
fn part1(passwords: &Vec<(Policy, String)>) -> u32 {
let mut valid_count = 0;
for (Policy {min, max, match_char}, password) in passwords {
let mut count = 0;
for char in password.chars() {
if char == *match_char {
count += 1;
}
}
if count >= *min && count <= *max {
valid_count += 1;
}
}
valid_count
}
#[aoc(day2, part2)]
fn part2(passwords: &Vec<(Policy, String)>) -> u32 {
let mut valid_count = 0;
for (Policy {min, max, match_char}, password) in passwords {
let first = password.chars().collect::<Vec<_>>()[(*min - 1) as usize] == *match_char;
let second = password.chars().collect::<Vec<_>>()[(*max - 1) as usize] == *match_char;
if first ^ second {
valid_count += 1;
}
}
valid_count
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"1-3 a: abcde
1-3 b: cdefg
2-9 c: ccccccccc";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 2);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX)), 1);
}
}

64
src/day3.rs Normal file
View File

@ -0,0 +1,64 @@
use aoc_runner_derive::{aoc, aoc_generator};
#[aoc_generator(day3)]
fn parse(input: &str) -> Vec<Vec<char>> {
let input = input.lines().map(|line| {
line.chars().collect::<Vec<_>>()
}).collect::<Vec<_>>();
input
}
#[aoc(day3, part1)]
fn part1(input: &Vec<Vec<char>>) -> u64 {
count_trees(1, 3, input)
}
#[aoc(day3, part2)]
fn part2(input: &Vec<Vec<char>>) -> u64 {
vec![(1,1), (1,3), (1,5), (1,7), (2,1)].iter()
.map(|(rise, run)| {
count_trees(*rise, *run, input)
}).product()
}
fn count_trees(rise: usize, run: usize, input: &Vec<Vec<char>>) -> u64 {
let mut x = 0;
let mut tree_count = 0;
for y in (rise..input.len()).step_by(rise) {
x += run;
if input[y][x % input[0].len()] == '#' {
tree_count += 1;
}
}
tree_count
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"..##.......
#...#...#..
.#....#..#.
..#.#...#.#
.#...##..#.
..#.##.....
.#.#.#....#
.#........#
#.##...#...
#...##....#
.#..#...#.#";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 7);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX)), 336);
}
}

202
src/day4.rs Normal file
View File

@ -0,0 +1,202 @@
use aoc_runner_derive::{aoc, aoc_generator};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
#[derive(Debug, EnumIter, PartialEq, Clone, Copy)]
enum IDField {
BirthYear,
IssueYear,
ExpirationYear,
Height,
HairColor,
EyeColor,
PassportID,
CountryID
}
impl From<&str> for IDField {
fn from(value: &str) -> Self {
match &*value {
"byr" => Self::BirthYear,
"iyr" => Self::IssueYear,
"eyr" => Self::ExpirationYear,
"hgt" => Self::Height,
"hcl" => Self::HairColor,
"ecl" => Self::EyeColor,
"pid" => Self::PassportID,
"cid" => Self::CountryID,
_ => unreachable!()
}
}
}
impl IDField {
fn validate(&self, val: &str) -> bool {
match self {
IDField::BirthYear => {
if val.len() == 4 {
if let Ok(num) = val.parse::<u32>() {
if num >= 1920 && num <= 2002 {
return true;
}
}
}
false
},
IDField::IssueYear => {
if val.len() == 4 {
if let Ok(num) = val.parse::<u32>() {
if num >= 2010 && num <= 2020 {
return true;
}
}
}
false
},
IDField::ExpirationYear => {
if val.len() == 4 {
if let Ok(num) = val.parse::<u32>() {
if num >= 2020 && num <= 2030 {
return true;
}
}
}
false
},
IDField::Height => {
if let Some(idx) = val.find("cm") {
if let Ok(num) = val[0..idx].parse::<u32>() {
if num >= 150 && num <= 193 {
return true;
}
}
} else if let Some(idx) = val.find("in") {
if let Ok(num) = val[0..idx].parse::<u32>() {
if num >= 59 && num <= 76 {
return true;
}
}
}
false
},
IDField::HairColor => {
if val.chars().next().unwrap() == '#' {
return val[1..].chars().all(|char| char.is_ascii_hexdigit())
}
false
},
IDField::EyeColor => {
match val {
"amb" | "blu" | "brn" | "gry" | "grn" | "hzl" | "oth" => true,
_ => false
}
},
IDField::PassportID => {
val.len() == 9 && val.chars().all(char::is_numeric)
},
IDField::CountryID => true,
}
}
}
#[aoc_generator(day4)]
fn parse(input: &str) -> Vec<Vec<(IDField, String)>> {
let input = input.split("\n\n")
.map(str::split_ascii_whitespace)
.map(|line| {
line.map(|field_str| {
let colon = field_str.find(':').unwrap();
(field_str[0..colon].into(), field_str[colon + 1..].to_string())
}).collect::<Vec<_>>()
}).collect::<Vec<_>>();
input
}
#[aoc(day4, part1)]
fn part1(input: &Vec<Vec<(IDField, String)>>) -> u32 {
input.iter()
.map(|passport| {
let passport = passport.iter().map(|(field, _)| *field).collect::<Vec<_>>();
IDField::iter().all(|x| {
if x == IDField::CountryID {
return true
}
passport.contains(&x)
})
}).filter(|x| *x).count() as u32
}
#[aoc(day4, part2)]
fn part2(input: &Vec<Vec<(IDField, String)>>) -> u32 {
input.iter().map(|passport| {
IDField::iter().all(|x| {
if x == IDField::CountryID {
return true
}
if let Some((_, val)) = passport.iter().find(|(field, _)| field == &x ) {
return x.validate(&val)
}
false
})
}).filter(|x| *x).count() as u32
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
byr:1937 iyr:2017 cid:147 hgt:183cm
iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
hcl:#cfa07d byr:1929
hcl:#ae17e1 iyr:2013
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm
hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in";
const EX_2: &str = r"eyr:1972 cid:100
hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926
iyr:2019
hcl:#602927 eyr:1967 hgt:170cm
ecl:grn pid:012533040 byr:1946
hcl:dab227 iyr:2012
ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277
hgt:59cm ecl:zzz
eyr:2038 hcl:74454a iyr:2023
pid:3556412378 byr:2007
pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980
hcl:#623a2f
eyr:2029 ecl:blu cid:129 byr:1989
iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm
hcl:#888785
hgt:164cm byr:2001 iyr:2015 cid:88
pid:545766238 ecl:hzl
eyr:2022
iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 2);
}
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX_2)), 4);
}
}

10
src/lib.rs Normal file
View File

@ -0,0 +1,10 @@
mod day1;
mod day4;
mod day3;
mod day2;
extern crate aoc_runner;
#[macro_use]
extern crate aoc_runner_derive;
aoc_lib!{ year = 2020 }

7
src/main.rs Normal file
View File

@ -0,0 +1,7 @@
extern crate advent_of_code_2020;
extern crate aoc_runner_derive;
extern crate aoc_runner;
use aoc_runner_derive::aoc_main;
aoc_main! { lib = advent_of_code_2020 }