Add day 8 part 2 solution

This commit is contained in:
Wesley Moore 2017-12-10 19:22:58 +11:00
parent 37bef8869f
commit e608483ef0
2 changed files with 109 additions and 58 deletions

View file

@ -22,3 +22,6 @@ You might also encounter <= (less than or equal to) or != (not equal to). Howeve
What is the largest value in any register after completing the instructions in your puzzle input?
--- Part Two ---
To be safe, the CPU also needs to know the highest value held in any register during this process so that it can decide how much memory to allocate to these operations. For example, in the above instructions, the highest value ever held was 10 (in register c after the third instruction was evaluated).

View file

@ -3,66 +3,86 @@ use std::fs::File;
use std::collections::HashMap;
use std::str::FromStr;
type Registers = HashMap<String, i64>;
pub struct RegisterMachine {
registers: HashMap<String, i64>,
max_seen: i64
}
impl RegisterMachine {
pub fn new() -> Self {
RegisterMachine {
registers: HashMap::new(),
max_seen: 0
}
}
pub fn max(&self) -> i64 {
*self.registers.values().max().unwrap()
}
pub fn registers(&self) -> &HashMap<String, i64> {
&self.registers
}
pub fn max_seen(&self) -> i64 {
self.max_seen
}
fn eval_cond(lhs: i64, cond: &str, rhs: i64) -> bool {
match cond {
"==" => lhs == rhs,
"!=" => lhs != rhs,
">" => lhs > rhs,
">=" => lhs >= rhs,
"<" => lhs < rhs,
"<=" => lhs <= rhs,
_ => panic!("unknown cond op, '{}'", cond)
}
}
fn eval_line(&mut self, line: &str) {
let tokens = line.split_whitespace().collect::<Vec<_>>();
// b inc 5 if a > 1
let register = tokens[0];
let op = tokens[1];
let op_operand = i64::from_str(tokens[2]).expect("op operand is not a number");
let cond_reg = tokens[4];
let cond_op = tokens[5];
let cond_operand = i64::from_str(tokens[6]).expect("cond operand is not a number");
if RegisterMachine::eval_cond(self.registers.get(cond_reg).map(|val| *val).unwrap_or(0), cond_op, cond_operand) {
if !self.registers.contains_key(register) {
self.registers.insert(register.to_owned(), 0);
}
let register_val = self.registers.get_mut(register).unwrap();
match op {
"inc" => *register_val += op_operand,
"dec" => *register_val -= op_operand,
_ => panic!("unknown operation, '{}'", op)
}
self.max_seen = self.max_seen.max(*register_val)
}
}
fn eval(&mut self, input: &str) {
for line in input.lines() {
self.eval_line(line);
}
}
}
fn main() {
let mut input = String::new();
let mut file = File::open("input").expect("unable to open input file");
file.read_to_string(&mut input).expect("error reading input");
let max = max_value(&eval(&input));
println!("{}", max);
}
let mut machine = RegisterMachine::new();
machine.eval(&input);
println!("Part 1: {}", machine.max());
println!("Part 2: {}", machine.max_seen());
fn eval_cond(lhs: i64, cond: &str, rhs: i64) -> bool {
match cond {
"==" => lhs == rhs,
"!=" => lhs != rhs,
">" => lhs > rhs,
">=" => lhs >= rhs,
"<" => lhs < rhs,
"<=" => lhs <= rhs,
_ => panic!("unknown cond op, '{}'", cond)
}
}
fn eval_line(registers: &mut Registers, line: &str) {
let tokens = line.split_whitespace().collect::<Vec<_>>();
// b inc 5 if a > 1
let register = tokens[0];
let op = tokens[1];
let op_operand = i64::from_str(tokens[2]).expect("op operand is not a number");
let cond_reg = tokens[4];
let cond_op = tokens[5];
let cond_operand = i64::from_str(tokens[6]).expect("cond operand is not a number");
if eval_cond(registers.get(cond_reg).map(|val| *val).unwrap_or(0), cond_op, cond_operand) {
if !registers.contains_key(register) {
registers.insert(register.to_owned(), 0);
}
let register_val = registers.get_mut(register).unwrap();
match op {
"inc" => *register_val += op_operand,
"dec" => *register_val -= op_operand,
_ => panic!("unknown operation, '{}'", op)
}
}
}
fn eval(input: &str) -> Registers {
let mut registers = HashMap::new();
for line in input.lines() {
eval_line(&mut registers, line);
}
registers
}
fn max_value(registers: &Registers) -> i64 {
*registers.values().max().unwrap()
}
#[test]
@ -76,14 +96,42 @@ fn test_eval() {
expected.insert("a".to_owned(), 1);
expected.insert("c".to_owned(), -10);
assert_eq!(eval(input), expected);
let mut machine = RegisterMachine::new();
machine.eval(input);
assert_eq!(machine.registers(), &expected);
}
#[test]
fn test_max_value() {
let mut registers = HashMap::new();
registers.insert("a".to_owned(), 1);
registers.insert("c".to_owned(), -10);
let input = "b inc 5 if a > 1\na inc 1 if b < 5\nc dec -10 if a >= 1\nc inc -20 if c == 10\n";
let mut expected = HashMap::new();
assert_eq!(max_value(&registers), 1);
// a is increased by 1 (to 1) because b is less than 5 (it is 0).
// c is decreased by -10 (to 10) because a is now greater than or equal to 1 (it is 1).
// c is increased by -20 (to -10) because c is equal to 10.
expected.insert("a".to_owned(), 1);
expected.insert("c".to_owned(), -10);
let mut machine = RegisterMachine::new();
machine.eval(input);
assert_eq!(machine.max(), 1);
}
#[test]
fn test_max_seen() {
let input = "b inc 5 if a > 1\na inc 1 if b < 5\nc dec -10 if a >= 1\nc inc -20 if c == 10\n";
let mut expected = HashMap::new();
// a is increased by 1 (to 1) because b is less than 5 (it is 0).
// c is decreased by -10 (to 10) because a is now greater than or equal to 1 (it is 1).
// c is increased by -20 (to -10) because c is equal to 10.
expected.insert("a".to_owned(), 1);
expected.insert("c".to_owned(), -10);
let mut machine = RegisterMachine::new();
machine.eval(input);
assert_eq!(machine.max_seen(), 10);
}