use std::io::{self, Read};
#[derive(Clone, Copy)]
enum State {
Group,
Garbage,
Ignore,
}
fn scan(input: &str) -> (usize, usize) {
let mut score = 0;
let mut garbage = 0;
let mut indendation = 0;
let mut states = Vec::new();
for ch in input.chars() {
let state = *states.last().unwrap_or(&State::Group);
match (state, ch) {
// Group
(State::Group, '{') => {
indendation += 1;
}
(State::Group, '}') => {
score += indendation;
indendation -= 1;
states.pop();
}
(State::Group, '<') => {
states.push(State::Garbage);
}
(State::Group, '!') => {
states.push(State::Ignore);
}
// Garbage
(State::Garbage, '>') => {
states.pop();
}
(State::Garbage, '!') => {
states.push(State::Ignore);
}
(State::Garbage, _) => {
garbage += 1;
}
// Ignore
(State::Ignore, _) => {
states.pop();
}
_ => (),
}
}
(score, garbage)
}
fn main() {
let mut input = String::new();
io::stdin()
.read_to_string(&mut input)
.expect("faild to read input");
let (score, garbage) = scan(&input);
println!("part_one={}", score);
println!("part_two={}", garbage);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_score() {
assert_eq!(scan("{}"), (1, 0));
assert_eq!(scan("{{{}}}"), (6, 0));
assert_eq!(scan("{{},{}}"), (5, 0));
assert_eq!(scan("{{{},{},{{}}}}"), (16, 0));
assert_eq!(scan("{,,,}"), (1, 4));
assert_eq!(scan("{{},{},{},{}}"), (9, 8));
assert_eq!(scan("{{},{},{},{}}"), (9, 0));
assert_eq!(scan("{{},{},{},{}}"), (3, 17));
}
#[test]
fn test_garbage() {
assert_eq!(scan("<>"), (0, 0));
assert_eq!(scan(""), (0, 17));
assert_eq!(scan("<<<<>"), (0, 3));
assert_eq!(scan("<{!>}>"), (0, 2));
assert_eq!(scan(""), (0, 0));
assert_eq!(scan(">"), (0, 0));
assert_eq!(scan(r#"<{o"i!a,<{i"#), (0, 10));
}
}