day10 finished
This commit is contained in:
parent
f630ef6874
commit
54fd03233a
6 changed files with 464 additions and 2 deletions
165
src/days/day10/mod.rs
Normal file
165
src/days/day10/mod.rs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
use super::template::{DayTrait, ResultType};
|
||||
use std::{num::ParseIntError, slice::Iter};
|
||||
use thiserror::Error;
|
||||
|
||||
const DAY_NUMBER: usize = 10;
|
||||
|
||||
pub struct Day;
|
||||
|
||||
impl DayTrait for Day {
|
||||
fn get_day_number(&self) -> usize {
|
||||
DAY_NUMBER
|
||||
}
|
||||
|
||||
fn part1(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let instructions = lines
|
||||
.iter()
|
||||
.map(|line| Instruction::parse(line))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let result = CpuCycles::signal_strength(&instructions, &[20, 60, 100, 140, 180, 220]);
|
||||
Ok(ResultType::Integer(result as i64))
|
||||
}
|
||||
|
||||
fn part2(&self, lines: &[String]) -> anyhow::Result<ResultType> {
|
||||
let instructions = lines
|
||||
.iter()
|
||||
.map(|line| Instruction::parse(line))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let result = CpuCycles::draw(&instructions);
|
||||
Ok(ResultType::Lines(result))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum CpuError {
|
||||
#[error("unknown instruction: {0}")]
|
||||
UnknownInstruction(String),
|
||||
|
||||
#[error("could not parse Number")]
|
||||
InvalidInteger(#[from] ParseIntError),
|
||||
}
|
||||
|
||||
enum Instruction {
|
||||
Add(i32),
|
||||
Noop,
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
pub fn parse(line: &str) -> Result<Self, CpuError> {
|
||||
if line == "noop" {
|
||||
Ok(Instruction::Noop)
|
||||
} else if line.starts_with("addx") {
|
||||
let value = line[5..].parse()?;
|
||||
Ok(Instruction::Add(value))
|
||||
} else {
|
||||
Err(CpuError::UnknownInstruction(line.to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CpuCycles<'a> {
|
||||
register: i32,
|
||||
instructions: Iter<'a, Instruction>,
|
||||
current: Option<i32>,
|
||||
}
|
||||
|
||||
impl<'a> CpuCycles<'a> {
|
||||
pub fn create(instructions: &'a [Instruction]) -> Self {
|
||||
Self {
|
||||
instructions: instructions.iter(),
|
||||
register: 1,
|
||||
current: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal_strength(instructions: &'a [Instruction], to_collect: &[usize]) -> i32 {
|
||||
CpuCycles::create(instructions)
|
||||
.enumerate()
|
||||
.filter_map(|(cycle, register)| {
|
||||
if to_collect.contains(&(cycle + 1)) {
|
||||
Some(register * (cycle + 1) as i32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub fn draw(instructions: &'a [Instruction]) -> Vec<String> {
|
||||
let mut result = Vec::new();
|
||||
let mut line = "".to_owned();
|
||||
for (cycle, sprite) in CpuCycles::create(instructions).enumerate() {
|
||||
let cycle = (cycle % 40) as i32;
|
||||
if (sprite - cycle).abs() <= 1 {
|
||||
line.push('#');
|
||||
} else {
|
||||
line.push(' ');
|
||||
}
|
||||
if cycle == 39 {
|
||||
result.push(line.to_owned());
|
||||
line = "".to_owned();
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CpuCycles<'a> {
|
||||
type Item = i32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(value) = self.current {
|
||||
let start_register = self.register;
|
||||
self.register += value;
|
||||
self.current = None;
|
||||
Some(start_register)
|
||||
} else if let Some(instruction) = self.instructions.next() {
|
||||
match instruction {
|
||||
Instruction::Add(value) => self.current = Some(*value),
|
||||
Instruction::Noop => {}
|
||||
}
|
||||
Some(self.register)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common::file::read_lines;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
fn test_simple() -> Result<()> {
|
||||
let instructions = vec![Instruction::Noop, Instruction::Add(3), Instruction::Add(-5)];
|
||||
let expected = vec![1, 1, 1, 4, 4];
|
||||
let result = CpuCycles::create(&instructions).collect::<Vec<_>>();
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part1() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::Integer(13140);
|
||||
let result = day.part1(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_part2() -> Result<()> {
|
||||
let day = Day {};
|
||||
let lines = read_lines(day.get_day_number(), "example01.txt")?;
|
||||
let expected = ResultType::Lines(read_lines(day.get_day_number(), "expected01.txt")?);
|
||||
let result = day.part2(&lines)?;
|
||||
assert_eq!(result, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ mod day06;
|
|||
mod day07;
|
||||
mod day08;
|
||||
mod day09;
|
||||
mod day10;
|
||||
mod template;
|
||||
|
||||
pub use template::DayTrait;
|
||||
|
|
@ -16,7 +17,7 @@ pub mod day_provider {
|
|||
use super::*;
|
||||
use thiserror::Error;
|
||||
|
||||
const MAX_DAY: usize = 9;
|
||||
const MAX_DAY: usize = 10;
|
||||
|
||||
pub fn get_day(day_num: usize) -> Result<Box<dyn DayTrait>, ProviderError> {
|
||||
match day_num {
|
||||
|
|
@ -29,6 +30,7 @@ pub mod day_provider {
|
|||
7 => Ok(Box::new(day07::Day)),
|
||||
8 => Ok(Box::new(day08::Day)),
|
||||
9 => Ok(Box::new(day09::Day)),
|
||||
10 => Ok(Box::new(day10::Day)),
|
||||
_ => Err(ProviderError::InvalidNumber(day_num)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ fn output(day: usize, part: usize, result: ResultType, time: Duration) {
|
|||
time.as_secs_f32()
|
||||
);
|
||||
for line in &value[1..] {
|
||||
println!(" part : {line}");
|
||||
println!(" {line}");
|
||||
}
|
||||
}
|
||||
ResultType::Nothing => {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue