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
|
use {
anyhow::{
anyhow,
Context,
Result,
},
std::{
env::args,
fs::File,
io::{
BufRead,
BufReader,
},
path::Path,
},
};
#[derive(Clone,Copy)]
enum Play {
Rock = 1,
Paper = 2,
Scissors = 3,
}
impl Play {
fn strategy(&self, desired: Outcome) -> Play {
match (self, desired) {
(Play::Rock, Outcome::Lose) => Play::Scissors,
(Play::Rock, Outcome::Draw) => Play::Rock,
(Play::Rock, Outcome::Win) => Play::Paper,
(Play::Paper, Outcome::Lose) => Play::Rock,
(Play::Paper, Outcome::Draw) => Play::Paper,
(Play::Paper, Outcome::Win) => Play::Scissors,
(Play::Scissors, Outcome::Lose) => Play::Paper,
(Play::Scissors, Outcome::Draw) => Play::Scissors,
(Play::Scissors, Outcome::Win) => Play::Rock,
}
}
}
#[derive(Clone,Copy)]
enum Outcome {
Lose = 0,
Draw = 3,
Win = 6,
}
struct Game {
opponent: Play,
play: Play,
outcome: Outcome,
}
impl Game {
fn outcome(&self) -> Outcome {
match (&self.play, &self.opponent) {
(Play::Rock, Play::Rock) => Outcome::Draw,
(Play::Rock, Play::Paper) => Outcome::Lose,
(Play::Rock, Play::Scissors) => Outcome::Win,
(Play::Paper, Play::Rock) => Outcome::Win,
(Play::Paper, Play::Paper) => Outcome::Draw,
(Play::Paper, Play::Scissors) => Outcome::Lose,
(Play::Scissors, Play::Rock) => Outcome::Lose,
(Play::Scissors, Play::Paper) => Outcome::Win,
(Play::Scissors, Play::Scissors) => Outcome::Draw,
}
}
fn update(&mut self) {
self.play = self.opponent.strategy(self.outcome);
}
fn score(&self) -> usize {
self.play as usize + self.outcome() as usize
}
}
fn read_input<T: AsRef<Path>>(filename: T) -> Result<Vec<Game>> {
let reader = BufReader::new(File::open(filename)?);
reader.lines().map(
|v| {
let s = v?;
let fields: Vec<_> = s.split(' ').collect();
let opponent = match *(fields.first().ok_or_else(|| anyhow!("Parse error"))?) {
"A" => Ok(Play::Rock),
"B" => Ok(Play::Paper),
"C" => Ok(Play::Scissors),
_ => Err(anyhow!("Invalid input")),
}?;
let ( play, outcome ) = match *(fields.get(1).ok_or_else(|| anyhow!("Parse error"))?) {
"X" => Ok((Play::Rock, Outcome::Lose)),
"Y" => Ok((Play::Paper, Outcome::Draw)),
"Z" => Ok((Play::Scissors, Outcome::Win)),
_ => Err(anyhow!("Invalid input")),
}?;
Ok(Game { opponent, play, outcome })
}
).collect()
}
fn part1(input: &[Game]) -> Result<usize> {
Ok(input.iter().map(|game| game.score()).sum())
}
fn part2(input: &mut [Game]) -> Result<usize> {
Ok(input.iter_mut().map(|game| {
game.update();
game.score()
}).sum())
}
fn main() -> Result<()> {
let ( do_part_1, do_part_2 ) = aoc::do_parts();
let filename = args().nth(1).ok_or_else(|| anyhow!("Missing input filename"))?;
let mut input = read_input(filename).context("Could not read input")?;
if do_part_1 {
let solution = part1(&input).context("No solution for part 1")?;
println!("Part1, solution found to be: {}", solution);
}
if do_part_2 {
let solution = part2(&mut input).context("No solution for part 2")?;
println!("Part2, solution found to be: {}", solution);
}
Ok(())
}
|