feat: day 17 + fmt

This commit is contained in:
installer
2024-12-18 20:41:30 +01:00
parent fe253537ef
commit 83166f9e6b
3 changed files with 254 additions and 24 deletions

5
data/examples/17.txt Normal file
View File

@@ -0,0 +1,5 @@
Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0

View File

@@ -1,7 +1,7 @@
advent_of_code::solution!(16); advent_of_code::solution!(16);
use std::collections::HashMap;
use std::collections::vec_deque::VecDeque; use std::collections::vec_deque::VecDeque;
use std::collections::HashMap;
#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
struct Pos { struct Pos {
@@ -13,13 +13,37 @@ impl Pos {
fn neighbors(&self) -> Vec<Step> { fn neighbors(&self) -> Vec<Step> {
let mut res: Vec<Step> = Vec::new(); let mut res: Vec<Step> = Vec::new();
if self.x > 0 { 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 { 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 {
res.push(Step { pos: Pos { x: self.x, y: self.y + 1 }, dir: Dir::Down }); 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 res
} }
} }
@@ -48,13 +72,16 @@ struct Step {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Path { struct Path {
steps: VecDeque<Step> steps: VecDeque<Step>,
} }
impl Path { impl Path {
fn init(pos: Pos) -> Self { fn init(pos: Pos) -> Self {
Self { Self {
steps: VecDeque::from(vec![Step {pos, dir: Dir::Right}]), steps: VecDeque::from(vec![Step {
pos,
dir: Dir::Right,
}]),
} }
} }
@@ -90,19 +117,22 @@ impl TryFrom<&str> for State {
type Error = (); type Error = ();
fn try_from(input: &str) -> Result<State, Self::Error> { fn try_from(input: &str) -> Result<State, Self::Error> {
let input = input.lines().collect::<Vec<_>>(); let input = input.lines().collect::<Vec<_>>();
let size = Pos { x: input[0].len(), y: input.len() }; let size = Pos {
let input: Vec<(Pos, char)> = input.iter() x: input[0].len(),
y: input.len(),
};
let input: Vec<(Pos, char)> = input
.iter()
.enumerate() .enumerate()
.flat_map(|(y, l)| .flat_map(|(y, l)| {
l l.chars().enumerate().filter_map(move |(x, c)| {
.chars()
.enumerate()
.filter_map(move |(x, c)|
if c == '#' { if c == '#' {
None None
} else { } else {
Some((Pos { x, y }, c)) Some((Pos { x, y }, c))
})) }
})
})
.collect(); .collect();
let start = input.iter().find(|(_, c)| *c == 'S').ok_or(())?.0.clone(); let start = input.iter().find(|(_, c)| *c == 'S').ok_or(())?.0.clone();
let end = input.iter().find(|(_, c)| *c == 'E').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); all_paths.push(path);
return; return;
} }
for next in cur.neighbors().iter() for next in cur
.filter(|p| self.map.contains_key(&p.pos) && !path.have_visited(&p.pos)) { .neighbors()
.iter()
.filter(|p| self.map.contains_key(&p.pos) && !path.have_visited(&p.pos))
{
let mut new_path = path.clone(); let mut new_path = path.clone();
new_path.push(next.clone()); new_path.push(next.clone());
self.compute_all_paths(new_path, all_paths); self.compute_all_paths(new_path, all_paths);

192
src/bin/17.rs Normal file
View File

@@ -0,0 +1,192 @@
advent_of_code::solution!(17);
use std::iter::successors;
#[derive(Debug, Clone)]
struct State {
registers: [i32; 3],
memory: Vec<i32>,
ptr: usize,
output: Vec<i32>,
}
impl State {
fn dv(&self, reg: usize, combo: i32) -> Option<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<String> = self.output.iter().map(|n| n.to_string()).collect();
vec.join(",")
}
}
impl TryFrom<&str> for State {
type Error = ();
fn try_from(input: &str) -> Result<Self, Self::Error> {
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::<i32>().unwrap())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>(),
)
}
})
.flatten()
.collect::<Vec<_>>();
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<String> {
State::try_from(input).ok().map(|s| s.run().get_output())
}
pub fn part_two(input: &str) -> Option<u32> {
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);
}
}