Moloch! Moloch! Robot apartments! Invisible suburbs! Skeleton treasuries! Blind capitals! Demonic industries! Spectral nations!
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, [&\#39; &\#39;, &\#39;-&\#39;, &\#39;:&\#39;], 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(&\#39;\n&\#39;).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&\#39;\#&\#39;)) .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&\#39;B&\#39; || b == b&\#39;R&\#39;)) }) .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][a as usize % 4] }
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&\#39;a&\#39;)))) .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(&\#39;,&\#39;).map(str::trim\_start) { let (count, s) = s.split\_at(s.find(&\#39; &\#39;).unwrap()); let count = count.parse().unwrap(); let (inner, \_) = s.split\_at(s.rfind(&\#39; &\#39;).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<&\#39;a>( graph: &HashMap<&str, Vec<(&&\#39;a str, u32)>>, visited: &mut Option<HashSet<&&\#39;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]) }