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
143
src/bin/day10.rs
143
src/bin/day10.rs
|
@ -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()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in a new issue