119 lines
2.7 KiB
Rust
119 lines
2.7 KiB
Rust
//! Day 2: Cube Conundrum
|
|
|
|
use once_cell::sync::Lazy;
|
|
use regex::Regex;
|
|
|
|
pub const DAY: u8 = 2;
|
|
pub const TITLE: &str = "Cube Conundrum";
|
|
|
|
#[derive(Debug)]
|
|
struct Game {
|
|
id: u32,
|
|
draws: Vec<Draw>,
|
|
}
|
|
|
|
#[derive(Debug, Default)]
|
|
struct Draw {
|
|
r: u32,
|
|
g: u32,
|
|
b: u32,
|
|
}
|
|
|
|
impl Draw {
|
|
fn max(&self, other: &Draw) -> Self {
|
|
Self {
|
|
r: self.r.max(other.r),
|
|
g: self.g.max(other.g),
|
|
b: self.b.max(other.b),
|
|
}
|
|
}
|
|
|
|
fn power(&self) -> u32 {
|
|
self.r * self.g * self.b
|
|
}
|
|
}
|
|
|
|
fn parse_games(input: Vec<String>) -> Vec<Game> {
|
|
static LINE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^Game (\d+): (.+)$").unwrap());
|
|
|
|
input
|
|
.iter()
|
|
.map(|line| {
|
|
let cap = LINE.captures(line).expect(line);
|
|
let id = cap[1].parse().unwrap();
|
|
let draws = cap[2]
|
|
.split("; ")
|
|
.map(|gstr| {
|
|
let (mut r, mut g, mut b) = (0, 0, 0);
|
|
for p in gstr.split(", ") {
|
|
if let Some(n) = p.strip_suffix(" red") {
|
|
r = n.parse().unwrap();
|
|
} else if let Some(n) = p.strip_suffix(" green") {
|
|
g = n.parse().unwrap();
|
|
} else if let Some(n) = p.strip_suffix(" blue") {
|
|
b = n.parse().unwrap();
|
|
} else {
|
|
panic!("invalid part: {p}")
|
|
}
|
|
}
|
|
|
|
Draw { r, g, b }
|
|
})
|
|
.collect();
|
|
|
|
Game { id, draws }
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub fn part1(input: Vec<String>) -> String {
|
|
parse_games(input)
|
|
.iter()
|
|
.filter_map(|g| {
|
|
if g.draws.iter().all(|d| d.r <= 12 && d.g <= 13 && d.b <= 14) {
|
|
Some(g.id)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.sum::<u32>()
|
|
.to_string()
|
|
}
|
|
|
|
pub fn part2(input: Vec<String>) -> String {
|
|
parse_games(input)
|
|
.iter()
|
|
.map(|g| {
|
|
g.draws
|
|
.iter()
|
|
.fold(Draw::default(), |acc, d| acc.max(d))
|
|
.power()
|
|
})
|
|
.sum::<u32>()
|
|
.to_string()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn t_example1() {
|
|
assert_eq!(part1(crate::read_example(DAY, 1)), "8");
|
|
}
|
|
|
|
#[test]
|
|
fn t_part1() {
|
|
assert_eq!(part1(crate::read_input(DAY)), "2006");
|
|
}
|
|
|
|
#[test]
|
|
fn t_example2() {
|
|
assert_eq!(part2(crate::read_example(DAY, 2)), "2286");
|
|
}
|
|
|
|
#[test]
|
|
fn t_part2() {
|
|
assert_eq!(part2(crate::read_input(DAY)), "84911");
|
|
}
|
|
}
|