Some changes

This commit is contained in:
Malte Tammena 2022-12-03 22:03:18 +01:00
parent 730ba8e885
commit 7982e1c56f
3 changed files with 87 additions and 30 deletions

View file

@ -50,12 +50,11 @@ fn replace_rand<I>(rng: &mut rand::rngs::SmallRng, list: &mut Vec<I>, item: I) {
}
fn gen_triple(rng: &mut rand::rngs::SmallRng) -> [String; 3] {
let amounts = ARGS.half_line_range().choose_multiple(rng, 3);
// The badge that is shared in this triple
let badge: char = *CHARS.choose(rng).unwrap();
let mut lines: Vec<String> = amounts
.iter()
.map(|&amount| {
let mut lines: Vec<String> = (0..3)
.map(|_| {
let amount = rng.gen_range(ARGS.half_line_range());
debug_assert!(amount > 0);
// The item that is shared between the halves
let wrong_between_halves: char = *CHARS

62
day03/src/bitmask.rs Normal file
View file

@ -0,0 +1,62 @@
use std::ops::{BitAnd, BitOr};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Bitmask(u64);
impl Bitmask {
#[cfg(test)]
pub const fn from_raw(raw: u64) -> Self {
Self(raw)
}
pub const fn from_alpha(alpha: &u8) -> Self {
// 'a' is the LSB, 'Z' is MSB
if *alpha <= b'Z' {
Self(1 << (alpha - b'A' + 26))
} else {
Self(1 << (alpha - b'a'))
}
}
/// Get the priority from a rucksack entry
pub const fn to_priority(self) -> super::Prio {
self.0.trailing_zeros() as usize + 1
}
}
impl const BitOr for Bitmask {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl const BitAnd for Bitmask {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl std::fmt::Binary for Bitmask {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:b}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bitmask_works() {
assert_eq!(
crate::parse_chars::<String>("abc".into()),
Bitmask::from_raw(7)
);
assert_eq!(
crate::parse_chars::<String>("Z".into()),
Bitmask::from_raw(1 << 51)
);
}
}

View file

@ -1,13 +1,18 @@
#![allow(incomplete_features)]
#![feature(iter_array_chunks)]
#![feature(generic_const_exprs)]
#![feature(const_trait_impl)]
#![feature(const_ops)]
use bitmask::Bitmask;
use std::{
fs::File,
io::{BufRead, BufReader},
};
mod bitmask;
type Prio = usize;
type AsciiChar = u8;
#[derive(Debug, Default)]
enum SolvePuzzle {
@ -23,39 +28,29 @@ trait IsTrue {}
/// A correct assertion, of course, is true!
impl IsTrue for Assert<true> {}
/// Get the priority from a rucksack entry
fn to_priority(char: AsciiChar) -> Prio {
match char {
// a..z have priority 1..=26
b'a'..=b'z' => (char - b'a' + 1) as usize,
// A..Z have priority 27..=52
b'A'..=b'Z' => (char - b'A' + 27) as usize,
_ => unreachable!(),
}
}
/// Convert the line into a list of ascii chars
fn parse_chars(line: String) -> Vec<AsciiChar> {
line.as_bytes().to_vec()
fn parse_chars<S: AsRef<str>>(line: S) -> Bitmask {
line.as_ref()
.as_bytes()
.iter()
.map(Bitmask::from_alpha)
.reduce(std::ops::BitOr::bitor)
.unwrap()
}
/// Given an array of size `N` containing lists of chars.
/// Find the char that is contained in all `N` lists, if any.
fn find_n_entry<const N: usize>(lists: [Vec<AsciiChar>; N]) -> Option<AsciiChar>
fn find_n_entry<const N: usize>(lists: [Bitmask; N]) -> Option<Bitmask>
where
Assert<{ N > 1 }>: IsTrue,
{
let mut found = lists[0].clone();
for list in &lists[1..] {
found.retain(|char| list.contains(char))
}
found.first().copied()
lists.into_iter().reduce(|left, right| left & right)
}
/// Split the given [`Vec`] in the middle
fn split_line(line: Vec<AsciiChar>) -> [Vec<AsciiChar>; 2] {
/// Split the given [`String`] in the middle
fn split_line(line: String) -> [String; 2] {
let (left, right) = line.split_at(line.len() / 2);
[left.to_vec(), right.to_vec()]
[left.to_string(), right.to_string()]
}
/// Solve the first puzzle:
@ -65,11 +60,12 @@ fn solve_first_puzzle<B: BufRead>(reader: B) -> usize {
reader
.lines()
.map(Result::unwrap)
.flat_map(split_line)
.map(parse_chars)
.map(split_line)
.array_chunks::<2>()
.map(find_n_entry)
.map(Option::unwrap)
.map(to_priority)
.map(Bitmask::to_priority)
.sum()
}
@ -84,7 +80,7 @@ fn solve_second_puzzle<B: BufRead>(reader: B) -> usize {
.array_chunks::<3>()
.map(find_n_entry)
.map(Option::unwrap)
.map(to_priority)
.map(Bitmask::to_priority)
.sum()
}