1
0
www.mikescher.com/www/statics/aoc/2020/08_solution.rs

167 lines
4.0 KiB
Rust

use crate::common::AdventOfCodeDay;
use itertools::Itertools;
use std::collections::HashSet;
use std::fmt::Display;
#[derive(Debug, Clone)]
struct HGCProgramm {
code: Vec<HGCCommand>,
}
impl HGCProgramm {
fn parse_program(codestr: String) -> HGCProgramm {
HGCProgramm {
code: codestr.lines().map(HGCCommand::parse).collect(),
}
}
}
#[derive(Debug, Clone)]
struct HGCCommand {
cmdtype: HGCCommandType,
argument: i32,
}
impl HGCCommand {
fn parse(line: &str) -> HGCCommand {
let (str_cmd, str_arg) = line.split(' ').collect_tuple::<(_, _)>().unwrap();
HGCCommand {
cmdtype: HGCCommandType::parse(str_cmd),
argument: str_arg.parse::<i32>().unwrap(),
}
}
}
#[derive(Debug, PartialEq, Clone)]
enum HGCCommandType {
NOP,
ACC,
JMP,
}
impl HGCCommandType {
fn parse(val: &str) -> HGCCommandType {
match val {
"acc" => HGCCommandType::ACC,
"jmp" => HGCCommandType::JMP,
"nop" => HGCCommandType::NOP,
_ => panic!("not a cmd")
}
}
}
impl Display for HGCCommandType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Debug)]
struct HGCMachineState {
trace: bool,
acc: i32,
ip: usize,
}
impl HGCMachineState {
fn new() -> HGCMachineState {
HGCMachineState {
trace: is_verbose!(),
acc: 0,
ip: 0,
}
}
fn exec_step(&mut self, prog: &HGCProgramm) {
self.exec_single(&prog.code[self.ip])
}
fn exec_single(&mut self, cmd: &HGCCommand) {
if self.trace {
verboseln!("ip: {: <4} || cmd:[{}({: <5})] (acc: {})", self.ip, cmd.cmdtype, cmd.argument, self.acc)
}
if cmd.cmdtype == HGCCommandType::NOP {
self.ip += 1;
} else if cmd.cmdtype == HGCCommandType::JMP {
self.ip = (self.ip as i32 + cmd.argument) as usize;
} else if cmd.cmdtype == HGCCommandType::ACC {
self.acc += cmd.argument;
self.ip += 1;
}
}
}
pub struct Day08 {
input: HGCProgramm,
}
impl Day08 {
pub fn new() -> Self {
let input_bytes = include_bytes!("../res/08_input.txt");
let input_str = String::from_utf8_lossy(input_bytes);
Self {
input: HGCProgramm::parse_program(input_str.to_owned().to_string())
}
}
fn find_loop(prog: &HGCProgramm) -> (i32, bool) {
let mut vm = HGCMachineState::new();
let mut visited: HashSet<usize> = HashSet::new();
visited.insert(vm.ip);
loop {
vm.exec_step(prog);
if visited.contains(&vm.ip) {
return (vm.acc, false);
}
visited.insert(vm.ip);
if vm.ip == prog.code.len() {
return (vm.acc, true);
}
}
}
}
impl AdventOfCodeDay for Day08 {
fn task_1(&self) -> String {
return Day08::find_loop(&self.input).0.to_string();
}
fn task_2(&self) -> String {
for i in 0..self.input.code.len() {
if self.input.code[i].cmdtype == HGCCommandType::ACC {
continue;
}
let mut progclone = self.input.clone();
if self.input.code[i].cmdtype == HGCCommandType::JMP {
progclone.code[i] = HGCCommand {
cmdtype: HGCCommandType::NOP,
argument: self.input.code[i].argument,
}
} else if self.input.code[i].cmdtype == HGCCommandType::NOP {
progclone.code[i] = HGCCommand {
cmdtype: HGCCommandType::JMP,
argument: self.input.code[i].argument,
}
} else {
panic!();
}
if let (acc, true) = Day08::find_loop(&progclone) {
return acc.to_string();
}
}
panic!();
}
}