Cleanup for 2022 day 10: Turned into a lib and introduced parse errors
This commit is contained in:
parent
6e1656f7ee
commit
68802e6959
3 changed files with 121 additions and 124 deletions
121
2022/day10-cathode-ray_tube/src/lib.rs
Normal file
121
2022/day10-cathode-ray_tube/src/lib.rs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
use core::fmt::Display;
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum ParseError<'a> {
|
||||||
|
ParseIntError(std::num::ParseIntError),
|
||||||
|
UnknownInstruction(&'a str),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for ParseError<'_> {
|
||||||
|
fn from(value: ParseIntError) -> Self {
|
||||||
|
Self::ParseIntError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ParseError<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::ParseIntError(e) => write!(f, "Unable to parse into integer: {e}"),
|
||||||
|
Self::UnknownInstruction(i) => write!(f, "Tried to parse unknown instruction {i}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cpu {
|
||||||
|
states: Vec<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a> TryFrom<&'a str> for Cpu {
|
||||||
|
type Error = ParseError<'a>;
|
||||||
|
|
||||||
|
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||||
|
let mut cpu = Cpu { states: vec![1, 1] };
|
||||||
|
for instruction in value.lines() {
|
||||||
|
match &instruction[0..4] {
|
||||||
|
"noop" => cpu.noop(),
|
||||||
|
"addx" => cpu.addx(instruction[5..].parse()?),
|
||||||
|
instr => return Err(Self::Error::UnknownInstruction(instr)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(cpu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cpu {
|
||||||
|
fn addx(&mut self, x: i32) {
|
||||||
|
let old_state = *self.states.last().unwrap();
|
||||||
|
self.states.push(old_state);
|
||||||
|
self.states.push(old_state + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn noop(&mut self) {
|
||||||
|
let old_state = *self.states.last().unwrap();
|
||||||
|
self.states.push(old_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_rendering(&self) -> String {
|
||||||
|
let mut rendering = String::new();
|
||||||
|
(0..self.states.len()/40).for_each(|line_number| {
|
||||||
|
if line_number != 0 {
|
||||||
|
rendering.push('\n');
|
||||||
|
}
|
||||||
|
let mut this_line = String::new();
|
||||||
|
(0..40).for_each(|col_number| {
|
||||||
|
let clock_cycle = 40*line_number+col_number;
|
||||||
|
if (clock_cycle as i32 % 40 - self.states[clock_cycle + 1]).abs() < 2 {
|
||||||
|
this_line += "#";
|
||||||
|
} else {
|
||||||
|
this_line += ".";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rendering.push_str(&this_line);
|
||||||
|
});
|
||||||
|
rendering
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(input: &str) -> Result<(i32, String), ParseError> {
|
||||||
|
let cpu = Cpu::try_from(input)?;
|
||||||
|
let first = [20, 60, 100, 140, 180, 220].iter()
|
||||||
|
.map(|&i| i as i32 * cpu.states[i])
|
||||||
|
.sum();
|
||||||
|
let second = cpu.get_rendering();
|
||||||
|
Ok((first, second))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
fn read_file(name: &str) -> String {
|
||||||
|
read_to_string(name).expect(&format!("Unable to read file: {name}")[..]).trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sample() {
|
||||||
|
let sample_input = read_file("tests/sample_input");
|
||||||
|
let expected = &r#"
|
||||||
|
##..##..##..##..##..##..##..##..##..##..
|
||||||
|
###...###...###...###...###...###...###.
|
||||||
|
####....####....####....####....####....
|
||||||
|
#####.....#####.....#####.....#####.....
|
||||||
|
######......######......######......####
|
||||||
|
#######.......#######.......#######....."#[1..];
|
||||||
|
assert_eq!(run(&sample_input), Ok((13140, expected.to_string())));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_challenge() {
|
||||||
|
let challenge_input = read_file("tests/challenge_input");
|
||||||
|
let expected = &r#"
|
||||||
|
####.####.###..###..###..####.####.####.
|
||||||
|
#.......#.#..#.#..#.#..#.#.......#.#....
|
||||||
|
###....#..###..#..#.###..###....#..###..
|
||||||
|
#.....#...#..#.###..#..#.#.....#...#....
|
||||||
|
#....#....#..#.#....#..#.#....#....#....
|
||||||
|
#....####.###..#....###..#....####.#...."#[1..];
|
||||||
|
assert_eq!(run(&challenge_input), Ok((14720, expected.to_string())));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,124 +0,0 @@
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
struct Cpu {
|
|
||||||
states: Vec<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cpu {
|
|
||||||
fn addx(&mut self, x: i32) {
|
|
||||||
let old_state = *self.states.last().unwrap();
|
|
||||||
self.states.push(old_state);
|
|
||||||
self.states.push(old_state + x);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn noop(&mut self) {
|
|
||||||
let old_state = *self.states.last().unwrap();
|
|
||||||
self.states.push(old_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(&mut self, instruction: &str) {
|
|
||||||
match &instruction[0..4] {
|
|
||||||
"noop" => self.noop(),
|
|
||||||
"addx" => self.addx(instruction[5..].parse().unwrap()),
|
|
||||||
_ => panic!("Unknown instruction"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_rendering(&self) -> String {
|
|
||||||
let mut rendering = String::new();
|
|
||||||
(0..self.states.len()/40).for_each(|line_number| {
|
|
||||||
if line_number != 0 {
|
|
||||||
rendering.push('\n');
|
|
||||||
}
|
|
||||||
let mut this_line = String::new();
|
|
||||||
(0..40).for_each(|col_number| {
|
|
||||||
let clock_cycle = 40*line_number+col_number;
|
|
||||||
if (clock_cycle as i32 % 40 - self.states[clock_cycle + 1]).abs() < 2 {
|
|
||||||
this_line += "#";
|
|
||||||
} else {
|
|
||||||
this_line += ".";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
rendering.push_str(&this_line);
|
|
||||||
});
|
|
||||||
rendering
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&self) {
|
|
||||||
for line_number in 0..self.states.len()/40 {
|
|
||||||
let mut line_string = String::new();
|
|
||||||
for col_number in 0..40 {
|
|
||||||
let clock_cycle = 40*line_number+col_number;
|
|
||||||
if (clock_cycle as i32 % 40 - self.states[clock_cycle + 1]).abs() < 2 {
|
|
||||||
line_string += "#";
|
|
||||||
} else {
|
|
||||||
line_string += ".";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("{line_string}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_file(path: &str) -> String {
|
|
||||||
fs::read_to_string(path)
|
|
||||||
.expect("File not Found")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
//let program = read_file("sample_input");
|
|
||||||
let program = read_file("input");
|
|
||||||
|
|
||||||
let mut cpu = Cpu { states: vec![1, 1], };
|
|
||||||
for instruction in program.lines() {
|
|
||||||
cpu.parse(instruction);
|
|
||||||
}
|
|
||||||
let sum_of_relevant_strengths: i32 = [20, 60, 100, 140, 180, 220].iter()
|
|
||||||
.map(|&i| i as i32 * cpu.states[i])
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
println!("The relevant signal strengths sum up to {sum_of_relevant_strengths}.");
|
|
||||||
cpu.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn sample_input() {
|
|
||||||
let program = read_file("tests/sample_input");
|
|
||||||
|
|
||||||
let mut cpu = Cpu { states: vec![1, 1], };
|
|
||||||
for instruction in program.lines() {
|
|
||||||
cpu.parse(instruction);
|
|
||||||
}
|
|
||||||
let sum_of_relevant_strengths: i32 = [20, 60, 100, 140, 180, 220].iter()
|
|
||||||
.map(|&i| i as i32 * cpu.states[i])
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
assert_eq!(sum_of_relevant_strengths, 13140);
|
|
||||||
assert_eq!(cpu.get_rendering(), r#"##..##..##..##..##..##..##..##..##..##..
|
|
||||||
###...###...###...###...###...###...###.
|
|
||||||
####....####....####....####....####....
|
|
||||||
#####.....#####.....#####.....#####.....
|
|
||||||
######......######......######......####
|
|
||||||
#######.......#######.......#######....."#);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn challenge_input() {
|
|
||||||
let program = read_file("tests/input");
|
|
||||||
|
|
||||||
let mut cpu = Cpu { states: vec![1, 1], };
|
|
||||||
for instruction in program.lines() {
|
|
||||||
cpu.parse(instruction);
|
|
||||||
}
|
|
||||||
let sum_of_relevant_strengths: i32 = [20, 60, 100, 140, 180, 220].iter()
|
|
||||||
.map(|&i| i as i32 * cpu.states[i])
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
assert_eq!(sum_of_relevant_strengths, 14720);
|
|
||||||
assert_eq!(cpu.get_rendering(), r#"####.####.###..###..###..####.####.####.
|
|
||||||
#.......#.#..#.#..#.#..#.#.......#.#....
|
|
||||||
###....#..###..#..#.###..###....#..###..
|
|
||||||
#.....#...#..#.###..#..#.#.....#...#....
|
|
||||||
#....#....#..#.#....#..#.#....#....#....
|
|
||||||
#....####.###..#....###..#....####.#...."#);
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue