summary refs log tree commit diff
path: root/03/src/main.rs
blob: 03c6d237ce06ed63bab9e8438d9d49f7a5aa34b5 (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
121
122
123
124
125
126
127
128
129
130
131
132
use advent_lib::prelude::*;


fn main() -> Result<()> {
  let mut args = std::env::args();
  if args.len() != 2 {
    eprintln!("Usage: advent input");
  }
  let _ = args.next();
  let filename = args.next().unwrap();

  let input = advent_lib::read_lines_file(&filename)?;

  {
    let mut frequencies = Vec::new();

    for _ in 0 .. input[0].len() {
      frequencies.push(0);
    }

    for line in &input {
      let mut i = 0;
      for c in line.chars() {
        match c {
          '1' => {
            frequencies[i] += 1;
          },
          _ => { }
        }

        i += 1;
      }
    }

    let n_lines = input.len();

    let mut gamma = 0;
    let mut epsilon = 0;

    for i in 0 .. frequencies.len() {
      let bit_value = 1 << frequencies.len() - i - 1;
      if frequencies[i] > n_lines / 2 {
        gamma += bit_value;
      } else {
        epsilon += bit_value;
      }
    }

    println!("{}", gamma * epsilon);
  }

  {
    let n_bits = input[0].len();

    let generator_line = filter(&input, 0, true);
    let mut generator = 0;

    for i in 0 .. n_bits {
      let bit_value = 1 << n_bits - i - 1;
      if generator_line.chars().nth(i).unwrap() == '1' {
        generator += bit_value;
      }
    }

    let scrubber_line = filter(&input, 0, false);
    let mut scrubber = 0;

    for i in 0 .. n_bits {
      let bit_value = 1 << n_bits - i - 1;
      if scrubber_line.chars().nth(i).unwrap() == '1' {
        scrubber += bit_value;
      }
    }

    println!("{}", generator * scrubber);
  }

  Ok(())
}


fn filter(input: &Vec<String>, bit_offset: usize, want_most: bool) -> String {
  if input.len() == 1 {
    return input[0].clone();
  }

  let mut frequency = 0;

  for line in input {
    match line.chars().nth(bit_offset).unwrap() {
      '1' => {
        frequency += 1;
      },
      _ => { }
    }
  }

  let is_tied = frequency * 2 == input.len();
  let one_is_most = frequency > input.len() / 2;

  let mut new_input = Vec::new();
  for line in input {
    let is_one = line.chars().nth(bit_offset).unwrap() == '1';
    let is_wanted = if is_tied {
      if want_most {
        is_one
      } else {
        !is_one
      }
    } else {
      if want_most {
        if one_is_most {
          is_one
        } else {
          !is_one
        }
      } else {
        if one_is_most {
          !is_one
        } else {
          is_one
        }
      }
    };
    if is_wanted {
      new_input.push(line.clone());
    }
  }

  return filter(&new_input, bit_offset + 1, want_most);
}