Cleaner but slightly slower implementation

This commit is contained in:
2022-12-10 22:00:56 +01:00
parent fbfcfa65fb
commit a79eb70581

View File

@@ -1,4 +1,3 @@
use anyhow::Context;
use anyhow::Result; use anyhow::Result;
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
@@ -16,12 +15,22 @@ enum Instruction {
} }
impl Instruction { impl Instruction {
#[inline]
pub fn cycles(self) -> usize { pub fn cycles(self) -> usize {
match self { match self {
Instruction::AddX(_) => 2, Instruction::AddX(_) => 2,
Instruction::Noop => 1, Instruction::Noop => 1,
} }
} }
#[inline]
pub fn execute(self, x: &mut i32, cycle: &mut usize) {
*cycle += self.cycles();
if let Instruction::AddX(v) = self {
*x += v;
}
}
} }
fn parse_instruction(input: &[u8]) -> IResult<&[u8], Instruction> { fn parse_instruction(input: &[u8]) -> IResult<&[u8], Instruction> {
@@ -46,28 +55,18 @@ pub fn part1(input: &[u8]) -> Result<String> {
let mut total = 0; let mut total = 0;
for instruction in &mut input_it { for instruction in &mut input_it {
let cycles = instruction.cycles(); let old_cycle = cycle;
let old_x = x; let old_x = x;
match instruction { instruction.execute(&mut x, &mut cycle);
Instruction::AddX(val) => x += val,
Instruction::Noop => (),
}
if cycle % 40 < 20 && (cycle + cycles) % 40 >= 20 { if old_cycle % 40 < 20 && cycle % 40 >= 20 {
let to_report = if (cycle + cycles) % 40 == 20 { let to_report = if cycle % 40 == 20 { x } else { old_x };
x
} else {
old_x
};
let checkpoint = (cycle + cycles) / 20 * 20; let checkpoint = cycle / 20 * 20;
total += to_report * (checkpoint as i32); total += to_report * (checkpoint as i32);
} }
cycle += cycles;
if cycle >= 220 { if cycle >= 220 {
return Ok(total.to_string()); return Ok(total.to_string());
} }
@@ -79,22 +78,15 @@ pub fn part1(input: &[u8]) -> Result<String> {
pub fn part2(input: &[u8]) -> Result<String> { pub fn part2(input: &[u8]) -> Result<String> {
let mut x = 1; let mut x = 1;
let mut input_it = iterator(input, parse_instruction); let mut input_it = iterator(input, parse_instruction);
let mut input_it = (&mut input_it).peekable();
let mut output = String::with_capacity(226); let mut output = String::with_capacity(226);
let mut cpu_cycle = 0; let mut cpu_cycle = 0;
let mut next_instruction = (&mut input_it).next().context("No instructions?")?;
for crt_cycle in 1..=240 { for crt_cycle in 1..=240 {
while cpu_cycle + next_instruction.cycles() < crt_cycle { if let Some(instruction) = input_it.next_if(|i| cpu_cycle + i.cycles() < crt_cycle) {
match next_instruction { instruction.execute(&mut x, &mut cpu_cycle);
Instruction::AddX(v) => x += v,
Instruction::Noop => (),
}
cpu_cycle += next_instruction.cycles();
next_instruction = (&mut input_it).next().unwrap_or(next_instruction);
} }
let beam_pos = ((crt_cycle + 39) % 40) as i32; let beam_pos = ((crt_cycle + 39) % 40) as i32;