mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
165 lines
4.5 KiB
Rust
165 lines
4.5 KiB
Rust
use std::collections::HashSet;
|
|
use std::io::BufRead;
|
|
use std::io::BufReader;
|
|
use std::io::Read;
|
|
|
|
use regex::Regex;
|
|
|
|
use common::Solution;
|
|
use cpu::CPU;
|
|
use cpu::OpCode;
|
|
|
|
pub struct Day16 {
|
|
matcher: Regex,
|
|
buf: String,
|
|
}
|
|
|
|
impl Day16 {
|
|
pub fn new() -> Self {
|
|
Day16 {
|
|
matcher: Regex::new(r"\d+").unwrap(),
|
|
buf: String::new(),
|
|
}
|
|
}
|
|
|
|
fn read(&mut self, reader: &mut BufRead, target: &mut [i32]) -> bool {
|
|
self.buf.clear();
|
|
if reader.read_line(&mut self.buf).is_err() {
|
|
return false;
|
|
}
|
|
|
|
let mut found = false;
|
|
|
|
for (target, num) in target.iter_mut().zip(self.matcher.find_iter(&self.buf)) {
|
|
*target = num.as_str().parse().unwrap();
|
|
found = true
|
|
}
|
|
|
|
found
|
|
}
|
|
|
|
fn determine_options(&mut self, mut reader: &mut BufReader<&mut Read>) -> [HashSet<OpCode>; 16] {
|
|
let mut mappings: [HashSet<OpCode>; 16] = [
|
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
|
HashSet::new(), HashSet::new(), HashSet::new(), HashSet::new(),
|
|
];
|
|
let mut before = [0; 6];
|
|
let mut op = [0; 4];
|
|
let mut after = [0; 6];
|
|
while self.read(&mut reader, &mut before) {
|
|
self.read(&mut reader, &mut op);
|
|
self.read(&mut reader, &mut after);
|
|
reader.read_line(&mut self.buf).unwrap_or(0);
|
|
|
|
if mappings[op[0] as usize].is_empty() {
|
|
mappings[op[0] as usize].extend(OpCode::values()
|
|
.filter(|x| x.is_valid(&op, &before, &after)));
|
|
} else {
|
|
for option in OpCode::values()
|
|
.filter(|x| !x.is_valid(&op, &before, &after)) {
|
|
mappings[op[0] as usize].remove(&option);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
mappings
|
|
}
|
|
|
|
fn determine_mapping(&self, mut options: [HashSet<OpCode>; 16]) -> [OpCode; 16] {
|
|
let mut mapping: [Option<OpCode>; 16] = [None; 16];
|
|
let mut determined = 0;
|
|
|
|
while determined < mapping.len() {
|
|
for op in mapping.iter() {
|
|
if let Some(op) = op {
|
|
for option in options.iter_mut() {
|
|
option.remove(op);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (idx, option) in options.iter_mut().enumerate() {
|
|
if option.len() == 1 {
|
|
mapping[idx] = option.drain().next();
|
|
option.clear();
|
|
determined += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut actual_mapping = [OpCode::ADDI; 16];
|
|
for (i, op) in mapping.iter().enumerate() {
|
|
actual_mapping[i] = op.unwrap();
|
|
}
|
|
|
|
actual_mapping
|
|
}
|
|
}
|
|
|
|
impl Default for Day16 {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl Solution for Day16 {
|
|
fn part1(&mut self, input: &mut Read) -> String {
|
|
let mut reader = BufReader::new(input);
|
|
|
|
let mut before = [0; 6];
|
|
let mut op = [0; 4];
|
|
let mut after = [0; 6];
|
|
let mut counter = 0;
|
|
|
|
while self.read(&mut reader, &mut before) {
|
|
self.read(&mut reader, &mut op);
|
|
self.read(&mut reader, &mut after);
|
|
reader.read_line(&mut self.buf).unwrap_or(0);
|
|
|
|
let valid = OpCode::values()
|
|
.filter(|x| x.is_valid(&op, &before, &after))
|
|
.count();
|
|
|
|
if valid >= 3 {
|
|
counter += 1;
|
|
}
|
|
}
|
|
counter.to_string()
|
|
}
|
|
|
|
fn part2(&mut self, input: &mut Read) -> String {
|
|
let mut reader = BufReader::new(input);
|
|
|
|
let mappings = self.determine_options(&mut reader);
|
|
let mapping = self.determine_mapping(mappings);
|
|
|
|
let mut op = [0; 4];
|
|
// Skip a line
|
|
reader.read_line(&mut self.buf).unwrap();
|
|
|
|
let mut cpu = CPU::new();
|
|
|
|
while self.read(&mut reader, &mut op) {
|
|
cpu.execute(mapping[op[0] as usize], &op[1..4]).unwrap();
|
|
}
|
|
|
|
cpu.registers[0].to_string()
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use common::Solution;
|
|
use day16::Day16;
|
|
|
|
#[test]
|
|
fn sample_part1() {
|
|
let input: &[u8] = include_bytes!("samples/16.txt");
|
|
let mut instance = Day16::new();
|
|
assert_eq!("1", instance.part1(&mut input.as_ref()));
|
|
}
|
|
}
|