This commit is contained in:
parent
666675342d
commit
183db991f9
1000
input/day03
Normal file
1000
input/day03
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,20 +8,19 @@ impl crate::day::Day for Day01 {
|
|||
}
|
||||
|
||||
fn part1(&self) -> String {
|
||||
let (a, _) = self.0.iter().fold((0, -1), increments);
|
||||
let (a, _) = self.0.iter().copied().fold((0, -1), increments);
|
||||
format!("{}", a)
|
||||
}
|
||||
|
||||
fn part2(&self) -> String {
|
||||
let ws = self.0.windows(3).map(|a| a.iter().fold(0, std::ops::Add::add)).collect::<Vec<i32>>();
|
||||
let (a, _) = ws.iter().fold((0, -1), increments);
|
||||
let (a, _) = ws.iter().copied().fold((0, -1), increments);
|
||||
format!("{}", a)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn increments((a, b): (i32, i32), c: &i32) -> (i32, i32) {
|
||||
let c = *c;
|
||||
fn increments((a, b): (i32, i32), c: i32) -> (i32, i32) {
|
||||
if b == -1 {
|
||||
(a, c)
|
||||
} else if c > b {
|
||||
|
|
173
src/day03.rs
Normal file
173
src/day03.rs
Normal file
|
@ -0,0 +1,173 @@
|
|||
use crate::Day;
|
||||
|
||||
pub struct Day03(Vec<Vec<bool>>);
|
||||
|
||||
impl Day for Day03 {
|
||||
fn init(content: String) -> Self {
|
||||
let v = content.lines().map(split_lines).collect();
|
||||
Self(v)
|
||||
}
|
||||
|
||||
fn part1(&self) -> String {
|
||||
format!("{}", self.gamma() * self.epsilon())
|
||||
}
|
||||
|
||||
fn part2(&self) -> String {
|
||||
format!("{}", self.ox() * self.co2())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Day03 {
|
||||
pub fn gamma_calc(&self) -> Vec<bool> {
|
||||
let mut result = Vec::new();
|
||||
for i in 0..self.0[0].len() {
|
||||
let bit = !matches!(most_common_bit(&self.0.clone(), i), CommonBit::Zero);
|
||||
result.push(bit);
|
||||
}
|
||||
result
|
||||
}
|
||||
pub fn eps_calc(&self) -> Vec<bool> {
|
||||
let mut result = Vec::new();
|
||||
for i in 0..self.0[0].len() {
|
||||
let bit = !matches!(most_common_bit(&self.0.clone(), i), CommonBit::Zero);
|
||||
result.push(!bit);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_oxygen_generator_rating_binary(&self) -> Vec<bool> {
|
||||
let mut working_set = self.0.clone();
|
||||
for i in 0..self.0[0].len() {
|
||||
let common_bit = !matches!(most_common_bit(&working_set.clone(), i), CommonBit::Zero);
|
||||
working_set = working_set
|
||||
.into_iter()
|
||||
.filter(|x| x[i] == common_bit)
|
||||
.collect();
|
||||
if working_set.len() == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
working_set[0].clone()
|
||||
}
|
||||
pub fn get_co2_scrubber_rating_binary(&self) -> Vec<bool> {
|
||||
let mut working_set = self.0.clone();
|
||||
for i in 0..self.0[0].len() {
|
||||
let common_bit = matches!(least_common_bit(&working_set.clone(), i), CommonBit::One);
|
||||
working_set = working_set
|
||||
.into_iter()
|
||||
.filter(|x| x[i] == common_bit)
|
||||
.collect();
|
||||
if working_set.len() == 1 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
working_set[0].clone()
|
||||
}
|
||||
|
||||
pub fn gamma(&self) -> u32 {
|
||||
convert(&self.gamma_calc())
|
||||
}
|
||||
pub fn epsilon(&self) -> u32 {
|
||||
convert(&self.eps_calc())
|
||||
}
|
||||
|
||||
pub fn ox(&self) -> u32 {
|
||||
convert(&self.get_oxygen_generator_rating_binary())
|
||||
}
|
||||
pub fn co2(&self) -> u32 {
|
||||
convert(&self.get_co2_scrubber_rating_binary())
|
||||
}
|
||||
}
|
||||
|
||||
enum CommonBit {
|
||||
Zero,
|
||||
One,
|
||||
Equal,
|
||||
}
|
||||
|
||||
fn most_common_bit(set: &[Vec<bool>], bit_position: usize) -> CommonBit {
|
||||
let ones_count = set.iter().fold(
|
||||
0,
|
||||
|ones, code| if code[bit_position] { ones + 1 } else { ones },
|
||||
);
|
||||
let len = (set.len() + 1) / 2;
|
||||
match ones_count.cmp(&len) {
|
||||
std::cmp::Ordering::Less => CommonBit::Zero,
|
||||
std::cmp::Ordering::Equal => CommonBit::Equal,
|
||||
std::cmp::Ordering::Greater => CommonBit::One,
|
||||
}
|
||||
}
|
||||
|
||||
fn least_common_bit(set: &[Vec<bool>], bit_position: usize) -> CommonBit {
|
||||
let ones_count = set.iter().fold(
|
||||
0,
|
||||
|ones, code| if code[bit_position] { ones + 1 } else { ones },
|
||||
);
|
||||
let len = (set.len() + 1) / 2;
|
||||
match ones_count.cmp(&len) {
|
||||
std::cmp::Ordering::Less => CommonBit::One,
|
||||
std::cmp::Ordering::Equal => CommonBit::Equal,
|
||||
std::cmp::Ordering::Greater => CommonBit::Zero,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(binary: &[bool]) -> u32 {
|
||||
binary.iter().fold(0, |result, &bit| (result << 1) ^ bit as u32)
|
||||
}
|
||||
|
||||
|
||||
fn split_lines(content: &str) -> Vec<bool> {
|
||||
content.chars().map(|x| x == '1').collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs::read_to_string;
|
||||
|
||||
use crate::Day03;
|
||||
use crate::day::Day;
|
||||
|
||||
const INPUT: &str = r"00100
|
||||
11110
|
||||
10110
|
||||
10111
|
||||
10101
|
||||
01111
|
||||
00111
|
||||
11100
|
||||
10000
|
||||
11001
|
||||
00010
|
||||
01010";
|
||||
|
||||
#[test]
|
||||
fn part1_test() {
|
||||
let t = Day03::init(String::from(INPUT));
|
||||
let p1 = t.part1();
|
||||
assert_eq!("198", p1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_test() {
|
||||
let t = Day03::init(String::from(INPUT));
|
||||
let p2 = t.part2();
|
||||
assert_eq!("230", p2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_real() {
|
||||
let f = read_to_string("./input/day03").expect("Could not load input");
|
||||
let t = Day03::init(f);
|
||||
let p1 = t.part1();
|
||||
assert_eq!("4118544", p1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_real() {
|
||||
let f = read_to_string("./input/day03").expect("Could not load input");
|
||||
let t = Day03::init(f);
|
||||
let p2 = t.part2();
|
||||
assert_eq!("3832770", p2)
|
||||
}
|
||||
}
|
19
src/main.rs
19
src/main.rs
|
@ -3,19 +3,21 @@ use chrono::Datelike;
|
|||
use clap::{App, Arg};
|
||||
use crate::day01::Day01;
|
||||
use crate::day02::Day02;
|
||||
use crate::day03::Day03;
|
||||
use crate::day::Day;
|
||||
|
||||
mod day;
|
||||
mod day01;
|
||||
mod day02;
|
||||
mod day03;
|
||||
|
||||
fn load_input(day: &str) -> String {
|
||||
read_to_string(format!("./input/day{}", day)).expect("Could not load input")
|
||||
}
|
||||
|
||||
fn run_day(days: &Vec<Box<dyn Day>>, day: usize) {
|
||||
fn run_day(days: &[Box<dyn Day>], day: usize) {
|
||||
if let Some(d) = days.get(day - 1) {
|
||||
let day_code = d.clone();
|
||||
let day_code = d;
|
||||
println!("Running day {}!", day);
|
||||
println!("\tPart 1: {}", d.part1());
|
||||
println!("\tPart 2: {}", day_code.part2());
|
||||
|
@ -42,25 +44,26 @@ fn main() {
|
|||
.multiple(true))
|
||||
.get_matches();
|
||||
|
||||
let days: Vec<Box<dyn Day>> = vec![Box::new(Day01::init(load_input("01"))), Box::new(Day02::init(load_input("02")))];
|
||||
let days: Vec<Box<dyn Day>> = vec![Box::new(Day01::init(load_input("01"))), Box::new(Day02::init(load_input("02"))),
|
||||
Box::new(Day03::init(load_input("03")))];
|
||||
|
||||
let _verbosity = matches.occurrences_of("v");
|
||||
if matches.is_present("all") {
|
||||
let l = days.len();
|
||||
println!("running {} days!", l);
|
||||
for v in 1..l + 1 {
|
||||
for v in 1..=l {
|
||||
run_day(&days, v);
|
||||
}
|
||||
} else if let Some(d) = matches.values_of("DAY") {
|
||||
let d = d.map(|x| x.parse::<i32>().expect("Did not provide an int!"));
|
||||
let d = d.map(|x| x.parse::<usize>().expect("Did not provide an int!"));
|
||||
for v in d {
|
||||
run_day(&days, v as usize);
|
||||
run_day(&days, v);
|
||||
}
|
||||
} else {
|
||||
let v = chrono::Local::now();
|
||||
if v.month() != 12 {
|
||||
println!("This was really only meant to be used in december...")
|
||||
println!("This was really only meant to be used in december...");
|
||||
}
|
||||
run_day(&days, v.day() as usize)
|
||||
run_day(&days, v.day() as usize);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue