If...if...We didn't love freedom enough. And even more – we had no awareness of the real situation.... We purely and simply deserved everything that happened afterward.
Apparently, the great eater-of-iron himself has graced us with his presence. Welcome, 'Steve', and thanks for your submissions!
steveklabnik/steveklabnik-day01.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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.rssteveklabnik/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]) }