day14
This commit is contained in:
parent
9fc94b0e06
commit
a0c9ce9882
149
src/day14.rs
Normal file
149
src/day14.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use itertools::Itertools;
|
||||
|
||||
const PREAMBLE_LEN: usize = 25;
|
||||
const PREAMBLE_LEN: usize = 5;
|
||||
|
||||
#[aoc_generator(day9)]
|
||||
fn parse(input: &str) -> Vec<u64> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod day14;
|
||||
mod day13;
|
||||
mod day12;
|
||||
mod day10;
|
||||
|
Loading…
Reference in New Issue
Block a user