mirror of
https://github.com/FranLMSP/aoc-2024.git
synced 2026-01-01 07:21:35 -05:00
star twenty three
This commit is contained in:
@@ -32,6 +32,7 @@ mod star_twenty_nine;
|
||||
mod star_thirty;
|
||||
mod star_thirty_one;
|
||||
mod star_thirty_two;
|
||||
mod star_thirty_three;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
@@ -68,6 +69,7 @@ fn main() {
|
||||
"30" => star_thirty::run(),
|
||||
"31" => star_thirty_one::run(),
|
||||
"32" => star_thirty_two::run(),
|
||||
"33" => star_thirty_three::run(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
274
src/star_thirty_three.rs
Normal file
274
src/star_thirty_three.rs
Normal file
@@ -0,0 +1,274 @@
|
||||
use std::fs;
|
||||
|
||||
pub fn run() {
|
||||
let file = fs::read_to_string("./inputs/star_thirty_three.txt").unwrap();
|
||||
let mut cpu = parse_input(file.lines());
|
||||
println!("{:?}", cpu);
|
||||
cpu.run();
|
||||
|
||||
println!("Result: {}", cpu.output.clone().iter().map(|o| o.to_string()).collect::<Vec<String>>().join(","));
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct Registers {
|
||||
a: isize,
|
||||
b: isize,
|
||||
c: isize,
|
||||
pc: usize,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct CPU {
|
||||
registers: Registers,
|
||||
halted: bool,
|
||||
program: Vec<u8>,
|
||||
output: Vec<isize>,
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
halted: false,
|
||||
program: vec![],
|
||||
output: vec![],
|
||||
registers: Registers {
|
||||
a: 0,
|
||||
b: 0,
|
||||
c: 0,
|
||||
pc: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
while !self.halted {
|
||||
self.tick();
|
||||
}
|
||||
}
|
||||
|
||||
fn tick(&mut self) {
|
||||
if self.registers.pc >= self.program.len() {
|
||||
self.halted = true;
|
||||
return;
|
||||
}
|
||||
self.decode();
|
||||
}
|
||||
|
||||
fn decode(&mut self) {
|
||||
let opcode = *self.program.get(self.registers.pc).unwrap_or(&0);
|
||||
match opcode {
|
||||
0 => self.adv(),
|
||||
1 => self.bxl(),
|
||||
2 => self.bst(),
|
||||
3 => self.jnz(),
|
||||
4 => self.bxc(),
|
||||
5 => self.out(),
|
||||
6 => self.bdv(),
|
||||
7 => self.cdv(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_operand(&self, operand: u8, is_literal: bool) -> isize {
|
||||
if is_literal {
|
||||
return operand as isize;
|
||||
}
|
||||
match operand {
|
||||
4 => self.registers.a,
|
||||
5 => self.registers.b,
|
||||
6 => self.registers.c,
|
||||
_ => operand as isize,
|
||||
}
|
||||
}
|
||||
|
||||
fn adv(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false);
|
||||
self.registers.a = self.registers.a / 2_isize.pow(operand as u32);
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn bxl(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), true);
|
||||
self.registers.b = self.registers.b ^ operand;
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn bst(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false);
|
||||
self.registers.b = operand & 0b111;
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn jnz(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), true);
|
||||
if self.registers.a == 0 {
|
||||
self.registers.pc += 2;
|
||||
return
|
||||
}
|
||||
self.registers.pc = operand as usize & 0b111;
|
||||
}
|
||||
|
||||
fn bxc(&mut self) {
|
||||
self.registers.b = self.registers.b ^ self.registers.c;
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn out(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false);
|
||||
self.output.push(operand & 0b111);
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn bdv(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false);
|
||||
self.registers.b = self.registers.a / 2_isize.pow(operand as u32);
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
|
||||
fn cdv(&mut self) {
|
||||
let operand = self.parse_operand(*self.program.get(self.registers.pc + 1).unwrap_or(&0), false);
|
||||
self.registers.c = self.registers.a / 2_isize.pow(operand as u32);
|
||||
self.registers.pc += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_input<'a, I>(str_lines: I) -> CPU
|
||||
where
|
||||
I: IntoIterator<Item = &'a str>
|
||||
{
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
for str_line in str_lines {
|
||||
let l = str_line.to_string();
|
||||
if l.starts_with("Register A:") {
|
||||
cpu.registers.a = parse_register_data(&l);
|
||||
} else if l.starts_with("Register B:") {
|
||||
cpu.registers.b = parse_register_data(&l);
|
||||
} else if l.starts_with("Register C:") {
|
||||
cpu.registers.c = parse_register_data(&l);
|
||||
} else if l.starts_with("Program:") {
|
||||
cpu.program = parse_program(&l)
|
||||
}
|
||||
}
|
||||
|
||||
cpu
|
||||
}
|
||||
|
||||
fn parse_register_data(str_line: &String) -> isize {
|
||||
str_line[12..].to_string().trim().parse().unwrap()
|
||||
}
|
||||
|
||||
fn parse_program(str_line: &String) -> Vec<u8> {
|
||||
str_line[8..].to_string()
|
||||
.trim()
|
||||
.split(",")
|
||||
.map(|b| b.trim().parse::<u8>().unwrap())
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_input() {
|
||||
let input = String::from("\
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"
|
||||
);
|
||||
let cpu = parse_input(input.lines());
|
||||
let expected_cpu = CPU {
|
||||
halted: false,
|
||||
program: vec![0, 1, 5, 4, 3, 0],
|
||||
output: vec![],
|
||||
registers: Registers {
|
||||
a: 729,
|
||||
b: 0,
|
||||
c: 0,
|
||||
pc: 0,
|
||||
}
|
||||
};
|
||||
assert_eq!(cpu, expected_cpu);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_run_program() {
|
||||
let input = String::from("\
|
||||
Register A: 729
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
assert_eq!(cpu.output, [4,6,3,5,6,3,5,2,1,0]);
|
||||
|
||||
let input = String::from("\
|
||||
Register A: 0
|
||||
Register B: 0
|
||||
Register C: 9
|
||||
|
||||
Program: 2,6
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
assert_eq!(cpu.registers.b, 1);
|
||||
|
||||
let input = String::from("\
|
||||
Register A: 10
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 5,0,5,1,5,4
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
assert_eq!(cpu.output, [0,1,2]);
|
||||
|
||||
let input = String::from("\
|
||||
Register A: 2024
|
||||
Register B: 0
|
||||
Register C: 0
|
||||
|
||||
Program: 0,1,5,4,3,0
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
assert_eq!(cpu.output, [4,2,5,6,7,7,7,7,3,1,0]);
|
||||
assert_eq!(cpu.registers.a, 0);
|
||||
|
||||
let input = String::from("\
|
||||
Register A: 0
|
||||
Register B: 29
|
||||
Register C: 9
|
||||
|
||||
Program: 1,7
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
// assert_eq!(cpu.registers.b, 27);
|
||||
|
||||
let input = String::from("\
|
||||
Register A: 0
|
||||
Register B: 2024
|
||||
Register C: 43690
|
||||
|
||||
Program: 4,0
|
||||
"
|
||||
);
|
||||
let mut cpu = parse_input(input.lines());
|
||||
cpu.run();
|
||||
assert_eq!(cpu.registers.b, 44354);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user