Skip to content

Commit 9e25af2

Browse files
committed
more rust
1 parent f250bfa commit 9e25af2

25 files changed

+842
-13
lines changed

2020/Cargo.toml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
# http://adventofcode.com/2020
22

33
[workspace]
4-
members = ["day1", "day2", "day3", "day6", "day13", "day19", "day23"]
4+
members = [
5+
"day1",
6+
"day2",
7+
"day3",
8+
"day4",
9+
"day5",
10+
"day6",
11+
"day7",
12+
"day8",
13+
"day9",
14+
"day10",
15+
"day13",
16+
"day19",
17+
"day23",
18+
]
519

620
resolver = "2"

2020/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
![AoC2020](https://img.shields.io/badge/Advent_of_Code-2020-8A2BE2)
44
![Stars: 50](https://img.shields.io/badge/Stars-50⭐-blue)
5-
![Rust: 7](https://img.shields.io/badge/Rust-7-cyan?logo=Rust)
5+
![Rust: 13](https://img.shields.io/badge/Rust-13-cyan?logo=Rust)
66
![Python: 23](https://img.shields.io/badge/Python-23-cyan?logo=Python)
77

88
## 2020 ([Calendar](https://adventofcode.com/2020)) ([Solutions](../2020/)) : 50⭐
@@ -12,13 +12,13 @@ Puzzle | Stars
1212
[Day 1: Report Repair](https://adventofcode.com/2020/day/1) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day1/day1.rs) [![Python](../scripts/assets/python.png)](../2020/day1/day1.py)
1313
[Day 2: Password Philosophy](https://adventofcode.com/2020/day/2) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day2/day2.rs) [![Python](../scripts/assets/python.png)](../2020/day2/day2.py)
1414
[Day 3: Toboggan Trajectory](https://adventofcode.com/2020/day/3) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day3/day3.rs) [![Python](../scripts/assets/python.png)](../2020/day3/day3.py)
15-
[Day 4: Passport Processing](https://adventofcode.com/2020/day/4) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day4/day4.py)
16-
[Day 5: Binary Boarding](https://adventofcode.com/2020/day/5) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day5/day5.py)
15+
[Day 4: Passport Processing](https://adventofcode.com/2020/day/4) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day4/day4.rs) [![Python](../scripts/assets/python.png)](../2020/day4/day4.py)
16+
[Day 5: Binary Boarding](https://adventofcode.com/2020/day/5) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day5/day5.rs) [![Python](../scripts/assets/python.png)](../2020/day5/day5.py)
1717
[Day 6: Custom Customs](https://adventofcode.com/2020/day/6) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day6/day6.rs) [![Python](../scripts/assets/python.png)](../2020/day6/day6.py)
18-
[Day 7: Handy Haversacks](https://adventofcode.com/2020/day/7) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day7/day7.py)
19-
[Day 8: Handheld Halting](https://adventofcode.com/2020/day/8) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day8/day8.py)
20-
[Day 9: Encoding Error](https://adventofcode.com/2020/day/9) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day9/day9.py)
21-
[Day 10: Adapter Array](https://adventofcode.com/2020/day/10) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day10/day10.py)
18+
[Day 7: Handy Haversacks](https://adventofcode.com/2020/day/7) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day7/day7.rs) [![Python](../scripts/assets/python.png)](../2020/day7/day7.py)
19+
[Day 8: Handheld Halting](https://adventofcode.com/2020/day/8) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day8/day8.rs) [![Python](../scripts/assets/python.png)](../2020/day8/day8.py)
20+
[Day 9: Encoding Error](https://adventofcode.com/2020/day/9) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day9/day9.rs) [![Python](../scripts/assets/python.png)](../2020/day9/day9.py)
21+
[Day 10: Adapter Array](https://adventofcode.com/2020/day/10) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day10/day10.rs) [![Python](../scripts/assets/python.png)](../2020/day10/day10.py)
2222
[Day 11: Seating System](https://adventofcode.com/2020/day/11) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day11/day11.py)
2323
[Day 12: Rain Risk](https://adventofcode.com/2020/day/12) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day12/day12.py)
2424
[Day 13: Shuttle Search](https://adventofcode.com/2020/day/13) | ⭐⭐ | [![Rust](../scripts/assets/rust.png)](../2020/day13/day13.rs) [![Python](../scripts/assets/python.png)](../2020/day13/day13.py)

2020/day10/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "day10"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aoc = { path = "../../aoc" }
8+
9+
[[bin]]
10+
name = "day10"
11+
path = "day10.rs"

2020/day10/day10.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! [Day 10: Adapter Array](https://adventofcode.com/2020/day/10)
2+
3+
use std::collections::HashMap;
4+
5+
struct Puzzle {
6+
adapters: Vec<i64>,
7+
}
8+
9+
impl Puzzle {
10+
const fn new() -> Self {
11+
Self {
12+
adapters: Vec::new(),
13+
}
14+
}
15+
16+
/// Get the puzzle input.
17+
fn configure(&mut self, path: &str) {
18+
let data = std::fs::read_to_string(path).unwrap_or_else(|_| {
19+
eprintln!("cannot read input file {path}");
20+
std::process::exit(1);
21+
});
22+
23+
self.adapters
24+
.extend(data.lines().map_while(|line| line.parse::<i64>().ok()));
25+
26+
self.adapters.sort_unstable();
27+
}
28+
29+
/// Solve part one.
30+
fn part1(&self) -> u32 {
31+
let mut diffs: HashMap<i64, u32> = HashMap::new();
32+
33+
for w in self.adapters.windows(2) {
34+
let d = w[1] - w[0];
35+
36+
*diffs.entry(d).or_default() += 1;
37+
}
38+
39+
*diffs.entry(self.adapters[0] /*- 0*/).or_default() += 1; // charging outlet has an effective rating of 0 jolts
40+
*diffs.entry(3).or_default() += 1; // device's built-in adapter is always 3 higher
41+
42+
diffs[&1] * diffs[&3]
43+
}
44+
45+
/// Solve part two.
46+
fn part2(&self) -> i64 {
47+
let mut adapters = self.adapters.clone();
48+
49+
adapters.insert(0, 0); // add the charging outlet
50+
51+
let mut n = (0, 0, 1);
52+
53+
for w in adapters.windows(2) {
54+
n = match w[1] - w[0] {
55+
1 => (n.1, n.2, n.0 + n.1 + n.2),
56+
2 => (n.2, 0, n.1 + n.2),
57+
3 => (0, 0, n.2),
58+
_ => n,
59+
}
60+
}
61+
62+
n.2
63+
}
64+
}
65+
66+
fn main() {
67+
let args = aoc::parse_args();
68+
let mut puzzle = Puzzle::new();
69+
puzzle.configure(args.path.as_str());
70+
println!("{}", puzzle.part1());
71+
println!("{}", puzzle.part2());
72+
}
73+
74+
/// Test from puzzle input
75+
#[cfg(test)]
76+
mod test {
77+
use super::*;
78+
79+
#[test]
80+
fn test_part1_1() {
81+
let mut puzzle = Puzzle::new();
82+
puzzle.configure("sample_1.txt");
83+
assert_eq!(puzzle.part1(), 7 * 5);
84+
}
85+
86+
#[test]
87+
fn test_part1_2() {
88+
let mut puzzle = Puzzle::new();
89+
puzzle.configure("sample_2.txt");
90+
assert_eq!(puzzle.part1(), 22 * 10);
91+
}
92+
93+
#[test]
94+
fn test_part2() {
95+
let mut puzzle = Puzzle::new();
96+
puzzle.configure("sample_2.txt");
97+
assert_eq!(puzzle.part2(), 19208);
98+
}
99+
}

2020/day10/sample_1.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
16
2+
10
3+
15
4+
5
5+
1
6+
11
7+
7
8+
19
9+
6
10+
12
11+
4

2020/day10/test.txt renamed to 2020/day10/sample_2.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@
2828
2
2929
34
3030
10
31-
3
31+
3

2020/day4/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "day4"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aoc = { path = "../../aoc" }
8+
9+
[[bin]]
10+
name = "day4"
11+
path = "day4.rs"

2020/day4/day4.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//! [Day 4: Passport Processing](https://adventofcode.com/2020/day/4)
2+
3+
use std::collections::HashSet;
4+
5+
fn validate_field(field: &str, value: &str) -> bool {
6+
match (field, value.len()) {
7+
("byr", 4) => {
8+
let byr: u32 = value.parse().unwrap_or(0);
9+
(1920..=2002).contains(&byr)
10+
}
11+
("iyr", 4) => {
12+
let iyr: u32 = value.parse().unwrap_or(0);
13+
(2010..=2020).contains(&iyr)
14+
}
15+
("eyr", 4) => {
16+
let eyr: u32 = value.parse().unwrap_or(0);
17+
(2020..=2030).contains(&eyr)
18+
}
19+
("hgt", _) => value.strip_suffix("in").map_or_else(
20+
|| {
21+
value.strip_suffix("cm").map_or(false, |centimeters| {
22+
let height: u8 = centimeters.parse().unwrap_or(0);
23+
(150..=193).contains(&height)
24+
})
25+
},
26+
|inches| {
27+
let height: u8 = inches.parse().unwrap_or(0);
28+
(59..=76).contains(&height)
29+
},
30+
),
31+
("hcl", 7) => {
32+
value.starts_with('#')
33+
&& value
34+
.chars()
35+
.skip(1)
36+
.all(|c| "abcdef0123456789".contains(c))
37+
}
38+
("ecl", 3) => ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"].contains(&value),
39+
("pid", 9) => value.chars().all(|c| c.is_ascii_digit()),
40+
_ => false,
41+
}
42+
}
43+
44+
struct Puzzle {
45+
data: String,
46+
}
47+
48+
impl Puzzle {
49+
const fn new() -> Self {
50+
Self {
51+
data: String::new(),
52+
}
53+
}
54+
55+
/// Get the puzzle input.
56+
fn configure(&mut self, path: &str) {
57+
let data = std::fs::read_to_string(path).unwrap_or_else(|_| {
58+
eprintln!("cannot read input file {path}");
59+
std::process::exit(1);
60+
});
61+
62+
self.data = data;
63+
}
64+
65+
/// Solve part one.
66+
fn part1(&self) -> u32 {
67+
let mandatory_fields: HashSet<_> = ["eyr", "iyr", "byr", "ecl", "pid", "hcl", "hgt"]
68+
.iter()
69+
.copied()
70+
.collect();
71+
72+
self.data
73+
.split("\n\n")
74+
.map(|record| {
75+
let mut fields = HashSet::new();
76+
for item in record.split_ascii_whitespace() {
77+
let (field, _) = item.split_once(':').unwrap();
78+
fields.insert(field);
79+
}
80+
u32::from(fields.is_superset(&mandatory_fields))
81+
})
82+
.sum()
83+
}
84+
85+
/// Solve part two.
86+
fn part2(&self) -> u32 {
87+
let mandatory_fields: HashSet<_> = ["eyr", "iyr", "byr", "ecl", "pid", "hcl", "hgt"]
88+
.iter()
89+
.copied()
90+
.collect();
91+
92+
self.data
93+
.split("\n\n")
94+
.map(|record| {
95+
let mut fields = HashSet::new();
96+
for item in record.split_ascii_whitespace() {
97+
let (field, value) = item.split_once(':').unwrap();
98+
99+
if validate_field(field, value) {
100+
fields.insert(field);
101+
}
102+
}
103+
u32::from(fields.is_superset(&mandatory_fields))
104+
})
105+
.sum()
106+
}
107+
}
108+
109+
fn main() {
110+
let args = aoc::parse_args();
111+
let mut puzzle = Puzzle::new();
112+
puzzle.configure(args.path.as_str());
113+
println!("{}", puzzle.part1());
114+
println!("{}", puzzle.part2());
115+
}
116+
117+
/// Test from puzzle input
118+
#[cfg(test)]
119+
mod test {
120+
use super::*;
121+
122+
#[test]
123+
fn test_part1() {
124+
let mut puzzle = Puzzle::new();
125+
puzzle.configure("sample_1.txt");
126+
assert_eq!(puzzle.part1(), 2);
127+
}
128+
129+
#[test]
130+
fn test_part2_invalid() {
131+
let mut puzzle = Puzzle::new();
132+
puzzle.configure("sample_3.txt");
133+
assert_eq!(puzzle.part2(), 0);
134+
}
135+
136+
#[test]
137+
fn test_part2_valid() {
138+
let mut puzzle = Puzzle::new();
139+
puzzle.configure("sample_4.txt");
140+
assert_eq!(puzzle.part2(), 4);
141+
}
142+
}

2020/day4/sample_1.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
ecl:gry pid:860033327 eyr:2020 hcl:#fffffd
2+
byr:1937 iyr:2017 cid:147 hgt:183cm
3+
4+
iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884
5+
hcl:#cfa07d byr:1929
6+
7+
hcl:#ae17e1 iyr:2013
8+
eyr:2024
9+
ecl:brn pid:760753108 byr:1931
10+
hgt:179cm
11+
12+
hcl:#cfa07d eyr:2025 pid:166559648
13+
iyr:2011 ecl:brn hgt:59in

2020/day4/sample_3.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
eyr:1972 cid:100
2+
hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926
3+
4+
iyr:2019
5+
hcl:#602927 eyr:1967 hgt:170cm
6+
ecl:grn pid:012533040 byr:1946
7+
8+
hcl:dab227 iyr:2012
9+
ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277
10+
11+
hgt:59cm ecl:zzz
12+
eyr:2038 hcl:74454a iyr:2023
13+
pid:3556412378 byr:2007

0 commit comments

Comments
 (0)