Skip to content

Instantly share code, notes, and snippets.

@shaleh
Created December 28, 2022 09:48
Show Gist options
  • Save shaleh/56321754e7a728aa401866f274f453b9 to your computer and use it in GitHub Desktop.
Save shaleh/56321754e7a728aa401866f274f453b9 to your computer and use it in GitHub Desktop.
Advent of Code 2022 day 10
use std::fs;
use std::str::FromStr;
#[derive(Copy, Clone, Debug)]
enum CpuOpcode {
Noop,
Addx(i64),
}
impl FromStr for CpuOpcode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let pieces: Vec<_> = s.split(' ').collect();
match pieces.as_slice() {
["noop"] => Ok(Self::Noop),
["addx", num] => Ok(Self::Addx(num.parse::<i64>().map_err(|_| ())?)),
_ => Err(()),
}
}
}
#[derive(Debug)]
struct CpuState {
accumulator: i64,
register: i64,
cycle: usize,
current_op: Option<CpuOpcode>,
should_render: bool,
screen: Vec<Vec<char>>,
}
impl CpuState {
fn new(should_render: bool) -> Self {
Self {
accumulator: 0,
register: 1,
cycle: 0,
current_op: None,
should_render,
screen: vec![
vec!['.'; 40],
vec!['.'; 40],
vec!['.'; 40],
vec!['.'; 40],
vec!['.'; 40],
vec!['.'; 40],
],
}
}
fn evaluate(&mut self, opcodes: &[CpuOpcode]) -> i64 {
let mut codes: Vec<_> = opcodes.iter().rev().collect();
while !codes.is_empty() {
self.cycle += 1;
if [20, 60, 100, 140, 180, 220].contains(&self.cycle) {
self.accumulator += self.cycle as i64 * self.register;
}
if self.should_render {
self.render();
}
match self.current_op {
Some(CpuOpcode::Addx(value)) => {
self.register += value;
self.current_op = None;
}
Some(op) => {
unreachable!("unknown op: {:?}", op);
}
None => match codes.pop().expect("next op code") {
CpuOpcode::Noop => {}
op => {
self.current_op = Some(*op);
}
},
}
}
self.accumulator
}
fn render(&mut self) {
let position = (self.cycle - 1) % 40;
let pixel = if ((self.register - 1)..=(self.register + 1)).contains(&(position as i64)) {
'#'
} else {
'.'
};
self.screen[(self.cycle - 1) / 40][position] = pixel;
print!("{}", pixel);
if self.cycle % 40 == 0 {
println!();
}
}
}
fn solve(opcodes: &[CpuOpcode], should_render: bool) -> i64 {
let mut cpu = CpuState::new(should_render);
cpu.evaluate(opcodes)
}
fn part1(opcodes: &[CpuOpcode]) -> i64 {
solve(opcodes, false)
}
fn part2(opcodes: &[CpuOpcode]) {
solve(opcodes, true);
}
fn parse_input(input: &str) -> Vec<CpuOpcode> {
input
.lines()
.map(|input| input.parse::<CpuOpcode>().expect("valid opcode"))
.collect()
}
fn main() {
let input_raw = fs::read_to_string("../../inputs/10").expect("data");
let opcodes = parse_input(&input_raw);
println!("part1: {}", part1(&opcodes));
part2(&opcodes);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment