Skip to content

Commit

Permalink
Year 2016: Day 23
Browse files Browse the repository at this point in the history
  • Loading branch information
joshleaves committed Mar 22, 2024
1 parent 69bf158 commit e77e9ba
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 14 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ Of note:
- The changelog 2015.5.2 has been rewritten from each commit content.
- This file may be amended entirely in the future to adhere to the [GNU Changelog style](https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs)

## [2016.23.1]
### Added
- Solved [exercice for 2016, day 23](src/year_2016/23.rs).


## [2016.22.1]
### Added
- Solved [exercice for 2016, day 22](src/year_2016/22.rs).
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "advent-rs"
version = "2016.22.1"
version = "2016.23.1"
edition = "2021"
authors = ["Arnaud 'red' Rouyer"]
readme = "README.md"
Expand Down
4 changes: 4 additions & 0 deletions NOTES_2016.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ I love interpreters.
## Day 22: Grid Computing

So far, my [BreadthFirstSearch library](src/bfs.rs) has saved me from rewriting a BFS from scratch twice.

## Day 23: Safe Cracking

I had forgotten [the original was taking ten minutes to run](https://github.com/joshleaves/advent-rb/NOTES_2016.md#day-23-safe-cracking). This one takes only seven seconds, and I'll be happy with it.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ As I said, [Consistency is hard](https://github.com/joshleaves/advent-rb), and I

I'm also adding notes that may be useful if you're (like me) discovering Rust:
- [2015, complete!](NOTES_2015.md)
- [2016, up to day 22](NOTES_2016.md)
- [2016, up to day 23](NOTES_2016.md)

# Regarding style rules
I'm gonna use a mix of what `cargo fmt` does, with some stuff that feels more natural to me.
Expand Down
16 changes: 15 additions & 1 deletion benches/year_2016.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use advent_rs::year_2016::day_19;
use advent_rs::year_2016::day_20;
use advent_rs::year_2016::day_21;
use advent_rs::year_2016::day_22;
use advent_rs::year_2016::day_23;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn year_2016_day_01(c: &mut Criterion) {
Expand Down Expand Up @@ -286,6 +287,18 @@ fn year_2016_day_22(c: &mut Criterion) {
g2016_day_22.finish();
}

fn year_2016_day_23(c: &mut Criterion) {
let mut g2016_day_23 = c.benchmark_group("year_2016::day_23");
let input_year_2016_day_23 = include_str!("../inputs/year_2016/day_23_input");
g2016_day_23.bench_function("year_2016::day_23_v1", |b| {
b.iter(|| day_23::day_23_v1(black_box(input_year_2016_day_23)))
});
g2016_day_23.bench_function("year_2016::day_23_v2", |b| {
b.iter(|| day_23::day_23_v2(black_box(input_year_2016_day_23)))
});
g2016_day_23.finish();
}

criterion_group!(
benches,
year_2016_day_01,
Expand All @@ -309,6 +322,7 @@ criterion_group!(
year_2016_day_19,
year_2016_day_20,
year_2016_day_21,
year_2016_day_22
year_2016_day_22,
year_2016_day_23
);
criterion_main!(benches);
26 changes: 26 additions & 0 deletions inputs/year_2016/day_23_input
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
cpy a b
dec b
cpy a d
cpy 0 a
cpy b c
inc a
dec c
jnz c -2
dec d
jnz d -5
dec b
cpy b c
cpy c d
dec d
inc c
jnz d -2
tgl c
cpy -16 c
jnz 1 c
cpy 96 c
jnz 91 d
inc a
inc d
jnz d -2
inc c
jnz c -5
10 changes: 10 additions & 0 deletions src/year_2016.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod day_19;
pub mod day_20;
pub mod day_21;
pub mod day_22;
pub mod day_23;

pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
if part != 1 && part != 2 {
Expand Down Expand Up @@ -54,6 +55,7 @@ pub fn solve(day: u8, part: u8, input: impl Into<String>) -> Option<String> {
20 => Some(format!("{}", day_20::day_20(part, input))),
21 => Some(format!("{}", day_21::day_21(part, input))),
22 => Some(format!("{}", day_22::day_22(part, input))),
23 => Some(format!("{}", day_23::day_23(part, input))),
_ => None,
}
}
Expand Down Expand Up @@ -224,4 +226,12 @@ mod tests {
assert_eq!(day_22::day_22_v1(input), 955);
assert_eq!(day_22::day_22_v2(input), 246);
}

#[test]
#[ignore = "Too slow for CI"]
fn day_23() {
let input = include_str!("../inputs/year_2016/day_23_input");
assert_eq!(day_23::day_23_v1(input), 13_776);
assert_eq!(day_23::day_23_v2(input), 479_010_336);
}
}
47 changes: 39 additions & 8 deletions src/year_2016/assembunny.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type Value = u64;
type Value = i64;
type Register = u8;

#[derive(Debug, Copy, Clone)]
Expand All @@ -25,24 +25,27 @@ enum Instruction {
// dec x decreases the value of register x by one.
Decrement(Register),
// jnz x y jumps to an instruction y away (positive means forward; negative means backward), but only if x is not zero.
JumpNotZero(ValueOrRegister, i8),
JumpNotZero(ValueOrRegister, ValueOrRegister),
// tgl x toggles the instruction x away (pointing at instructions like jnz does: positive means forward; negative means backward):
Toggle(Register),
Nop(),
}

pub struct Assembunny {
pc: usize,
pub registers: [u64; 4],
pub registers: [Value; 4],
instructions: Vec<Instruction>,
}

impl Assembunny {
const fn value_of(&self, item: ValueOrRegister) -> u64 {
const fn value_of(&self, item: ValueOrRegister) -> Value {
match item {
ValueOrRegister::Value(value) => value,
ValueOrRegister::Register(register_id) => self.registers[register_id as usize],
}
}

pub fn set_register(&mut self, register: &str, value: u64) {
pub fn set_register(&mut self, register: &str, value: Value) {
let reg_id = Self::register(register);
self.registers[reg_id as usize] = value;
}
Expand All @@ -64,12 +67,35 @@ impl Assembunny {
}
Instruction::JumpNotZero(vor, offset) => {
let value = self.value_of(*vor);
let offset = self.value_of(*offset);
if value != 0 {
self.pc = ((self.pc as i8) + offset) as usize;
self.pc = ((self.pc as i64) + offset) as usize;
} else {
self.pc += 1;
}
}
Instruction::Toggle(register) => {
let target = (self.pc as Value + self.registers[*register as usize]) as usize;
if target >= self.instructions.len() {
self.pc += 1;
continue;
}
self.instructions[target] = match self.instructions[target] {
Instruction::Copy(vor, register) => {
Instruction::JumpNotZero(vor, ValueOrRegister::Register(register))
}
Instruction::Increment(register) => Instruction::Decrement(register),
Instruction::Decrement(register) => Instruction::Increment(register),
Instruction::JumpNotZero(vor, offset) => match offset {
ValueOrRegister::Register(register) => Instruction::Copy(vor, register),
_ => Instruction::Nop(),
},
Instruction::Toggle(offset) => Instruction::Increment(offset as u8),
Instruction::Nop() => Instruction::Nop(),
};
self.pc += 1;
}
Instruction::Nop() => {}
}
}
}
Expand Down Expand Up @@ -108,15 +134,20 @@ impl Assembunny {
// jnz x y jumps to an instruction y away (positive means forward; negative means backward), but only if x is not zero.
"jnz" => {
let vor = ValueOrRegister::parse(parts[1]);
let offset = parts[2].parse::<i8>().unwrap();
let offset = ValueOrRegister::parse(parts[2]);
instructions.push(Instruction::JumpNotZero(vor, offset));
}
// tgl x toggles the instruction x away (pointing at instructions like jnz does: positive means forward; negative means backward):
"tgl" => {
let register = Self::register(parts[1]);
instructions.push(Instruction::Toggle(register));
}
_ => panic!("Invalid instruction: {}", line),
}
}
Assembunny {
pc: 0,
registers: [0u64; 4],
registers: [0; 4],
instructions: instructions,
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/year_2016/day_12.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use super::assembunny::Assembunny;

pub fn day_12_v1(input: impl Into<String>) -> u64 {
pub fn day_12_v1(input: impl Into<String>) -> i64 {
let mut bunny: Assembunny = Assembunny::from_input(&input.into());
bunny.run();

bunny.registers[0]
}
pub fn day_12_v2(input: impl Into<String>) -> u64 {
pub fn day_12_v2(input: impl Into<String>) -> i64 {
let mut bunny: Assembunny = Assembunny::from_input(&input.into());
bunny.set_register("c", 1);
bunny.run();

bunny.registers[0]
}

solvable!(day_12, day_12_v1, day_12_v2, u64);
solvable!(day_12, day_12_v1, day_12_v2, i64);

#[cfg(test)]
mod tests {
Expand Down
46 changes: 46 additions & 0 deletions src/year_2016/day_23.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use super::assembunny::Assembunny;

// pub fn day_12_v1(input: impl Into<String>) -> i64 {
// }
// pub fn day_12_v2(input: impl Into<String>) -> i64 {
// let mut bunny: Assembunny = Assembunny::from_input(&input.into());
// bunny.set_register("c", 1);
// bunny.run();

// bunny.registers[0]
// }

pub fn day_23_v1(input: impl Into<String>) -> i64 {
let mut bunny: Assembunny = Assembunny::from_input(&input.into());
bunny.set_register("a", 7);
bunny.run();

bunny.registers[0]
}

pub fn day_23_v2(input: impl Into<String>) -> i64 {
let mut bunny: Assembunny = Assembunny::from_input(&input.into());
bunny.set_register("a", 12);
bunny.run();

bunny.registers[0]
}

solvable!(day_23, day_23_v1, day_23_v2, i64);

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn works_with_samples_v1() {
let sample_one = "cpy 2 a\n\
tgl a\n\
tgl a\n\
tgl a\n\
cpy 1 a\n\
dec a\n\
dec a";
assert_eq!(day_23_v1(sample_one), 3);
}
}

0 comments on commit e77e9ba

Please sign in to comment.