From aa464884fe6306145a4c6a58cf6485d6505de97b Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 8 Dec 2021 20:15:42 +0100 Subject: [PATCH] 2021 day8/rust: add solutions --- 2021/day8/day8_rs/Cargo.toml | 15 +++++++++ 2021/day8/day8_rs/src/lib.rs | 13 ++++++++ 2021/day8/day8_rs/src/main.rs | 23 +++++++++++++ 2021/day8/day8_rs/src/v1.rs | 51 ++++++++++++++++++++++++++++ 2021/day8/day8_rs/src/v2.rs | 52 +++++++++++++++++++++++++++++ 2021/day8/day8_rs/src/v3.rs | 63 +++++++++++++++++++++++++++++++++++ 2021/day8/day8_rs/src/v4.rs | 63 +++++++++++++++++++++++++++++++++++ 7 files changed, 280 insertions(+) create mode 100644 2021/day8/day8_rs/Cargo.toml create mode 100644 2021/day8/day8_rs/src/lib.rs create mode 100644 2021/day8/day8_rs/src/main.rs create mode 100644 2021/day8/day8_rs/src/v1.rs create mode 100644 2021/day8/day8_rs/src/v2.rs create mode 100644 2021/day8/day8_rs/src/v3.rs create mode 100644 2021/day8/day8_rs/src/v4.rs diff --git a/2021/day8/day8_rs/Cargo.toml b/2021/day8/day8_rs/Cargo.toml new file mode 100644 index 0000000..4d61240 --- /dev/null +++ b/2021/day8/day8_rs/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "day8_rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[dev-dependencies] +criterion = "0.3.5" + +[[bench]] +name = "unscramble" +harness = false diff --git a/2021/day8/day8_rs/src/lib.rs b/2021/day8/day8_rs/src/lib.rs new file mode 100644 index 0000000..8eaacaf --- /dev/null +++ b/2021/day8/day8_rs/src/lib.rs @@ -0,0 +1,13 @@ +#![warn(clippy::pedantic)] +#![deny(unsafe_op_in_unsafe_fn)] + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct LineResult { + pub unique_digits: usize, + pub number: usize, +} + +pub mod v1; +pub mod v2; +pub mod v3; +pub mod v4; diff --git a/2021/day8/day8_rs/src/main.rs b/2021/day8/day8_rs/src/main.rs new file mode 100644 index 0000000..3bd7ec2 --- /dev/null +++ b/2021/day8/day8_rs/src/main.rs @@ -0,0 +1,23 @@ +#![warn(clippy::pedantic)] +use day8_rs::{v3::unscramble, LineResult}; +use std::io::{stdin, BufRead}; + +fn main() { + let result = stdin() + .lock() + .lines() + .map(|s| unscramble(&s.unwrap())) + .fold( + LineResult { + unique_digits: 0, + number: 0, + }, + |a, b| LineResult { + unique_digits: a.unique_digits + b.unique_digits, + number: a.number + b.number, + }, + ); + + println!("{}", result.unique_digits); + println!("{}", result.number); +} diff --git a/2021/day8/day8_rs/src/v1.rs b/2021/day8/day8_rs/src/v1.rs new file mode 100644 index 0000000..c2096dd --- /dev/null +++ b/2021/day8/day8_rs/src/v1.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; + +use crate::LineResult; + +#[inline] +fn lookup(n: usize) -> usize { + match n { + 17 => 1, + 25 => 7, + 30 => 4, + 34 => 2, + 37 => 5, + 39 => 3, + 41 => 6, + 42 => 0, + 49 => 8, + 45 => 9, + _ => unreachable!(), + } +} + +#[inline] +#[must_use] +pub fn unscramble(line: &str) -> LineResult { + let mut parts = line.split('|'); + let input = parts.next().unwrap(); + + let mut counts: HashMap<_, usize> = HashMap::new(); + for c in input.chars() { + *counts.entry(c).or_default() += 1; + } + + let digits: Vec<_> = parts + .next() + .unwrap() + .trim() + .split(' ') + .map(|s| s.chars().map(|c| counts[&c]).sum()) + .map(lookup) + .collect(); + + LineResult { + unique_digits: digits.iter().filter(|d| [1, 4, 7, 8].contains(d)).count(), + number: digits + .iter() + .map(|&d| char::from_digit(d as u32, 10).unwrap()) + .collect::() + .parse() + .unwrap(), + } +} diff --git a/2021/day8/day8_rs/src/v2.rs b/2021/day8/day8_rs/src/v2.rs new file mode 100644 index 0000000..135fa54 --- /dev/null +++ b/2021/day8/day8_rs/src/v2.rs @@ -0,0 +1,52 @@ +use crate::LineResult; + +const FREQ_TABLE: [usize; 50] = { + let mut tab = [0; 50]; + tab[17] = 1; + tab[25] = 7; + tab[30] = 4; + tab[34] = 2; + tab[37] = 5; + tab[39] = 3; + tab[41] = 6; + tab[42] = 0; + tab[45] = 9; + tab[49] = 8; + tab +}; + +#[must_use] +#[inline] +pub fn unscramble(line: &str) -> LineResult { + let mut parts = line.split('|'); + let input = parts.next().unwrap(); + + let mut counts = [0; 7]; + for c in input.bytes() { + if (b'a'..=b'g').contains(&c) { + counts[c as usize - b'a' as usize] += 1; + } + } + + let digits: Vec<_> = parts + .next() + .unwrap() + .trim() + .split(' ') + .map(|s| s.bytes().map(|c| counts[c as usize - b'a' as usize]).sum()) + .map(|n: usize| FREQ_TABLE[n]) + .collect(); + + LineResult { + unique_digits: digits.iter().filter(|d| [1, 4, 7, 8].contains(d)).count(), + number: digits + .iter() + .rev() + .scan(1, |mul, &d| { + let ret = Some(d * *mul); + *mul *= 10; + ret + }) + .sum(), + } +} diff --git a/2021/day8/day8_rs/src/v3.rs b/2021/day8/day8_rs/src/v3.rs new file mode 100644 index 0000000..ff5adc6 --- /dev/null +++ b/2021/day8/day8_rs/src/v3.rs @@ -0,0 +1,63 @@ +use crate::LineResult; + +const FREQ_TABLE: [usize; 256] = { + let mut tab = [0; 256]; + tab[17] = 1; + tab[25] = 7; + tab[30] = 4; + tab[34] = 2; + tab[37] = 5; + tab[39] = 3; + tab[41] = 6; + tab[42] = 0; + tab[45] = 9; + tab[49] = 8; + tab +}; + +#[must_use] +#[inline] +pub fn unscramble(line: &str) -> LineResult { + let mut bytes = line.bytes(); + + let mut counts = [0; 7]; + loop { + match bytes.next().unwrap() { + c @ b'a'..=b'g' => { + counts[c as usize - b'a' as usize] += 1; + } + b'|' => break, + _ => {} + } + } + + bytes.next(); + + let mut freq = 0; + let mut unique_digits = 0; + let mut number = 0; + loop { + let c = bytes.next(); + match c { + Some(b' ') | None => { + let digit = FREQ_TABLE[freq & 0xff]; + if [1, 4, 7, 8].contains(&digit) { + unique_digits += 1; + } + number = number * 10 + digit; + freq = 0; + if c.is_none() { + break; + } + } + Some(c) => { + freq += counts[c as usize - b'a' as usize]; + } + } + } + + LineResult { + unique_digits, + number, + } +} diff --git a/2021/day8/day8_rs/src/v4.rs b/2021/day8/day8_rs/src/v4.rs new file mode 100644 index 0000000..76bd80a --- /dev/null +++ b/2021/day8/day8_rs/src/v4.rs @@ -0,0 +1,63 @@ +use crate::LineResult; + +const FREQ_TABLE: [usize; 256] = { + let mut tab = [0; 256]; + tab[17] = 1; + tab[25] = 7; + tab[30] = 4; + tab[34] = 2; + tab[37] = 5; + tab[39] = 3; + tab[41] = 6; + tab[42] = 0; + tab[45] = 9; + tab[49] = 8; + tab +}; + +#[must_use] +#[inline] +pub fn unscramble(line: &str) -> LineResult { + let mut bytes = line.bytes(); + + let mut counts = [0; 7]; + loop { + match bytes.next().unwrap() { + c @ b'a'..=b'g' => { + *unsafe { counts.get_unchecked_mut(c as usize - b'a' as usize) } += 1; + } + b'|' => break, + _ => {} + } + } + + bytes.next(); + + let mut freq = 0; + let mut unique_digits = 0; + let mut number = 0; + loop { + let c = bytes.next(); + match c { + Some(b' ') | None => { + let digit = FREQ_TABLE[freq & 0xff]; + if [1, 4, 7, 8].contains(&digit) { + unique_digits += 1; + } + number = number * 10 + digit; + freq = 0; + if c.is_none() { + break; + } + } + Some(c) => { + freq += unsafe { counts.get_unchecked(c as usize - b'a' as usize) }; + } + } + } + + LineResult { + unique_digits, + number, + } +}