summaryrefslogtreecommitdiff
path: root/src/bin/day2.rs
blob: b094d02f95fd43bcd5970a1142596ba5e47b73f2 (plain)
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
static DAY: u8 = 2;

fn main() {
    let input = advent::read_lines(DAY);
    println!("{DAY}a: {}", game_score(&input, false));
    println!("{DAY}b: {}", game_score(&input, true));
}

#[derive(PartialEq, Eq, Clone, Copy)]
enum Shape {
    Rock,
    Paper,
    Scissors,
}

impl Shape {
    fn score(&self) -> u32 {
        match self {
            Shape::Rock => 1,
            Shape::Paper => 2,
            Shape::Scissors => 3,
        }
    }

    fn wins_against(&self) -> Shape {
        match self {
            Shape::Rock => Shape::Scissors,
            Shape::Paper => Shape::Rock,
            Shape::Scissors => Shape::Paper,
        }
    }

    fn draws_against(&self) -> Shape {
        *self
    }

    fn loses_against(&self) -> Shape {
        match self {
            Shape::Rock => Shape::Paper,
            Shape::Paper => Shape::Scissors,
            Shape::Scissors => Shape::Rock,
        }
    }
}

struct Round {
    opponent: Shape,
    you: Shape,
}

impl Round {
    fn new(input: &str, result_indicator: bool) -> Round {
        assert_eq!(input.len(), 3);
        let chars : Vec<char> = input.chars().collect();
        let opponent = match chars[0] {
            'A' => Shape::Rock,
            'B' => Shape::Paper,
            'C' => Shape::Scissors,
            _ => unreachable!(),
        };
        let you = if !result_indicator {
            match chars[2] {
                'X' => Shape::Rock,
                'Y' => Shape::Paper,
                'Z' => Shape::Scissors,
                _ => unreachable!(),
            }
        } else {
            match chars[2] {
                'X' => opponent.wins_against(),
                'Y' => opponent.draws_against(),
                'Z' => opponent.loses_against(),
                _ => unreachable!(),
            }
        };

        Round { opponent, you }
    }

    fn outcome_score(&self) -> u32 {
        if self.you.wins_against() == self.opponent {
            6
        } else if self.you.draws_against() == self.opponent {
            3
        } else if self.you.loses_against() == self.opponent {
            0
        } else {
            unreachable!()
        }
    }

    fn score(&self) -> u32 {
        self.outcome_score() + self.you.score()
    }
}

fn game_score(input: &[String], result_indicator: bool) -> u32 {
    let rounds = input.iter()
                      .map(|x| Round::new(x, result_indicator))
                      .collect::<Vec<_>>();
    rounds.iter()
          .map(|x| x.score())
          .sum()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        let input = [
            "A Y".to_string(),
            "B X".to_string(),
            "C Z".to_string(),
        ];
        assert_eq!(game_score(&input, false), 15);
        assert_eq!(game_score(&input, true), 12);
    }
}