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 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> {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
mod day14;
|
||||||
mod day13;
|
mod day13;
|
||||||
mod day12;
|
mod day12;
|
||||||
mod day10;
|
mod day10;
|
||||||
|
Loading…
Reference in New Issue
Block a user