Skip to content

Instantly share code, notes, and snippets.

@ThomasdenH
Created December 6, 2020 11:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasdenH/fddfa66908958cd5c0c506e189d4fc0d to your computer and use it in GitHub Desktop.
Save ThomasdenH/fddfa66908958cd5c0c506e189d4fc0d to your computer and use it in GitHub Desktop.
use aoc_runner_derive::aoc;
use std::iter::FromIterator;
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
struct AlphabetSet {
contains: u32,
}
impl AlphabetSet {
fn empty() -> Self {
AlphabetSet { contains: 0 }
}
fn one(c: u8) -> Self {
AlphabetSet {
contains: 1 << (c as u8 - b'a'),
}
}
fn all() -> Self {
(b'a'..=b'z').collect()
}
fn intersection(&self, other: &AlphabetSet) -> Self {
AlphabetSet {
contains: self.contains & other.contains,
}
}
fn union(&self, other: &AlphabetSet) -> Self {
AlphabetSet {
contains: self.contains | other.contains,
}
}
fn len(&self) -> usize {
self.contains.count_ones() as usize
}
}
impl FromIterator<u8> for AlphabetSet {
fn from_iter<I: IntoIterator<Item = u8>>(iter: I) -> Self {
iter.into_iter()
.map(AlphabetSet::one)
.fold(AlphabetSet::empty(), |acc, x| acc.union(&x))
}
}
#[aoc(day6, part1)]
fn part_01(input: &str) -> usize {
input
.split("\n\n")
.map(|lines| {
lines
.split('\n')
.map(|line| line.as_bytes().iter().copied().collect::<AlphabetSet>())
.fold(AlphabetSet::empty(), |acc, x| acc.union(&x))
.len()
})
.sum()
}
#[aoc(day6, part1, looping)]
fn part_01_looping(input: &[u8]) -> usize {
let mut iter = input.iter().copied();
let mut sum = 0;
let mut current_union = AlphabetSet::empty();
while let Some(c) = iter.next() {
if c == b'\n' {
sum += current_union.len();
current_union = AlphabetSet::empty();
} else {
// Read line
current_union = current_union.union(&AlphabetSet::one(c));
while let Some(c) = iter.next() {
if c == b'\n' {
break;
}
current_union = current_union.union(&AlphabetSet::one(c));
}
}
}
sum + current_union.len()
}
#[aoc(day6, part2)]
fn part_02(input: &str) -> usize {
input
.split("\n\n")
.map(|lines| {
lines
.lines()
.map(|c| c.as_bytes().iter().copied().collect())
.fold(AlphabetSet::all(), |acc, x| acc.intersection(&x))
.len()
})
.sum()
}
#[aoc(day6, part2, looping)]
fn part_02_looping(input: &[u8]) -> usize {
let mut iter = input.iter().copied().peekable();
let mut sum = 0;
let mut current_intersection = AlphabetSet::all();
while let Some(c) = iter.next() {
if c == b'\n' {
sum += current_intersection.len();
current_intersection = AlphabetSet::all();
} else {
// Read line
let mut line = AlphabetSet::one(c);
while let Some(c) = iter.next() {
if c == b'\n' {
break;
}
line = line.union(&AlphabetSet::one(c));
}
current_intersection = current_intersection.intersection(&line)
}
}
sum + current_intersection.len()
}
#[test]
fn test_example() {
let input = indoc::indoc! {"abc
a
b
c
ab
ac
a
a
a
a
b"};
assert_eq!(part_01(input), 11);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment