1
0
Fork 0

day(10): refactor and fix tests

Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
Matej Focko 2022-12-10 13:38:16 +01:00
parent 357888e311
commit 6afe8c41cc
Signed by: mfocko
GPG key ID: 7C47D46246790496

View file

@ -1,13 +1,12 @@
use std::str::FromStr; use std::{fmt::Display, str::FromStr};
use aoc_2022::*; use aoc_2022::*;
use color_eyre::{eyre::eyre, Report}; use color_eyre::{eyre::eyre, Report};
use itertools::Itertools; use itertools::Itertools;
use tracing::{debug, info};
type Input = Vec<Instruction>; type Input = Vec<Instruction>;
type Output = i32; type Output = Out;
#[derive(Debug)] #[derive(Debug)]
enum Instruction { enum Instruction {
@ -32,6 +31,35 @@ impl FromStr for Instruction {
} }
} }
#[derive(Debug, PartialEq, Eq)]
enum Out {
Strengths(i32),
Screen(Vec<Vec<char>>),
}
impl Out {
fn new_strengths() -> Out {
Out::Strengths(0)
}
fn new_screen() -> Out {
Out::Screen(vec![vec![]])
}
}
impl Display for Out {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Out::Screen(screen) => write!(
f,
"\n{}",
screen.iter().map(|line| line.iter().join("")).join("\n")
),
Out::Strengths(strengths) => write!(f, "{strengths}"),
}
}
}
struct State { struct State {
cycle: i32, cycle: i32,
register: i32, register: i32,
@ -45,21 +73,9 @@ impl State {
} }
} }
fn execute(&self, i: &Instruction) -> (State, i32) { fn check_signal_strength(&self, next_cycle: i32, total: &mut i32) {
let next = match i { *total += if let Some(cycle) =
Instruction::Addx(value) => State { (self.cycle..next_cycle).find(|&c| c >= 20 && (c + 20) % 40 == 0)
cycle: self.cycle + 2,
register: self.register + value,
},
Instruction::Noop => State {
cycle: self.cycle + 1,
register: self.register,
},
};
// debug!("New state of CPU: cycle={}, register={}", next.cycle, next.register);
let strength = if let Some(cycle) =
(self.cycle..next.cycle).find(|&c| c >= 20 && (c + 20) % 40 == 0)
{ {
// debug!( // debug!(
// "Adding {} x {} = {} to sum", // "Adding {} x {} = {} to sum",
@ -72,11 +88,27 @@ impl State {
} else { } else {
0 0
}; };
(next, strength)
} }
fn execute_and_draw(&self, i: &Instruction, screen: &mut Vec<Vec<char>>) -> State { fn draw_crt(&self, next_cycle: i32, screen: &mut Vec<Vec<char>>) {
// debug!("Checking: {:?} {:?}", i, (self.cycle..next.cycle));
(self.cycle..next_cycle).for_each(|c| {
if screen.is_empty() || screen.last().unwrap().len() == 40 {
screen.push(vec![]);
}
let idx = screen.len() - 1;
screen[idx].push(
if self.register - 1 <= (c - 1) % 40 && (c - 1) % 40 <= self.register + 1 {
'█'
} else {
' '
},
);
});
}
fn execute(&self, i: &Instruction, output: &mut Out) -> State {
let next = match i { let next = match i {
Instruction::Addx(value) => State { Instruction::Addx(value) => State {
cycle: self.cycle + 2, cycle: self.cycle + 2,
@ -89,27 +121,25 @@ impl State {
}; };
// debug!("New state of CPU: cycle={}, register={}", next.cycle, next.register); // debug!("New state of CPU: cycle={}, register={}", next.cycle, next.register);
// debug!("Checking: {:?} {:?}", i, (self.cycle..next.cycle)); match output {
(self.cycle..next.cycle).for_each(|c| { Out::Screen(screen) => self.draw_crt(next.cycle, screen),
let idx = screen.len() - 1; Out::Strengths(strengths) => self.check_signal_strength(next.cycle, strengths),
screen[idx].push( }
if self.register - 1 <= (c - 1) % 40 && (c - 1) % 40 <= self.register + 1 {
'█'
} else {
' '
},
);
// debug!("{} ; {} <= {} <= {}", screen[idx].last().unwrap(), self.register - 1, c % 40, self.register + 1);
if c % 40 == 0 {
screen.push(Vec::new());
}
});
next next
} }
} }
fn evaluate_instructions(instructions: &[Instruction], mut out: Output) -> Output {
instructions
.iter()
.fold(State::new(), |state, instruction| {
state.execute(instruction, &mut out)
});
out
}
struct Day10; struct Day10;
impl Solution<Input, Output> for Day10 { impl Solution<Input, Output> for Day10 {
fn parse_input<P: AsRef<Path>>(pathname: P) -> Input { fn parse_input<P: AsRef<Path>>(pathname: P) -> Input {
@ -117,29 +147,11 @@ impl Solution<Input, Output> for Day10 {
} }
fn part_1(input: &Input) -> Output { fn part_1(input: &Input) -> Output {
input evaluate_instructions(input, Out::new_strengths())
.iter()
.fold((State::new(), 0), |(state, strength_sum), instruction| {
let (new_state, strength) = state.execute(instruction);
(new_state, strength_sum + strength)
})
.1
} }
fn part_2(input: &Input) -> Output { fn part_2(input: &Input) -> Output {
let mut screen: Vec<Vec<char>> = vec![vec![]]; evaluate_instructions(input, Out::new_screen())
input.iter().fold(State::new(), |state, instruction| {
state.execute_and_draw(instruction, &mut screen)
});
info!(
"Screen:\n{}",
screen.iter().map(|line| line.iter().join("")).join("\n")
);
0
} }
} }
@ -147,4 +159,19 @@ fn main() -> Result<()> {
Day10::main() Day10::main()
} }
test_sample!(day_10, Day10, 13140, 1); test_sample!(
day_10,
Day10,
Out::Strengths(13140),
Out::Screen(
("██ ██ ██ ██ ██ ██ ██ ██ ██ ██ \n\
\n\
\n\
\n\
\n\
")
.lines()
.map(|l| l.chars().collect_vec())
.collect_vec()
)
);