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