Skip to content

Commit

Permalink
more rust
Browse files Browse the repository at this point in the history
  • Loading branch information
rene-d committed Dec 26, 2024
1 parent f250bfa commit 9e25af2
Show file tree
Hide file tree
Showing 25 changed files with 842 additions and 13 deletions.
16 changes: 15 additions & 1 deletion 2020/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# http://adventofcode.com/2020

[workspace]
members = ["day1", "day2", "day3", "day6", "day13", "day19", "day23"]
members = [
"day1",
"day2",
"day3",
"day4",
"day5",
"day6",
"day7",
"day8",
"day9",
"day10",
"day13",
"day19",
"day23",
]

resolver = "2"
14 changes: 7 additions & 7 deletions 2020/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

## 2020 ([Calendar](https://adventofcode.com/2020)) ([Solutions](../2020/)) : 50⭐
Expand All @@ -12,13 +12,13 @@ Puzzle | Stars
[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)
[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)
[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)
[Day 4: Passport Processing](https://adventofcode.com/2020/day/4) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day4/day4.py)
[Day 5: Binary Boarding](https://adventofcode.com/2020/day/5) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day5/day5.py)
[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)
[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)
[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)
[Day 7: Handy Haversacks](https://adventofcode.com/2020/day/7) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day7/day7.py)
[Day 8: Handheld Halting](https://adventofcode.com/2020/day/8) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day8/day8.py)
[Day 9: Encoding Error](https://adventofcode.com/2020/day/9) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day9/day9.py)
[Day 10: Adapter Array](https://adventofcode.com/2020/day/10) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day10/day10.py)
[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)
[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)
[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)
[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)
[Day 11: Seating System](https://adventofcode.com/2020/day/11) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day11/day11.py)
[Day 12: Rain Risk](https://adventofcode.com/2020/day/12) | ⭐⭐ | [![Python](../scripts/assets/python.png)](../2020/day12/day12.py)
[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)
Expand Down
11 changes: 11 additions & 0 deletions 2020/day10/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "day10"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../../aoc" }

[[bin]]
name = "day10"
path = "day10.rs"
99 changes: 99 additions & 0 deletions 2020/day10/day10.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! [Day 10: Adapter Array](https://adventofcode.com/2020/day/10)
use std::collections::HashMap;

struct Puzzle {
adapters: Vec<i64>,
}

impl Puzzle {
const fn new() -> Self {
Self {
adapters: Vec::new(),
}
}

/// Get the puzzle input.
fn configure(&mut self, path: &str) {
let data = std::fs::read_to_string(path).unwrap_or_else(|_| {
eprintln!("cannot read input file {path}");
std::process::exit(1);
});

self.adapters
.extend(data.lines().map_while(|line| line.parse::<i64>().ok()));

self.adapters.sort_unstable();
}

/// Solve part one.
fn part1(&self) -> u32 {
let mut diffs: HashMap<i64, u32> = HashMap::new();

for w in self.adapters.windows(2) {
let d = w[1] - w[0];

*diffs.entry(d).or_default() += 1;
}

*diffs.entry(self.adapters[0] /*- 0*/).or_default() += 1; // charging outlet has an effective rating of 0 jolts
*diffs.entry(3).or_default() += 1; // device's built-in adapter is always 3 higher

diffs[&1] * diffs[&3]
}

/// Solve part two.
fn part2(&self) -> i64 {
let mut adapters = self.adapters.clone();

adapters.insert(0, 0); // add the charging outlet

let mut n = (0, 0, 1);

for w in adapters.windows(2) {
n = match w[1] - w[0] {
1 => (n.1, n.2, n.0 + n.1 + n.2),
2 => (n.2, 0, n.1 + n.2),
3 => (0, 0, n.2),
_ => n,
}
}

n.2
}
}

fn main() {
let args = aoc::parse_args();
let mut puzzle = Puzzle::new();
puzzle.configure(args.path.as_str());
println!("{}", puzzle.part1());
println!("{}", puzzle.part2());
}

/// Test from puzzle input
#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_part1_1() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_1.txt");
assert_eq!(puzzle.part1(), 7 * 5);
}

#[test]
fn test_part1_2() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_2.txt");
assert_eq!(puzzle.part1(), 22 * 10);
}

#[test]
fn test_part2() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_2.txt");
assert_eq!(puzzle.part2(), 19208);
}
}
11 changes: 11 additions & 0 deletions 2020/day10/sample_1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
16
10
15
5
1
11
7
19
6
12
4
2 changes: 1 addition & 1 deletion 2020/day10/test.txt → 2020/day10/sample_2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
2
34
10
3
3
11 changes: 11 additions & 0 deletions 2020/day4/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "day4"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../../aoc" }

[[bin]]
name = "day4"
path = "day4.rs"
142 changes: 142 additions & 0 deletions 2020/day4/day4.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! [Day 4: Passport Processing](https://adventofcode.com/2020/day/4)
use std::collections::HashSet;

fn validate_field(field: &str, value: &str) -> bool {
match (field, value.len()) {
("byr", 4) => {
let byr: u32 = value.parse().unwrap_or(0);
(1920..=2002).contains(&byr)
}
("iyr", 4) => {
let iyr: u32 = value.parse().unwrap_or(0);
(2010..=2020).contains(&iyr)
}
("eyr", 4) => {
let eyr: u32 = value.parse().unwrap_or(0);
(2020..=2030).contains(&eyr)
}
("hgt", _) => value.strip_suffix("in").map_or_else(
|| {
value.strip_suffix("cm").map_or(false, |centimeters| {
let height: u8 = centimeters.parse().unwrap_or(0);
(150..=193).contains(&height)
})
},
|inches| {
let height: u8 = inches.parse().unwrap_or(0);
(59..=76).contains(&height)
},
),
("hcl", 7) => {
value.starts_with('#')
&& value
.chars()
.skip(1)
.all(|c| "abcdef0123456789".contains(c))
}
("ecl", 3) => ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"].contains(&value),
("pid", 9) => value.chars().all(|c| c.is_ascii_digit()),
_ => false,
}
}

struct Puzzle {
data: String,
}

impl Puzzle {
const fn new() -> Self {
Self {
data: String::new(),
}
}

/// Get the puzzle input.
fn configure(&mut self, path: &str) {
let data = std::fs::read_to_string(path).unwrap_or_else(|_| {
eprintln!("cannot read input file {path}");
std::process::exit(1);
});

self.data = data;
}

/// Solve part one.
fn part1(&self) -> u32 {
let mandatory_fields: HashSet<_> = ["eyr", "iyr", "byr", "ecl", "pid", "hcl", "hgt"]
.iter()
.copied()
.collect();

self.data
.split("\n\n")
.map(|record| {
let mut fields = HashSet::new();
for item in record.split_ascii_whitespace() {
let (field, _) = item.split_once(':').unwrap();
fields.insert(field);
}
u32::from(fields.is_superset(&mandatory_fields))
})
.sum()
}

/// Solve part two.
fn part2(&self) -> u32 {
let mandatory_fields: HashSet<_> = ["eyr", "iyr", "byr", "ecl", "pid", "hcl", "hgt"]
.iter()
.copied()
.collect();

self.data
.split("\n\n")
.map(|record| {
let mut fields = HashSet::new();
for item in record.split_ascii_whitespace() {
let (field, value) = item.split_once(':').unwrap();

if validate_field(field, value) {
fields.insert(field);
}
}
u32::from(fields.is_superset(&mandatory_fields))
})
.sum()
}
}

fn main() {
let args = aoc::parse_args();
let mut puzzle = Puzzle::new();
puzzle.configure(args.path.as_str());
println!("{}", puzzle.part1());
println!("{}", puzzle.part2());
}

/// Test from puzzle input
#[cfg(test)]
mod test {
use super::*;

#[test]
fn test_part1() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_1.txt");
assert_eq!(puzzle.part1(), 2);
}

#[test]
fn test_part2_invalid() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_3.txt");
assert_eq!(puzzle.part2(), 0);
}

#[test]
fn test_part2_valid() {
let mut puzzle = Puzzle::new();
puzzle.configure("sample_4.txt");
assert_eq!(puzzle.part2(), 4);
}
}
13 changes: 13 additions & 0 deletions 2020/day4/sample_1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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
13 changes: 13 additions & 0 deletions 2020/day4/sample_3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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
12 changes: 12 additions & 0 deletions 2020/day4/sample_4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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
11 changes: 11 additions & 0 deletions 2020/day5/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "day5"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../../aoc" }

[[bin]]
name = "day5"
path = "day5.rs"
Loading

0 comments on commit 9e25af2

Please sign in to comment.