1
Fork 0
advent-of-code/source/year_2020/day_14/mod.rs

118 lines
3.2 KiB
Rust

//! Day 14 of 2020.
use crate::prelude::*;
mod operation;
use operation::*;
/// Get the solution for day 14 of 2020.
pub fn solution() -> Solution {
Solution::new(Day::new(14, 2020), part_1, part_2)
.with_expected(9967721333886_i64, 4355897790573_i64)
}
/// The logic to solve part one.
fn part_1(input: &str) -> Result<String> {
let operations = input.lines().map(Into::into).collect::<Vec<Operation>>();
let mut current_mask = "".to_string();
let mut memory = HashMap::new();
for operation in operations {
match operation {
Operation::SetMask(mask) => current_mask = mask.clone(),
Operation::SetMemory(address, mut value) => {
for (index, character) in current_mask.chars().rev().enumerate() {
match character {
'0' => value &= !(1 << index),
'1' => value |= 1 << index,
_ => (),
}
}
*memory.entry(address).or_insert(value) = value;
}
}
}
Ok(memory.values().sum::<i64>().to_string())
}
/// The logic to solve part two.
fn part_2(input: &str) -> Result<String> {
let operations = input.lines().map(Into::into).collect::<Vec<Operation>>();
let mut current_mask = "".to_string();
let mut memory = HashMap::new();
for operation in operations {
match operation {
Operation::SetMask(mask) => current_mask = mask.clone(),
Operation::SetMemory(mut address, value) => {
for (index, character) in current_mask.chars().rev().enumerate() {
if character == '1' {
address |= 1 << index;
}
}
let mut new_mask = String::new();
for (index, character) in format!("{:036b}", address).char_indices() {
if current_mask.chars().nth(index) == Some('X') {
new_mask += "X";
} else {
new_mask += &character.to_string();
}
}
let mut floating_addresses = HashSet::new();
floating_addresses.insert(new_mask);
while floating_addresses
.iter()
.any(|address| address.contains('X'))
{
for address in floating_addresses.clone() {
for new_address in combine(address.clone()) {
floating_addresses.insert(new_address);
}
floating_addresses.remove(&address);
}
}
let floating_addresses = floating_addresses
.iter()
.map(|address| i64::from_str_radix(address, 2).unwrap())
.collect::<Vec<i64>>();
for mut address in floating_addresses {
for (index, character) in current_mask.chars().rev().enumerate() {
if character == '1' {
address |= 1 << index;
}
}
*memory.entry(address).or_insert(value) = value;
}
}
}
}
Ok(memory.values().sum::<i64>().to_string())
}
/// Loop over the input mask and replace any floating bits.
fn combine(input: String) -> Vec<String> {
let mut result = vec![];
for (index, character) in input.char_indices() {
if character == 'X' {
let zero = format!("{}{}{}", &input[0..index], '0', &input[index + 1..]);
result.push(zero);
let one = format!("{}{}{}", &input[0..index], '1', &input[index + 1..]);
result.push(one);
}
}
result
}