init
This commit is contained in:
commit
0005f4caff
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
/input
|
178
Cargo.lock
generated
Normal file
178
Cargo.lock
generated
Normal 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
16
Cargo.toml
Normal 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
46
src/day1.rs
Normal 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
75
src/day2.rs
Normal 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
64
src/day3.rs
Normal 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
202
src/day4.rs
Normal 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
10
src/lib.rs
Normal 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
7
src/main.rs
Normal 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 }
|
Loading…
Reference in New Issue
Block a user