mirror of
https://github.com/mx42/aoc2024.rs.git
synced 2026-01-14 13:59:52 +01:00
feat: day 17 + fmt
This commit is contained in:
5
data/examples/17.txt
Normal file
5
data/examples/17.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Register A: 729
|
||||||
|
Register B: 0
|
||||||
|
Register C: 0
|
||||||
|
|
||||||
|
Program: 0,1,5,4,3,0
|
||||||
@@ -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
192
src/bin/17.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user