From 83166f9e6bbb5748fdc3fd34dd053cc27b9f876a Mon Sep 17 00:00:00 2001 From: installer Date: Wed, 18 Dec 2024 20:41:30 +0100 Subject: [PATCH] feat: day 17 + fmt --- data/examples/17.txt | 5 ++ src/bin/16.rs | 81 ++++++++++++------ src/bin/17.rs | 192 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+), 24 deletions(-) create mode 100644 data/examples/17.txt create mode 100644 src/bin/17.rs diff --git a/data/examples/17.txt b/data/examples/17.txt new file mode 100644 index 0000000..f09839b --- /dev/null +++ b/data/examples/17.txt @@ -0,0 +1,5 @@ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 diff --git a/src/bin/16.rs b/src/bin/16.rs index 99903bc..88c31c0 100644 --- a/src/bin/16.rs +++ b/src/bin/16.rs @@ -1,7 +1,7 @@ advent_of_code::solution!(16); -use std::collections::HashMap; use std::collections::vec_deque::VecDeque; +use std::collections::HashMap; #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct Pos { @@ -13,13 +13,37 @@ impl Pos { fn neighbors(&self) -> Vec { let mut res: Vec = Vec::new(); if self.x > 0 { - res.push(Step { pos: Pos { x: self.x - 1, y: self.y }, dir: Dir::Left }); + res.push(Step { + pos: Pos { + x: self.x - 1, + y: self.y, + }, + dir: Dir::Left, + }); } if self.y > 0 { - res.push(Step { pos: Pos { x: self.x, y: self.y - 1 }, dir: Dir::Up }); + res.push(Step { + pos: Pos { + x: self.x, + y: self.y - 1, + }, + dir: Dir::Up, + }); } - res.push(Step { pos: Pos { x: self.x + 1, y: self.y }, dir: Dir::Right }); - res.push(Step { pos: Pos { x: self.x, y: self.y + 1 }, dir: Dir::Down }); + res.push(Step { + pos: Pos { + x: self.x + 1, + y: self.y, + }, + dir: Dir::Right, + }); + res.push(Step { + pos: Pos { + x: self.x, + y: self.y + 1, + }, + dir: Dir::Down, + }); res } } @@ -48,16 +72,19 @@ struct Step { #[derive(Debug, Clone)] struct Path { - steps: VecDeque + steps: VecDeque, } impl Path { fn init(pos: Pos) -> Self { Self { - steps: VecDeque::from(vec![Step {pos, dir: Dir::Right}]), + steps: VecDeque::from(vec![Step { + pos, + dir: Dir::Right, + }]), } } - + fn current(&self) -> Pos { self.steps.back().unwrap().pos.clone() } @@ -82,7 +109,7 @@ impl Path { } cur_dir = Some(step.dir); } - score + 1 // duh?! + score + 1 // duh?! } } @@ -90,19 +117,22 @@ impl TryFrom<&str> for State { type Error = (); fn try_from(input: &str) -> Result { let input = input.lines().collect::>(); - let size = Pos { x: input[0].len(), y: input.len() }; - let input: Vec<(Pos, char)> = input.iter() + let size = Pos { + x: input[0].len(), + y: input.len(), + }; + let input: Vec<(Pos, char)> = input + .iter() .enumerate() - .flat_map(|(y, l)| - l - .chars() - .enumerate() - .filter_map(move |(x, c)| - if c == '#' { - None - } else { - Some((Pos {x, y}, c)) - })) + .flat_map(|(y, l)| { + l.chars().enumerate().filter_map(move |(x, c)| { + if c == '#' { + None + } else { + Some((Pos { x, y }, c)) + } + }) + }) .collect(); let start = input.iter().find(|(_, c)| *c == 'S').ok_or(())?.0.clone(); let end = input.iter().find(|(_, c)| *c == 'E').ok_or(())?.0.clone(); @@ -128,8 +158,11 @@ impl State { all_paths.push(path); return; } - for next in cur.neighbors().iter() - .filter(|p| self.map.contains_key(&p.pos) && !path.have_visited(&p.pos)) { + for next in cur + .neighbors() + .iter() + .filter(|p| self.map.contains_key(&p.pos) && !path.have_visited(&p.pos)) + { let mut new_path = path.clone(); new_path.push(next.clone()); self.compute_all_paths(new_path, all_paths); @@ -168,7 +201,7 @@ pub fn part_one(input: &str) -> Option { // for p in st.get_paths() { // st.print_path(&p); // } - st.get_paths().iter().map(|p|p.score()).min() + st.get_paths().iter().map(|p| p.score()).min() } pub fn part_two(input: &str) -> Option { diff --git a/src/bin/17.rs b/src/bin/17.rs new file mode 100644 index 0000000..9cf6cb5 --- /dev/null +++ b/src/bin/17.rs @@ -0,0 +1,192 @@ +advent_of_code::solution!(17); + +use std::iter::successors; + +#[derive(Debug, Clone)] +struct State { + registers: [i32; 3], + memory: Vec, + ptr: usize, + output: Vec, +} + +impl State { + fn dv(&self, reg: usize, combo: i32) -> Option { + println!( + "DIV reg 0 {} / 2^{} => reg {}", + self.registers[0], combo, reg + ); + let two: i32 = 2; + let res = self.registers[0].checked_div(two.pow(combo as u32))?; + let mut new_registers = self.registers.clone(); + new_registers[reg] = res; + Some(Self { + registers: new_registers, + ptr: self.ptr + 2, + ..self.clone() + }) + } + + fn bxl(&self, combo: i32) -> Option { + println!("BXL reg 1 ^ {} => reg 1", combo); + let res = self.registers[1] ^ combo; + let mut new_registers = self.registers.clone(); + new_registers[1] = res; + Some(Self { + registers: new_registers, + ptr: self.ptr + 2, + ..self.clone() + }) + } + + fn bst(&self, combo: i32) -> Option { + println!("BST {} % 8 => reg 1", combo); + let mut new_registers = self.registers.clone(); + new_registers[1] = combo % 8; + Some(Self { + registers: new_registers, + ptr: self.ptr + 2, + ..self.clone() + }) + } + + fn jnz(&self, combo: i32) -> Option { + if self.registers[0] == 0 { + println!("JNZ reg 0 == 0 => NO-OP"); + Some(Self { + ptr: self.ptr + 2, + ..self.clone() + }) + } else { + println!("JNZ reg 0 != 0 => JMP {}", combo); + Some(Self { + ptr: combo as usize, + ..self.clone() + }) + } + } + + fn bxc(&self) -> Option { + println!("BXC reg 1 ^ reg 2 => reg 1"); + let mut new_registers = self.registers.clone(); + new_registers[1] = self.registers[1] ^ self.registers[2]; + Some(Self { + registers: new_registers, + ptr: self.ptr + 2, + ..self.clone() + }) + } + + fn out(&self, combo: i32) -> Option { + println!("OUT {} % 8 => out", combo); + let mut new_out = self.output.clone(); + new_out.push(combo % 8); + Some(Self { + output: new_out, + ptr: self.ptr + 2, + ..self.clone() + }) + } + + fn run(&self) -> Self { + successors(Some(self.clone()), |st| st.step()) + .last() + .unwrap() + } + + fn step(&self) -> Option { + println!("Current state\n{:?}", self); + if self.ptr >= self.memory.len() { + return None; + } + let opcode = self.memory.get(self.ptr).unwrap(); + let combo = *self.memory.get(self.ptr + 1).unwrap(); + if combo < 0 || combo > 6 { + return None; + } + let combo_value = match combo { + 0..=3 => combo, + 4 => self.registers[0], + 5 => self.registers[1], + 6 => self.registers[2], + _ => panic!(), + }; + match opcode { + 0 => self.dv(0, combo_value), + 1 => self.bxl(combo_value), + 2 => self.bst(combo_value), + 3 => self.jnz(combo_value), + 4 => self.bxc(), + 5 => self.out(combo_value), + 6 => self.dv(1, combo_value), + 7 => self.dv(2, combo_value), + _ => None, + } + } + fn get_output(&self) -> String { + let vec: Vec = self.output.iter().map(|n| n.to_string()).collect(); + vec.join(",") + } +} + +impl TryFrom<&str> for State { + type Error = (); + fn try_from(input: &str) -> Result { + let mut input = input + .lines() + .filter_map(|l| { + if l.is_empty() { + None + } else { + Some( + l.split(": ") + .skip(1) + .flat_map(|s| { + s.split(",") + .map(|n| n.parse::().unwrap()) + .collect::>() + }) + .collect::>(), + ) + } + }) + .flatten() + .collect::>(); + if input.len() < 4 { + Err(()) + } else { + let registers: [i32; 3] = [input.remove(0), input.remove(0), input.remove(0)]; + Ok(State { + registers, + memory: input, + ptr: 0, + output: Vec::new(), + }) + } + } +} + +pub fn part_one(input: &str) -> Option { + State::try_from(input).ok().map(|s| s.run().get_output()) +} + +pub fn part_two(input: &str) -> Option { + None +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_part_one() { + let result = part_one(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, Some("4,6,3,5,6,3,5,2,1,0".into())); + } + + #[test] + fn test_part_two() { + let result = part_two(&advent_of_code::template::read_file("examples", DAY)); + assert_eq!(result, None); + } +}