Day 3 in Rust

This commit is contained in:
Smaug123
2021-12-03 18:48:44 +00:00
parent 8329dc9c40
commit 7551e5e3b3
7 changed files with 1245 additions and 0 deletions

View File

@@ -2,4 +2,5 @@
members = [
"day_1",
"day_2",
"day_3",
]

15
day_3/Cargo.toml Normal file
View File

@@ -0,0 +1,15 @@
[package]
name = "day_3"
version = "0.1.0"
authors = ["Smaug123 <patrick+github@patrickstevens.co.uk>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dev-dependencies]
criterion = "0.3"
[[bench]]
name = "day_3"
harness = false

19
day_3/benches/day_3.rs Normal file
View File

@@ -0,0 +1,19 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use day_3::day_3::{input, part_1, part_2};
fn criterion_benchmark(c: &mut Criterion) {
let input = input::<12>();
c.bench_function("day 3 part 1", |b| {
b.iter(|| {
black_box(part_1(&input));
})
});
c.bench_function("day 3 part 2", |b| {
b.iter(|| {
black_box(part_2(&input));
})
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

7
day_3/day_3.m Normal file
View File

@@ -0,0 +1,7 @@
(* ::Package:: *)
nums=Import[StringJoin[NotebookDirectory[], "/input.txt"],"Table"];
part1 = 1##&@@Tr[1##&@@@(#/."up"->-"down")]&;
part2=1##&@@Rest@Fold[Function[{state,elt},Switch[elt[[1]],"forward",state+{0,elt[[2]],state[[1]] elt[[2]]},"down",MapAt[elt[[2]]+#&,state,1],"up",MapAt[#-elt[[2]]&,state,1]]],{0,0,0},#]&;

1000
day_3/input.txt Normal file

File diff suppressed because it is too large Load Diff

196
day_3/src/lib.rs Normal file
View File

@@ -0,0 +1,196 @@
pub mod day_3 {
use std::cmp::Ordering;
pub(crate) fn parse<const N: usize>(s: &str) -> [bool; N] {
let mut answer = [false; N];
for (i, c) in s.chars().enumerate() {
answer[i] = c != '0';
}
answer
}
pub fn input<const N: usize>() -> Vec<[bool; N]> {
let input = include_str!("../input.txt");
input
.trim()
.split('\n')
.map(parse)
.collect::<Vec<[bool; N]>>()
}
// lol interview prep
fn boyer_moore_majority_element<I, U>(input: I) -> U
where
U: Eq,
U: Copy,
I: Iterator<Item = U>,
{
let mut counter = 0;
let mut bag = None;
for elt in input {
if counter == 0 {
bag = Some(elt);
counter = 1;
} else if elt == bag.unwrap() {
counter += 1;
} else {
counter -= 1;
}
}
bag.unwrap()
}
fn most_common<const N: usize>(bits: &[[bool; N]], pos: usize) -> bool {
boyer_moore_majority_element(bits.iter().map(|arr| arr[pos]))
}
pub fn part_1<const N: usize>(bits: &[[bool; N]]) -> u32 {
let mut gamma = 0;
let mut eps = 0;
for i in 0..N {
let most = most_common(bits, i);
gamma = gamma * 2 + if most { 1 } else { 0 };
eps = eps * 2 + if most { 0 } else { 1 };
}
gamma * eps
}
fn majority_element_weak<I>(input: I, default: bool) -> Option<bool>
where
I: Iterator<Item = bool>,
{
let mut falses = 0;
let mut trues = 0;
for elt in input {
if elt {
trues += 1;
} else {
falses += 1;
}
}
if trues + falses == 1 {
return None;
}
match trues.cmp(&falses) {
Ordering::Greater => Some(true),
Ordering::Less => Some(false),
Ordering::Equal => Some(default),
}
}
fn most_common_skipping<F, const N: usize>(
bits: &[[bool; N]],
pos: usize,
default: bool,
should_ignore: F,
) -> Result<&[bool; N], bool>
where
F: Fn(&[bool; N]) -> bool,
{
let mut elt = None;
let majority = majority_element_weak(
bits.iter().filter(|&a| !should_ignore(a)).map(|arr| {
elt = Some(arr);
arr[pos]
}),
default,
);
match majority {
None => Ok(elt.unwrap()),
Some(b) => Err(b),
}
}
fn agree<const N: usize>(b1: &[bool; N], b2: &[bool; N], count: usize) -> bool {
for i in 0..count {
if b1[i] != b2[i] {
return false;
}
}
true
}
fn to_u16<const N: usize>(bits: [bool; N]) -> u16 {
let mut ans = 0;
for b in bits.iter() {
ans = ans * 2 + if *b { 1 } else { 0 };
}
ans
}
pub fn oxygen<const N: usize>(bits: &[[bool; N]]) -> u16 {
let mut most_common_arr = [false; N];
for i in 0..N {
let most = most_common_skipping(bits, i, true, |arr| !agree(&most_common_arr, arr, i));
match most {
Ok(answer) => {
return to_u16(*answer);
}
Err(b) => {
most_common_arr[i] = b;
}
}
}
to_u16(most_common_arr)
}
pub fn co2<const N: usize>(bits: &[[bool; N]]) -> u16 {
let mut least_common_arr = [false; N];
for i in 0..N {
let most = most_common_skipping(bits, i, true, |arr| !agree(&least_common_arr, arr, i));
match most {
Ok(answer) => {
return to_u16(*answer);
}
Err(b) => {
least_common_arr[i as usize] = !b;
}
}
}
to_u16(least_common_arr)
}
pub fn part_2<const N: usize>(bits: &[[bool; N]]) -> u32 {
let oxygen = oxygen(bits);
let co = co2(bits);
(oxygen as u32) * (co as u32)
}
}
#[cfg(test)]
mod tests {
use super::day_3::*;
#[test]
fn part1_known() {
let input = [
"00100", "11110", "10110", "10111", "10101", "01111", "00111", "11100", "10000",
"11001", "00010", "01010",
]
.map(parse::<5>);
assert_eq!(part_1(&input), 198);
}
#[test]
fn part2_known() {
let input = [
"00100", "11110", "10110", "10111", "10101", "01111", "00111", "11100", "10000",
"11001", "00010", "01010",
]
.map(parse::<5>);
assert_eq!(part_2(&input), 230);
}
#[test]
fn test_day_2() {
let input = input::<12>();
assert_eq!(part_1(&input), 3374136);
assert_eq!(part_2(&input), 1620141160);
}
}

7
day_3/src/main.rs Normal file
View File

@@ -0,0 +1,7 @@
use day_3::day_3;
fn main() {
let input = day_3::input::<12>();
println!("part 1 => {}", day_3::part_1(&input));
println!("part 2 => {}", day_3::part_2(&input));
}