Some changes
This commit is contained in:
parent
730ba8e885
commit
7982e1c56f
|
@ -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
62
day03/src/bitmask.rs
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue