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
111
112
113
114
115
116
117
118
119
120
121
122
|
use crate::{Problem, Solution};
pub struct Day06;
impl Problem for Day06 {
const DAY: u8 = 6;
const INPUT: &'static str = include_str!("../input/day_06.txt");
}
impl Solution for Day06 {
type Answer1 = usize;
type Answer2 = usize;
fn part_1(input: &str) -> anyhow::Result<Self::Answer1> {
let (time, dist) = input.split_once('\n').expect("Invalid input lines");
let races = time
.split_whitespace()
.skip(1)
.zip(dist.split_whitespace().skip(1))
.map(TryFrom::try_from)
.try_collect::<Vec<Race>>()?;
races
.iter()
.map(Race::wins)
.reduce(|acc, n| acc * n)
.ok_or(anyhow::format_err!("Failed to find race"))
}
fn part_2(input: &str) -> anyhow::Result<Self::Answer2> {
let race: Race = input.parse()?;
Ok(race.wins())
}
}
#[derive(Debug)]
struct Race {
time: usize,
dist: usize,
}
impl Race {
fn run(&self, speed: usize) -> bool {
(speed * (self.time - speed)) > self.dist
}
fn wins(&self) -> usize {
let mut count = 0;
for speed in 1..self.time {
if self.run(speed) {
count += 1;
} else if count > 0 {
break;
}
}
count
}
}
impl TryFrom<(&str, &str)> for Race {
type Error = std::num::ParseIntError;
fn try_from((time, dist): (&str, &str)) -> Result<Self, Self::Error> {
Ok(Self {
time: time.parse()?,
dist: dist.parse()?,
})
}
}
impl std::str::FromStr for Race {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (time, dist) = s
.trim()
.split_once('\n')
.ok_or(anyhow::format_err!("Invalid race format"))?;
let time = time
.strip_prefix("Time: ")
.ok_or(anyhow::format_err!("Invalid time format"))?
.chars()
.filter(|c| *c != ' ')
.collect::<String>()
.trim()
.parse()?;
let dist = dist
.strip_prefix("Distance: ")
.ok_or(anyhow::format_err!("Invalid distance format"))?
.chars()
.filter(|c| *c != ' ')
.collect::<String>()
.trim()
.parse()?;
Ok(Race { time, dist })
}
}
#[cfg(test)]
mod tests {
use super::*;
const INPUT: &str = indoc::indoc! {"
Time: 7 15 30
Distance: 9 40 200
"};
#[test]
fn test_part_1() -> anyhow::Result<()> {
Ok(assert_eq!(288, Day06::part_1(INPUT)?))
}
#[test]
fn test_part_2() -> anyhow::Result<()> {
Ok(assert_eq!(71503, Day06::part_2(INPUT)?))
}
}
|