-
Notifications
You must be signed in to change notification settings - Fork 1
/
day3.rs
94 lines (78 loc) · 2.26 KB
/
day3.rs
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
use std::ops::Range;
use itertools::Itertools;
use aoc_2021::shared::{Day, read_input_lines};
fn main() {
Day3 {
input: read_input_lines(3)
}.run()
}
struct Day3 {
input: Vec<String>,
}
impl Day for Day3 {
fn part1(&self) -> usize {
let binary = range(&self.input).map(|i| common_bit(&self.input, i)).join("");
decimal(binary.as_str()) * decimal(reverse_bits(binary.as_str()).as_str())
}
fn part2(&self) -> usize {
rating(&self.input, 0, false) * rating(&self.input, 0, true)
}
}
fn common_bit(bits: &[String], index: usize) -> char {
let count = bits.iter().filter_map(|s| s.chars().nth(index)).filter(|c| *c == '0').count();
if count > bits.len() / 2 {
'0'
} else {
'1'
}
}
fn rating(bits: &[String], index: usize, reverse: bool) -> usize {
let bit = if reverse { reverse_bit(common_bit(bits, index)) } else { common_bit(bits, index) };
let filtered: Vec<String> = bits.iter().filter(|s| s.chars().nth(index).unwrap() == bit).map(String::from).collect();
if filtered.len() == 1 {
return decimal(filtered[0].as_str());
}
rating(&filtered, index + 1, reverse)
}
fn reverse_bits(bits: &str) -> String {
bits.chars().map(reverse_bit).join("")
}
fn reverse_bit(bit: char) -> char {
if bit == '0' { '1' } else { '0' }
}
fn decimal(bits: &str) -> usize {
usize::from_str_radix(bits, 2).unwrap()
}
fn range(input: &[String]) -> Range<usize> {
0..input.first().unwrap().len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_sample() {
assert_eq!(sample_day().part1(), 198)
}
#[test]
fn part2_sample() {
assert_eq!(sample_day().part2(), 230)
}
fn sample_day() -> Day3 {
Day3 {
input: vec![
String::from("00100"),
String::from("11110"),
String::from("10110"),
String::from("10111"),
String::from("10101"),
String::from("01111"),
String::from("00111"),
String::from("11100"),
String::from("10000"),
String::from("11001"),
String::from("00010"),
String::from("01010"),
]
}
}
}