summaryrefslogtreecommitdiff
path: root/src/day_3.rs
blob: 89951ead5ae87f084e5561f6314e82120b2c1759 (plain) (blame)
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
use std::ops::AddAssign;

#[derive(Clone)]
struct Oneness(isize);

fn part1(input: &[String])
{
    let scale = calculate_scale(input);

    let mut gamma = 0;
    let mut epsilon = 0;
    for (i, oneness) in scale.iter().rev().enumerate() {
        gamma += (oneness.is_one() || oneness.is_balanced()) as usize * 2_usize.pow(i as u32);
        epsilon += (oneness.is_zero() || oneness.is_balanced()) as usize * 2_usize.pow(i as u32);
    }

    println!("Solution to part 1: {}", gamma * epsilon);
}

fn part2(input: Vec<String>)
{
    let mut oxygen = input.clone();
    let mut pos: usize = 0;
    while oxygen.len() != 1 {
        let scale = calculate_scale(&oxygen);
        let looking_for_one = scale[pos].is_one() || scale[pos].is_balanced();
        oxygen = oxygen
            .into_iter()
            .filter(|s| {
                let char_is_one = s.as_bytes()[pos] == '1' as u8;
                looking_for_one == char_is_one
            })
            .collect();

        pos += 1;
    }

    let mut co2 = input;
    pos = 0;
    while co2.len() != 1 {
        let scale = calculate_scale(&co2);
        let looking_for_one = scale[pos].is_zero();
        co2 = co2
            .into_iter()
            .filter(|s| {
                let char_is_one = s.as_bytes()[pos] == '1' as u8;
                looking_for_one == char_is_one
            })
            .collect();

        pos += 1;
    }

    let oxygen = usize::from_str_radix(&oxygen[0], 2).unwrap();
    let co2 = usize::from_str_radix(&co2[0], 2).unwrap();

    println!("Solution to part 2: {}", oxygen * co2);
}

fn calculate_scale(input: &[String]) -> Vec<Oneness>
{
    let mut one_scale = vec![Oneness::balanced(); input[0].len()];
    for s in input.iter() {
        for (i, c) in s.char_indices() {
            one_scale[i] += match c {
                '1' => true,
                '0' => false,
                o => panic!("Invalid input: {}", o),
            };
        }
    }

    one_scale
}

pub fn run(input: Vec<String>)
{
    // Determine the number of bits by taking a look at the first string.
    let num_bits = input[0].len();
    let mut one_scale = vec![Oneness::balanced(); num_bits];

    part1(&input);
    part2(input);
}

impl Oneness
{
    pub const fn balanced() -> Self { Self(0) }

    pub fn is_one(&self) -> bool { self.0 > 0 }

    pub fn is_zero(&self) -> bool { self.0 < 0 }

    pub fn is_balanced(&self) -> bool { self.0 == 0 }
}

impl AddAssign<bool> for Oneness
{
    fn add_assign(&mut self, rhs: bool)
    {
        match rhs {
            true => self.0 += 1,
            false => self.0 -= 1,
        }
    }
}