-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday-2.rs
110 lines (94 loc) · 2.79 KB
/
day-2.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use aoc_2023::{str_block, Error};
use std::str::FromStr;
const INPUT: &str = include_str!("day-2.txt");
#[allow(dead_code)]
const INPUT_EX: &str = str_block! {"
Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
"};
aoc_2023::aoc! {
struct Day2 {
games: Vec<Game>,
}
self(input = INPUT) {
Ok(Self { games: input.lines().map(|line| {
let (_, line) = line.split_once(": ").ok_or("invalid line")?;
line.parse::<Game>()
}).collect::<Result<Vec<_>, _>>()?})
}
1 part1 usize {
Ok(self.games.iter().enumerate().filter(|(_, game)| game.is_valid(12, 13, 14)).map(|(i, _)| i + 1).sum())
}
2 part2 usize {
Ok(self.games.iter().map(|game| {
let Round { red, green, blue } = game.fewest();
red * green * blue
}).sum())
}
INPUT_EX { 1 part1 = 8, 2 part2 = 2286 }
INPUT { 1 part1 = 2683, 2 part2 = 49710 }
}
#[derive(Clone)]
struct Game {
round: Vec<Round>,
}
impl FromStr for Game {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self {
round: s
.split("; ")
.map(|s| s.parse())
.collect::<Result<Vec<_>, _>>()?,
})
}
}
impl Game {
fn is_valid(&self, r: usize, g: usize, b: usize) -> bool {
self.round.iter().all(|round| round.is_valid(r, g, b))
}
fn fewest(&self) -> Round {
let mut red = 0;
let mut green = 0;
let mut blue = 0;
for r in self.round.iter() {
red = red.max(r.red);
green = green.max(r.green);
blue = blue.max(r.blue);
}
Round { red, green, blue }
}
}
#[derive(Clone)]
struct Round {
red: usize,
green: usize,
blue: usize,
}
impl FromStr for Round {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut red = 0;
let mut green = 0;
let mut blue = 0;
for s in s.split(", ") {
let (n, col) = s.split_once(' ').ok_or("missing space in round")?;
let n = n.parse().map_err(|_| format!("invalid quantity `{n}`"))?;
match col {
"red" => red = n,
"green" => green = n,
"blue" => blue = n,
_ => return Err(Error::from("unknown color")),
}
}
Ok(Self { red, green, blue })
}
}
impl Round {
fn is_valid(&self, r: usize, g: usize, b: usize) -> bool {
self.red <= r && self.green <= g && self.blue <= b
}
}