Steve Klabnik

Apparently, the great eater-of-iron himself has graced us with his presence. Welcome, 'Steve', and thanks for your submissions!

steveklabnik/steveklabnik-day01.rs
steveklabnik/steveklabnik-day01.rs
fn solve(input: &str) -> (u32, u32) {
        let mut input: Vec<u32> = input.lines().map(|s| s.parse().unwrap()).collect();
        input.sort_unstable();
    
        let solve_a = |target, i| {
            input
                .iter()
                .skip(i)
                .copied()
                .take_while(|&a| a < target)
                .enumerate()
                .find(|&(j, a)| input[i + j + 1..].binary_search(&(target - a)).is_ok())
                .map(|(_, a)| a * (target - a))
        };
    
        (
            solve_a(2020, 0).unwrap(),
            input
                .iter()
                .copied()
                .enumerate()
                .filter_map(|(i, a)| solve_a(2020 - a, i + 1).map(|b| a * b))
                .next()
                .unwrap()
        )
    }
    
steveklabnik/steveklabnik-day02.rs
steveklabnik/steveklabnik-day02.rs
macro_rules! parse {
        ($input:ident, [$($split:literal),+], $($name:ident$(: $ty:ty)?),+) => {
            let mut iter = $input
                .split(|c| matches!(c, $($split)|+))
                .filter(|s| !s.is_empty());
    
            $( let $name = iter.next().unwrap()$(.parse::<$ty>().unwrap())?; )+
        };
    }
    
    fn solve(input: &str) -> (u32, u32) {
        input.lines().fold((0, 0), |(a, b), s| {
            parse!(s, [' ', '-', ':'], min: usize, max: usize, c: char, pass);
            let c = c as u8;
    
            (
                a + u32::from((min..=max).contains(&pass.bytes().filter(|&b| b == c).count())),
                b + u32::from((pass.as_bytes()[min - 1] == c) ^ (pass.as_bytes()[max - 1] == c))
            )
        })
    }
    
steveklabnik/steveklabnik-day03.rs
steveklabnik/steveklabnik-day03.rs
use std::iter::successors;
    
    fn solve(input: &str) -> (u32, u64) {
        let width = input.find('\n').unwrap();
        let height = input.len() / (width + 1);
        debug_assert!(input.len() % (width + 1) == 0);
    
        let count_trees = |dx, dy| {
            (0..height)
                .step_by(dy)
                .zip(successors(Some(0), |x| Some((x + dx) % width)))
                .map(|(y, x)| u32::from(input.as_bytes()[y * (width + 1) + x] == b'#'))
                .sum()
        };
    
        let counts = [
            count_trees(1, 1),
            count_trees(3, 1),
            count_trees(5, 1),
            count_trees(7, 1),
            count_trees(1, 2)
        ];
    
        (counts[1], counts.iter().copied().map(u64::from).product())
    }
    
steveklabnik/steveklabnik-day04.rs
steveklabnik/steveklabnik-day04.rs
use std::ops::RangeInclusive;
    
    fn solve(input: &str) -> (u32, u32) {
        input.split("\n\n").fold((0, 0), |(a, b), s| {
            let (keys, valid) = s
                .split_whitespace()
                .map(|s| {
                    let (k, v) = s.split_at(4);
    
                    match k {
                        "byr:" => (1 << 0, check_number(v, 4, 1920..=2002)),
                        "iyr:" => (1 << 1, check_number(v, 4, 2010..=2020)),
                        "eyr:" => (1 << 2, check_number(v, 4, 2020..=2030)),
                        "hgt:" => {
                            (
                                1 << 3,
                                v.strip_suffix("cm")
                                    .map(|v| check_number(v, 3, 150..=193))
                                    .xor(v.strip_suffix("in").map(|v| check_number(v, 2, 59..=76)))
                                    .unwrap_or(false)
                            )
                        }
                        "hcl:" => {
                            (
                                1 << 4,
                                v.strip_prefix("#").map_or(false, |v| {
                                    v.len() == 6 && u32::from_str_radix(&v[1..], 16).is_ok()
                                })
                            )
                        }
                        "ecl:" => {
                            (
                                1 << 5,
                                matches!(v, "amb" | "blu" | "brn" | "gry" | "grn" | "hzl" | "oth")
                            )
                        }
                        "pid:" => (1 << 6, v.len() == 9 && v.parse::<u32>().is_ok()),
                        "cid:" => (0, true),
                        _ => (0, false)
                    }
                })
                .fold((0, true), |(keys, valid), (k, v)| (keys | k, valid && v));
    
            let all_fields = keys == 0b0111_1111;
    
            (
                a + u32::from(all_fields),
                b + u32::from(all_fields && valid)
            )
        })
    }
    
    fn check_number(s: &str, len: usize, range: RangeInclusive<u32>) -> bool {
        s.len() == len && s.parse().map_or(false, |i| range.contains(&i))
    }
    
steveklabnik/steveklabnik-day05.rs
steveklabnik/steveklabnik-day05.rs
fn solve(input: &str) -> (u32, u32) {
        let (min, max, sum) = input
            .lines()
            .map(|s| {
                s.bytes()
                    .fold(0, |acc, b| (acc << 1) | u32::from(b == b'B' || b == b'R'))
            })
            .fold((!0, 0, 0), |(min, max, sum), id| {
                (min.min(id), max.max(id), sum ^ id)
            });
    
        (max, cum_xor(max) ^ cum_xor(min - 1) ^ sum)
    }
    
    fn cum_xor(a: u32) -> u32 {
        a, 1, a + 1, 0
    }
    
steveklabnik/steveklabnik-day06.rs
steveklabnik/steveklabnik-day06.rs
fn solve(input: &str) -> (u32, u32) {
        input
            .split("\n\n")
            .map(|s| {
                s.lines()
                    .map(|s| s.bytes().fold(0_u32, |acc, b| acc | (1 << (b - b'a'))))
                    .fold((0, !0), |(a, b), i| (a | i, b & i))
            })
            .fold((0, 0), |(aa, ab), (a, b)| {
                (aa + a.count_ones(), ab + b.count_ones())
            })
    }
    
steveklabnik/steveklabnik-day07.rs
steveklabnik/steveklabnik-day07.rs
use std::collections::{HashMap, HashSet};
    
    fn solve(input: &str) -> (u32, u32) {
        let mut graph: HashMap<_, Vec<_>> = Default::default();
        let mut graph2: HashMap<_, Vec<_>> = Default::default();
    
        for s in input.lines() {
            let (outer, s) = s.split_at(s.find(" bags").unwrap());
            let s = &s[14..];
    
            if s != "no other bags." {
                for s in s.split(',').map(str::trim_start) {
                    let (count, s) = s.split_at(s.find(' ').unwrap());
                    let count = count.parse().unwrap();
                    let (inner, _) = s.split_at(s.rfind(' ').unwrap());
                    let inner = inner.trim();
    
                    graph.entry(outer).or_default().push((inner, count));
                    graph2.entry(inner).or_default().push((outer, 1));
                }
            }
        }
    
        (
            dfs(&graph2, &mut Some(HashSet::new()), "shiny gold"),
            dfs(&graph, &mut None, "shiny gold")
        )
    }
    
    fn dfs<'a>(
        graph: &HashMap<&str, Vec<(&'a str, u32)>>,
        visited: &mut Option<HashSet<&'a str>>,
        from: &str
    ) -> u32 {
        graph.get(&from).map_or(0, |tos| {
            let mut count = 0;
    
            for &(to, c) in tos {
                if visited.as_mut().map_or(true, |v| v.insert(to)) {
                    count += c + c * dfs(graph, visited, to);
                }
            }
    
            count
        })
    }
    
steveklabnik/steveklabnik-day08.rs
steveklabnik/steveklabnik-day08.rs
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    enum Op {
        Nop,
        Jmp,
        Acc
    }
    
    fn solve(input: &str) -> (i32, i32) {
        let ops: Vec<_> = input
            .lines()
            .map(|s| {
                let arg = s[4..].parse().unwrap();
    
                match &s[..3] {
                    "nop" => (Op::Nop, arg),
                    "jmp" => (Op::Jmp, arg),
                    "acc" => (Op::Acc, arg),
                    _ => unreachable!()
                }
            })
            .collect();
    
        let b = (0..ops.len())
            .filter(|&i| ops[i].0 != Op::Acc)
            .map(|i| {
                let mut ops = ops.clone();
                let op = &mut ops[i].0;
                *op = if *op == Op::Nop { Op::Jmp } else { Op::Nop };
                ops
            })
            .filter_map(|ops| run(&ops).ok())
            .next()
            .unwrap();
    
        (run(&ops).unwrap_err(), b)
    }
    
    fn run(ops: &[(Op, i32)]) -> Result<i32, i32> {
        let mut set = vec![false; ops.len()];
        let mut pc: u32 = 0;
        let mut acc = 0;
    
        while !std::mem::replace(&mut set[pc as usize], true) {
            match ops[pc as usize] {
                (Op::Nop, _) => pc += 1,
                (Op::Jmp, arg) => pc = ((pc as i32) + arg) as u32,
                (Op::Acc, arg) => {
                    acc += arg;
                    pc += 1;
                }
            }
    
            if pc as usize == ops.len() {
                return Ok(acc);
            }
        }
    
        Err(acc)
    }
    
steveklabnik/steveklabnik-day09.rs
steveklabnik/steveklabnik-day09.rs
fn solve(input: &str) -> (u64, u64) {
        let numbers: Vec<_> = input.lines().map(|s| s.parse().unwrap()).collect();
    
        let a = numbers
            .windows(26)
            .map(|w| (&w[..25], w[25]))
            .find(|&(preamble, target)| {
                let mut iter = preamble.iter().copied();
    
                while let Some(a) = iter.next() {
                    if iter.clone().any(|b| a + b == target) {
                        return false;
                    }
                }
    
                true
            })
            .map(|(_, n)| n)
            .unwrap();
    
        let mut stack = VecDeque::new();
        let mut sum = 0;
    
        numbers
            .iter()
            .find(|&&n| {
                stack.push_back(n);
                sum += n;
    
                while sum > a {
                    sum -= stack.pop_front().unwrap();
                }
    
                sum == a
            })
            .unwrap();
    
        let b = stack
            .iter()
            .fold((!0, 0), |(a, b), &n| (a.min(n), b.max(n)));
    
        (a, b.0 + b.1)
    }
    
steveklabnik/steveklabnik-day10.rs
steveklabnik/steveklabnik-day10.rs
fn solve(input: &str) -> (u32, u64) {
        let mut adapters: Vec<usize> = input.lines().map(|s| s.parse().unwrap()).collect();
        adapters.sort_unstable();
        let max = adapters.last().unwrap() + 3;
        adapters.push(max);
    
        let mut last = 0;
        let mut count = vec![0; max + 1];
        count[0] = 1;
    
        let a = adapters
            .iter()
            .inspect(|&&n| {
                count[n] = (1..=3)
                    .filter_map(|d| n.checked_sub(d).map(|n| count[n]))
                    .sum()
            })
            .map(|&n| n - std::mem::replace(&mut last, n))
            .fold((0, 0), |(a, b), d| {
                (a + u32::from(d == 1), b + u32::from(d == 3))
            });
    
        (a.0 * a.1, count[max])
    }
    

Tags: