diff --git a/2020/src/bin/day14.rs b/2020/src/bin/day14.rs index 9ee0d8c..5a2d8ff 100644 --- a/2020/src/bin/day14.rs +++ b/2020/src/bin/day14.rs @@ -1,6 +1,7 @@ -#![feature(test, str_split_once, destructuring_assignment)] +#![feature(test, str_split_once, destructuring_assignment, bool_to_option)] extern crate test; -use std::collections::HashMap; +use itertools::Itertools; +use std::collections::{HashMap, HashSet}; use aoc2020::common::*; @@ -9,6 +10,27 @@ enum Command<'a> { MemSet { addr: usize, val: usize }, } +#[derive(Debug, Clone, Copy, PartialEq)] +enum BitState { + One, + Zero, + Floating, +} + +/* +impl PartialEq for BitState { + fn eq(&self, other: &BitState) -> bool { + match (self, other) { + (BitState::One, BitState::One) => true, + (BitState::Zero, BitState::Zero) => true, + (BitState::Floating, _) => true, + (_, BitState::Floating) => true, + _ => false, + } + } +} +*/ + type Parsed<'a> = Vec>; fn read_input() -> String { @@ -36,7 +58,18 @@ fn calc_bitmask bool>(b: &str, f: F) -> usize { b.bytes().rev().enumerate().filter(f).fold(0, |acc, (n, _)| acc | 1 << n) } -fn calc_bitmasks(b: &str) -> (usize, usize) { +fn calc_bitmask_p2(b: &str) -> Vec { + b.bytes() + .map(|b| match b { + b'0' => BitState::Zero, + b'1' => BitState::One, + b'X' => BitState::Floating, + _ => unreachable!(), + }) + .collect() +} + +fn calc_bitmasks_p1(b: &str) -> (usize, usize) { (calc_bitmask(b, |(_, b)| *b == b'1'), calc_bitmask(b, |(_, b)| *b != b'0')) } @@ -45,7 +78,7 @@ fn part1<'a>(parsed: &Parsed<'a>) -> usize { let mut mem = HashMap::new(); for command in parsed { match command { - Command::BitMask(bm) => (ones, zeros) = calc_bitmasks(bm), + Command::BitMask(bm) => (ones, zeros) = calc_bitmasks_p1(bm), Command::MemSet { addr, val } => { mem.insert(addr, (val & zeros) | ones); } @@ -54,14 +87,67 @@ fn part1<'a>(parsed: &Parsed<'a>) -> usize { mem.values().sum() } -fn part2<'a>(parsed: &Parsed<'a>) -> usize { - unimplemented!() +// TODO: clean this all up or just delete it straight away because whatever I was trying to do here +// doesn’t work for the real input, and I’m pretty sure it can’t, but I also don’t know what to do. +fn part2<'a>(parsed: &Parsed<'a>) -> u128 { + // let mut ones = 0; + let mut floating = vec![]; + // let mut mem = HashMap::new(); + let mut floating_mem = vec![]; + for command in parsed { + match command { + Command::BitMask(bm) => { + // ones = calc_bitmasks_p1(bm).0; + floating = calc_bitmask_p2(bm); + } + Command::MemSet { addr, val } => { + let addr = format!("{:036b}", addr) + .bytes() + .zip(floating.iter()) + .map(|(b, f)| match (b, f) { + (_, BitState::Floating) => BitState::Floating, + (b'1', _) | (_, BitState::One) => BitState::One, + (b'0', _) => BitState::Zero, + _ => unreachable!(), + }) + .collect_vec(); + // mem.insert(addr, val); + floating_mem.push((addr, val)); + // floating.entry((addr, xs)).or_insert_with(Vec::new).push(val); + } + } + } + let mut sum = 0u128; + for i in 0..floating_mem.len() { + // for (addr, val) in floating_mem.iter().rev() { + let val = *floating_mem[i].1; + let volatiles = floating_mem[i..] + .iter() + .map(|(addr, _)| { + addr.iter() + .enumerate() + .filter_map(|(n, &a)| (a == BitState::Floating).then_some(n)) + .collect::>() + }) + .collect_vec(); + let mut first = volatiles[0].clone(); + for r in volatiles.iter().skip(1) { + for e in r { + first.remove(e); + } + } + // if first.len() != 0 { + sum += val as u128 * (1 << first.len()) as u128; + // } + } + sum } fn main() { let raw = read_input(); let input = parse_input(&raw); println!("Part 1: {}", part1(&input)); + // 40413886813 is too low println!("Part 2: {}", part2(&input)); } @@ -77,9 +163,19 @@ mem[8] = 11 mem[7] = 101 mem[8] = 0"; + const INPUT_PART_2: &str = "mask = 000000000000000000000000000000X1001X +mem[42] = 100 +mask = 00000000000000000000000000000000X0XX +mem[26] = 1"; + + #[test] + fn test_part2() { + let parsed = parse_input(INPUT_PART_2); + assert_eq!(part2(&parsed), 208); + } + test!(part1() == 165); - //test!(part2() == 0); bench!(part1() == 18630548206046); //bench!(part2() == 0); - //bench_input!(len == 0); + bench_input!(len == 577); }