diff --git a/day23/Cargo.lock b/day23/Cargo.lock new file mode 100644 index 0000000..8dd0414 --- /dev/null +++ b/day23/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "day23" +version = "0.1.0" diff --git a/day23/Cargo.toml b/day23/Cargo.toml new file mode 100644 index 0000000..4f0aacb --- /dev/null +++ b/day23/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "day23" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/day23/example.txt b/day23/example.txt new file mode 100644 index 0000000..bcabc2c --- /dev/null +++ b/day23/example.txt @@ -0,0 +1,7 @@ +cpy 2 a +tgl a +tgl a +tgl a +cpy 1 a +dec a +dec a diff --git a/day23/input.txt b/day23/input.txt new file mode 100644 index 0000000..6981cc4 --- /dev/null +++ b/day23/input.txt @@ -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 75 c +jnz 72 d +inc a +inc d +jnz d -2 +inc c +jnz c -5 diff --git a/day23/src/main.rs b/day23/src/main.rs new file mode 100644 index 0000000..e1014e1 --- /dev/null +++ b/day23/src/main.rs @@ -0,0 +1,214 @@ +#[cfg(debug_assertions)] +const FILENAME: &str = "example.txt"; +#[cfg(not(debug_assertions))] +const FILENAME: &str = "input.txt"; + +fn main() { + let mut program: Vec<_> = std::fs::read_to_string(FILENAME) + .unwrap() + .lines() + .map(Instruction::parse) + .collect(); + + part1(&mut program); + + let mut program: Vec<_> = std::fs::read_to_string(FILENAME) + .unwrap() + .lines() + .map(Instruction::parse) + .collect(); + + part2(&mut program); +} + +fn part2(program: &mut [Instruction]) { + let mut registers = Registers::new(); + registers.set('a', &Value::Numeric(12)); + + run_program(program, &mut registers); + + println!("{}", registers.registers[0]); +} + +fn part1(program: &mut [Instruction]) { + let mut registers = Registers::new(); + registers.set('a', &Value::Numeric(7)); + + run_program(program, &mut registers); + + println!("{}", registers.registers[0]); +} + +struct Registers { + registers: [isize; 4], +} + +impl Registers { + fn set(&mut self, register: char, value: &Value) { + let address = Self::get_address(register); + match value { + Value::Register(from_register) => { + let from_address = Self::get_address(*from_register); + self.registers[address] = self.registers[from_address]; + } + Value::Numeric(value) => self.registers[address] = *value, + } + } + + fn inc(&mut self, register: char) { + let address = Self::get_address(register); + self.registers[address] += 1; + } + + fn dec(&mut self, register: char) { + let address = Self::get_address(register); + self.registers[address] -= 1; + } + + fn is_nonzero(&self, value: &Value) -> bool { + match value { + Value::Register(register) => { + let address = Self::get_address(*register); + self.registers[address] != 0 + } + Value::Numeric(value) => *value != 0, + } + } + + fn get_address(register: char) -> usize { + match register { + 'a' => 0, + 'b' => 1, + 'c' => 2, + 'd' => 3, + _ => panic!("unknown register: {register}"), + } + } + + fn new() -> Self { + Self { registers: [0; 4] } + } +} + +#[derive(Debug)] +enum Instruction { + Cpy(Value, Value), + Inc(Value), + Dec(Value), + Jnz(Value, Value), + Tgl(Value), +} + +#[derive(Clone, Copy, Debug)] +enum Value { + Register(char), + Numeric(isize), +} + +impl Value { + fn parse(s: &str) -> Self { + let first_char = s.chars().next().unwrap(); + if first_char.is_ascii_digit() || first_char == '-' { + Self::Numeric(s.parse().unwrap()) + } else { + Self::Register(first_char) + } + } + + // fn is_register(&self) -> bool { + // match self { + // Value::Register(_) => true, + // Value::Numeric(_) => false, + // } + // } + + // fn is_numeric(&self) -> bool { + // !self.is_register() + // } +} + +impl Instruction { + fn parse(s: &str) -> Self { + let words: Vec<_> = s.split_whitespace().collect(); + match words[0] { + "cpy" => Self::Cpy(Value::parse(words[1]), Value::parse(words[2])), + "inc" => Self::Inc(Value::parse(words[1])), + "dec" => Self::Dec(Value::parse(words[1])), + "jnz" => Self::Jnz(Value::parse(words[1]), Value::parse(words[2])), + "tgl" => Self::Tgl(Value::parse(words[1])), + _ => panic!("unknown pattern: {s}"), + } + } +} + +fn run_program(program: &mut [Instruction], registers: &mut Registers) { + let mut pointer = 0; + + while let Some(instruction) = program.get(pointer) { + match instruction { + Instruction::Cpy(source, value) => { + match value { + Value::Register(r) => { + registers.set(*r, source); + } + Value::Numeric(_) => (), + } + pointer += 1; + } + Instruction::Inc(value) => { + match value { + Value::Register(r) => { + registers.inc(*r); + } + Value::Numeric(_) => (), + } + pointer += 1; + } + Instruction::Dec(value) => { + match value { + Value::Register(r) => { + registers.dec(*r); + } + Value::Numeric(_) => (), + } + pointer += 1; + } + Instruction::Jnz(register, value) => { + if registers.is_nonzero(register) { + match value { + Value::Register(r) => { + let val = registers.registers[Registers::get_address(*r)]; + pointer = ((pointer as isize) + val) as usize; + } + Value::Numeric(n) => { + pointer = ((pointer as isize) + *n) as usize; + } + } + } else { + pointer += 1; + } + } + Instruction::Tgl(value) => { + let val = match value { + Value::Register(r) => registers.registers[Registers::get_address(*r)], + Value::Numeric(n) => *n, + }; + let instruction = match program.get_mut((pointer as isize + val) as usize) { + Some(instruction) => instruction, + None => { + pointer += 1; + continue; + } + }; + *instruction = match instruction { + Instruction::Cpy(a, b) => Instruction::Jnz(*a, *b), + Instruction::Inc(a) => Instruction::Dec(*a), + Instruction::Dec(a) => Instruction::Inc(*a), + Instruction::Jnz(a, b) => Instruction::Cpy(*a, *b), + Instruction::Tgl(a) => Instruction::Inc(*a), + }; + pointer += 1; + } + } + } +}