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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
use anyhow::anyhow;
use std::{
env, fs,
ops::{Add, Sub},
str::FromStr,
};
#[derive(Debug, PartialEq, Eq)]
enum Rotation {
Left(u16),
Right(u16),
}
#[derive(Debug)]
struct ParseRotationError;
impl FromStr for Rotation {
type Err = ParseRotationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut chars = s.chars();
let lr = chars.next().ok_or(ParseRotationError)?;
let n: u16 = chars
.collect::<String>()
.parse()
.map_err(|_| ParseRotationError)?;
match lr {
'L' => Ok(Self::Left(n)),
'R' => Ok(Self::Right(n)),
_ => Err(ParseRotationError),
}
}
}
#[derive(Clone, Copy, Debug)]
struct Dial(u8);
impl Dial {
fn new() -> Self {
Self(50)
}
}
impl Add<u16> for Dial {
type Output = Self;
fn add(self, rhs: u16) -> Self::Output {
let n = self.0 as u16;
let m = (n + rhs) % 100;
Self(m as u8)
}
}
impl Sub<u16> for Dial {
type Output = Self;
fn sub(self, rhs: u16) -> Self::Output {
let n = self.0 as u16;
if rhs > n {
let m = 100 - (n + rhs) % 100;
Self(m as u8)
} else {
let m = n - rhs;
Self(m as u8)
}
}
}
impl PartialEq<u8> for Dial {
fn eq(&self, other: &u8) -> bool {
self.0 == *other
}
}
fn main() -> anyhow::Result<()> {
let mut args = env::args();
let input_path = args.nth(1).ok_or(anyhow!("usage: day1 INPUT"))?;
let input = fs::read_to_string(input_path)?;
let rotations: Vec<Rotation> = input
.split_whitespace()
.map(|s| s.parse().map_err(|_| anyhow!("bad rotation: {}", s)))
.collect::<anyhow::Result<_>>()?;
let mut dial = Dial::new();
let mut zeros = 0;
for rot in rotations {
println!("dial: {:?}", dial);
println!("rotation: {:?}", rot);
match rot {
Rotation::Left(n) => dial = dial - n,
Rotation::Right(n) => dial = dial + n,
}
if dial == 0 {
zeros = zeros + 1;
}
}
println!("zeros: {}", zeros);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_rotation() {
assert!("L2"
.parse::<Rotation>()
.is_ok_and(|rot| rot == Rotation::Left(2)));
assert!("R929"
.parse::<Rotation>()
.is_ok_and(|rot| rot == Rotation::Right(929)));
assert!("M1".parse::<Rotation>().is_err());
assert!("L".parse::<Rotation>().is_err());
assert!("2".parse::<Rotation>().is_err());
}
#[test]
fn dial() {
let dial = Dial::new();
assert_eq!(dial + 1, 51);
assert_eq!(dial + 50, 0);
assert_eq!(dial + 100, 50);
assert_eq!(dial + 150, 0);
assert_eq!(dial - 1, 49);
assert_eq!(dial - 68, 82);
assert_eq!(dial - 68 - 30, 52);
assert_eq!(dial - 100, 50);
}
}
|