Created
December 23, 2017 13:18
-
-
Save jtdowney/e68b4a09b603f1e476b0c4e04899c787 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] | |
extern crate error_chain; | |
mod errors { | |
error_chain! { | |
foreign_links { | |
Io(::std::io::Error); | |
ParseInt(::std::num::ParseIntError); | |
} | |
} | |
} | |
use errors::*; | |
use std::collections::HashMap; | |
use std::env; | |
use std::fs::File; | |
use std::io::{BufRead, BufReader}; | |
use std::str; | |
use std::result; | |
#[derive(Copy, Clone, Debug)] | |
enum Parameter { | |
Register(char), | |
Value(i64), | |
} | |
impl Parameter { | |
fn value(&self, registers: &HashMap<char, i64>) -> i64 { | |
match *self { | |
Parameter::Register(x) => *registers.get(&x).unwrap_or(&0), | |
Parameter::Value(x) => x, | |
} | |
} | |
} | |
impl str::FromStr for Parameter { | |
type Err = Error; | |
fn from_str(line: &str) -> Result<Parameter> { | |
let c = line.chars().nth(0).unwrap(); | |
if c.is_alphabetic() { | |
Ok(Parameter::Register(c)) | |
} else { | |
let value = line.parse()?; | |
Ok(Parameter::Value(value)) | |
} | |
} | |
} | |
#[derive(Copy, Clone, Debug)] | |
enum Instruction { | |
Set(Parameter, Parameter), | |
Sub(Parameter, Parameter), | |
Mul(Parameter, Parameter), | |
Jnz(Parameter, Parameter), | |
} | |
impl str::FromStr for Instruction { | |
type Err = Error; | |
fn from_str(line: &str) -> Result<Instruction> { | |
let parts = line.split_whitespace().collect::<Vec<&str>>(); | |
let instruction = match parts[0] { | |
"set" => Instruction::Set(parts[1].parse()?, parts[2].parse()?), | |
"sub" => Instruction::Sub(parts[1].parse()?, parts[2].parse()?), | |
"mul" => Instruction::Mul(parts[1].parse()?, parts[2].parse()?), | |
"jnz" => Instruction::Jnz(parts[1].parse()?, parts[2].parse()?), | |
i => unreachable!("unknown instruction: {}", i), | |
}; | |
Ok(instruction) | |
} | |
} | |
fn part1(instructions: &[Instruction]) { | |
let mut registers = HashMap::new(); | |
for c in b'a'..b'i' { | |
registers.insert(c as char, 0); | |
} | |
let mut count = 0; | |
let mut ip = 0; | |
loop { | |
match instructions.get(ip).cloned() { | |
Some(Instruction::Set(Parameter::Register(x), y)) => { | |
let value = y.value(®isters); | |
registers.insert(x, value); | |
} | |
Some(Instruction::Sub(Parameter::Register(x), y)) => { | |
let rhs = y.value(®isters); | |
let value = registers.entry(x).or_insert(0); | |
*value -= rhs; | |
} | |
Some(Instruction::Mul(Parameter::Register(x), y)) => { | |
let rhs = y.value(®isters); | |
let value = registers.entry(x).or_insert(0); | |
*value *= rhs; | |
count += 1; | |
} | |
Some(Instruction::Jnz(x, y)) => { | |
if x.value(®isters) != 0 { | |
ip = (ip as i64 + y.value(®isters)) as usize; | |
continue; | |
} | |
} | |
None => break, | |
i => unreachable!("invalid instruction: {:?}", i), | |
} | |
ip += 1; | |
} | |
println!("part 1: {}", count); | |
} | |
fn part2() { | |
let mut b = (84 * 100) + 100_000; | |
let c = b + 17_000; | |
let mut d; | |
let mut f; | |
let mut h = 0; | |
while b <= c { | |
f = 1; | |
d = 2; | |
while d != b { | |
if b % d == 0 { | |
f = 0; | |
break; | |
} | |
d += 1; | |
} | |
if f == 0 { | |
h += 1; | |
} | |
b += 17; | |
} | |
println!("part 2: {}", h); | |
} | |
fn run() -> Result<()> { | |
let filename = env::args().nth(1).expect("filename"); | |
let file = File::open(filename)?; | |
let reader = BufReader::new(file); | |
let instructions = reader | |
.lines() | |
.filter_map(result::Result::ok) | |
.map(|line| line.parse()) | |
.collect::<Result<Vec<Instruction>>>()?; | |
part1(&instructions); | |
part2(); | |
Ok(()) | |
} | |
quick_main!(run); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment