day(10): refactor and fix tests
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
357888e311
commit
6afe8c41cc
1 changed files with 85 additions and 58 deletions
141
src/bin/day10.rs
141
src/bin/day10.rs
|
@ -1,13 +1,12 @@
|
|||
use std::str::FromStr;
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use aoc_2022::*;
|
||||
|
||||
use color_eyre::{eyre::eyre, Report};
|
||||
use itertools::Itertools;
|
||||
use tracing::{debug, info};
|
||||
|
||||
type Input = Vec<Instruction>;
|
||||
type Output = i32;
|
||||
type Output = Out;
|
||||
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
cycle: i32,
|
||||
register: i32,
|
||||
|
@ -45,21 +73,9 @@ impl State {
|
|||
}
|
||||
}
|
||||
|
||||
fn execute(&self, i: &Instruction) -> (State, i32) {
|
||||
let next = match i {
|
||||
Instruction::Addx(value) => State {
|
||||
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)
|
||||
fn check_signal_strength(&self, next_cycle: i32, total: &mut i32) {
|
||||
*total += if let Some(cycle) =
|
||||
(self.cycle..next_cycle).find(|&c| c >= 20 && (c + 20) % 40 == 0)
|
||||
{
|
||||
// debug!(
|
||||
// "Adding {} x {} = {} to sum",
|
||||
|
@ -72,11 +88,27 @@ impl State {
|
|||
} else {
|
||||
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 {
|
||||
Instruction::Addx(value) => State {
|
||||
cycle: self.cycle + 2,
|
||||
|
@ -89,27 +121,25 @@ impl State {
|
|||
};
|
||||
// debug!("New state of CPU: cycle={}, register={}", next.cycle, next.register);
|
||||
|
||||
// debug!("Checking: {:?} {:?}", i, (self.cycle..next.cycle));
|
||||
(self.cycle..next.cycle).for_each(|c| {
|
||||
let idx = screen.len() - 1;
|
||||
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());
|
||||
match output {
|
||||
Out::Screen(screen) => self.draw_crt(next.cycle, screen),
|
||||
Out::Strengths(strengths) => self.check_signal_strength(next.cycle, strengths),
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
impl Solution<Input, Output> for Day10 {
|
||||
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 {
|
||||
input
|
||||
.iter()
|
||||
.fold((State::new(), 0), |(state, strength_sum), instruction| {
|
||||
let (new_state, strength) = state.execute(instruction);
|
||||
|
||||
(new_state, strength_sum + strength)
|
||||
})
|
||||
.1
|
||||
evaluate_instructions(input, Out::new_strengths())
|
||||
}
|
||||
|
||||
fn part_2(input: &Input) -> Output {
|
||||
let mut screen: Vec<Vec<char>> = vec![vec![]];
|
||||
|
||||
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
|
||||
evaluate_instructions(input, Out::new_screen())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,4 +159,19 @@ fn main() -> Result<()> {
|
|||
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()
|
||||
)
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue