This commit is contained in:
Andrew Glaze 2023-12-29 10:32:23 -05:00
parent 9fc94b0e06
commit a0c9ce9882
3 changed files with 151 additions and 1 deletions

149
src/day14.rs Normal file
View File

@ -0,0 +1,149 @@
use std::{collections::HashMap, iter::zip};
use aoc_runner_derive::{aoc, aoc_generator};
use itertools::{Itertools, iproduct};
#[derive(Debug)]
enum ProgramStep {
Mask(String),
Mem(u64, u64)
}
impl From<&str> for ProgramStep {
fn from(value: &str) -> Self {
let (name, value) = value.split(" = ").collect_tuple().unwrap();
return match name {
"mask" => Self::Mask(value.to_string()),
name if name.starts_with("mem") => {
Self::Mem(name[4..name.len() - 1].parse::<u64>().unwrap(), value.parse::<u64>().unwrap())
}
_ => unreachable!()
};
}
}
#[aoc_generator(day14)]
fn parse(input: &str) -> Vec<ProgramStep> {
input.lines().map(ProgramStep::from).collect_vec()
}
fn apply_mask(mask: &str, val: u64) -> u64 {
let mut val = val;
for (i, char) in mask.chars().enumerate() {
match char {
'X' => continue,
'1' => val = val | (2_u64.pow((36 - i - 1).try_into().unwrap())),
'0' => val = val & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
_ => unreachable!()
};
}
val
}
#[aoc(day14, part1)]
fn part1(program: &Vec<ProgramStep>) -> u64 {
let mut mem: HashMap<u64, u64> = HashMap::new();
let mut mask = "";
for step in program {
match step {
ProgramStep::Mask(val) => mask = val,
ProgramStep::Mem(addr, val) => {
let val = apply_mask(mask, *val);
mem.insert(*addr, val);
},
}
}
mem.values().sum()
}
fn permute_masks(mask: &str) -> Vec<String> {
let mut masks: Vec<String> = vec![];
let bits = mask.chars().enumerate().filter(|(_, v)| *v == 'X').map(|(i, _)| i).collect_vec();
let perms = kproduct("21".to_string(), bits.len() as u32);
let mut new_mask = mask.to_string();
for perm in perms {
let bit_vals = zip(bits.clone(), perm.chars()).collect::<HashMap<usize, char>>();
for (k, val) in bit_vals {
new_mask = new_mask[0..k].to_string() + &val.to_string() + &new_mask[k+1..];
}
masks.push(new_mask.clone());
}
masks
}
fn kproduct(seq: String, k: u32) -> Vec<String> {
match k {
0 => vec![],
1 => seq.chars().map(|c| c.to_string()).collect(),
2 => iproduct!(seq.chars(), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
_ => iproduct!(kproduct(seq.clone(), k - 1), seq.chars()).map(|(a, b)| format!("{}{}", a, b)).collect(),
}
}
fn get_addrs(addr: u64, mask: &str) -> Vec<u64> {
let mut addrs = vec![];
let masks = permute_masks(mask);
for mask in masks {
let mut addr = addr;
for (i, char) in mask.chars().enumerate() {
match char {
'1' => addr = addr | (2_u64.pow((36 - i - 1).try_into().unwrap())),
'2' => addr = addr & !(2_u64.pow((36 - i - 1).try_into().unwrap())),
'0' => continue,
_ => unreachable!()
}
}
addrs.push(addr)
}
addrs
}
#[aoc(day14, part2)]
fn part2(program: &Vec<ProgramStep>) -> u64 {
let mut mem: HashMap<u64, u64> = HashMap::new();
let mut mask = "";
for step in program {
match step {
ProgramStep::Mask(val) => mask = val,
ProgramStep::Mem(addr, val) => {
let addrs = get_addrs(*addr, mask);
for addr in addrs {
mem.insert(addr, *val);
}
},
}
}
mem.values().sum()
}
#[cfg(test)]
mod tests {
use super::*;
const EX: &str = r"mask = XXXXXXXXXXXXXXXXXXXXXXXXXXXXX1XXXX0X
mem[8] = 11
mem[7] = 101
mem[8] = 0";
#[test]
fn part1_example() {
assert_eq!(part1(&parse(EX)), 165);
}
const EX_2: &str = r"mask = 000000000000000000000000000000X1001X
mem[42] = 100
mask = 00000000000000000000000000000000X0XX
mem[26] = 1";
#[test]
fn part2_example() {
assert_eq!(part2(&parse(EX_2)), 208);
}
}

View File

@ -1,7 +1,7 @@
use aoc_runner_derive::{aoc, aoc_generator}; use aoc_runner_derive::{aoc, aoc_generator};
use itertools::Itertools; use itertools::Itertools;
const PREAMBLE_LEN: usize = 25; const PREAMBLE_LEN: usize = 5;
#[aoc_generator(day9)] #[aoc_generator(day9)]
fn parse(input: &str) -> Vec<u64> { fn parse(input: &str) -> Vec<u64> {

View File

@ -1,3 +1,4 @@
mod day14;
mod day13; mod day13;
mod day12; mod day12;
mod day10; mod day10;