2017/08-09

This commit is contained in:
2017-12-09 11:53:47 +01:00
parent 413c80b41b
commit 02718ba05f
8 changed files with 1412 additions and 0 deletions

286
2017/08/src/main.rs Normal file
View File

@@ -0,0 +1,286 @@
use std::io::{self, Read};
use std::collections::{HashMap, VecDeque};
use ast::*;
mod ast {
#[derive(PartialEq, Debug)]
pub enum Expr<'a> {
Equ(Value<'a>, Value<'a>, Assign<'a>), // ==
Neq(Value<'a>, Value<'a>, Assign<'a>), // !=
Lss(Value<'a>, Value<'a>, Assign<'a>), // <
Leq(Value<'a>, Value<'a>, Assign<'a>), // <=
Gtr(Value<'a>, Value<'a>, Assign<'a>), // >
Geq(Value<'a>, Value<'a>, Assign<'a>), // >=
}
#[derive(PartialEq, Debug)]
pub enum Assign<'a> {
Inc(Value<'a>, Value<'a>), // +
Dec(Value<'a>, Value<'a>), // -
}
#[derive(PartialEq, Debug)]
pub enum Value<'a> {
Register(&'a str),
Number(i64),
}
}
mod parse {
use std::collections::VecDeque;
use ast::*;
#[derive(PartialEq, Debug)]
pub enum AssignType {
Inc,
Dec,
}
#[derive(PartialEq, Debug)]
pub enum ExprType {
Equ,
Neq,
Lss,
Leq,
Gtr,
Geq,
}
pub fn from_str(input: &str) -> Expr {
let mut assign = None;
let mut expr = None;
let mut values = VecDeque::with_capacity(4);
for token in input.split_whitespace() {
match token {
"inc" => assign = Some(AssignType::Inc),
"dec" => assign = Some(AssignType::Dec),
"==" => expr = Some(ExprType::Equ),
"!=" => expr = Some(ExprType::Neq),
"<" => expr = Some(ExprType::Lss),
"<=" => expr = Some(ExprType::Leq),
">" => expr = Some(ExprType::Gtr),
">=" => expr = Some(ExprType::Geq),
"if" => (),
value => values.push_back(
value
.parse::<i64>()
.ok()
.map_or_else(|| Value::Register(token), Value::Number),
),
}
}
let a = values.pop_front().unwrap();
let b = values.pop_front().unwrap();
let assign = match assign.unwrap() {
AssignType::Inc => Assign::Inc(a, b),
AssignType::Dec => Assign::Dec(a, b),
};
let a = values.pop_front().unwrap();
let b = values.pop_front().unwrap();
match expr.unwrap() {
ExprType::Equ => Expr::Equ(a, b, assign),
ExprType::Neq => Expr::Neq(a, b, assign),
ExprType::Lss => Expr::Lss(a, b, assign),
ExprType::Leq => Expr::Leq(a, b, assign),
ExprType::Gtr => Expr::Gtr(a, b, assign),
ExprType::Geq => Expr::Geq(a, b, assign),
}
}
}
fn main() {
let mut input = String::new();
io::stdin()
.read_to_string(&mut input)
.expect("faild to read input");
let mut registers = HashMap::new();
let mut max_value = 0;
for instruction in input
.lines()
.filter(|line| !line.is_empty())
.map(parse::from_str)
.collect::<VecDeque<_>>()
{
let assign = match instruction {
Expr::Equ(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a == b {
Some(assign)
} else {
None
}
}
Expr::Neq(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a != b {
Some(assign)
} else {
None
}
}
Expr::Lss(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a < b {
Some(assign)
} else {
None
}
}
Expr::Leq(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a <= b {
Some(assign)
} else {
None
}
}
Expr::Gtr(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a > b {
Some(assign)
} else {
None
}
}
Expr::Geq(a, b, assign) => {
let a = match a {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
let b = match b {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
if a >= b {
Some(assign)
} else {
None
}
}
};
if let Some(assign) = assign {
match assign {
Assign::Inc(register, value) => {
let value = match value {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
match register {
Value::Register(name) => *registers.entry(name).or_insert(0) += value,
Value::Number(_) => (),
}
}
Assign::Dec(register, value) => {
let value = match value {
Value::Register(name) => *registers.entry(name).or_insert(0),
Value::Number(number) => number,
};
match register {
Value::Register(name) => *registers.entry(name).or_insert(0) -= value,
Value::Number(_) => (),
}
}
}
}
if let Some(value) = registers.values().max() {
if *value > max_value {
max_value = *value;
}
}
}
println!("part_one={}", registers.values().max().unwrap());
println!("part_two={}", max_value);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse() {
use ast::*;
assert_eq!(
parse::from_str("b inc 5 if a > 1"),
Expr::Gtr(
Value::Register("a"),
Value::Number(1),
Assign::Inc(Value::Register("b"), Value::Number(5))
)
);
}
}