2015/08-10, 2015/12-13, started on 2015/14
This commit is contained in:
397
2015/12/src/main.rs
Normal file
397
2015/12/src/main.rs
Normal file
@@ -0,0 +1,397 @@
|
||||
use std::io::{self, Read};
|
||||
use std::iter::Iterator;
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
enum Token<'a> {
|
||||
ObjectStart,
|
||||
ObjectEnd,
|
||||
ArrayStart,
|
||||
ArrayEnd,
|
||||
Number(i64),
|
||||
String(Cow<'a, str>),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
enum State {
|
||||
Unknown,
|
||||
InObject,
|
||||
InArray,
|
||||
Number(usize),
|
||||
String(usize),
|
||||
}
|
||||
|
||||
|
||||
struct Parser<'a> {
|
||||
state: Vec<State>,
|
||||
input: &'a str,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
fn new(input: &'a str) -> Self {
|
||||
Parser {
|
||||
state: Vec::new(),
|
||||
input: input,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Parser<'a> {
|
||||
type Item = Token<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Token<'a>> {
|
||||
if self.index >= self.input.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut iter = self.input.chars().skip(self.index);
|
||||
|
||||
let mut next = iter.next();
|
||||
|
||||
while let Some(ch) = next {
|
||||
let state = self.state.last().unwrap_or(&State::Unknown).clone();
|
||||
|
||||
match (state, ch) {
|
||||
// Unknown.
|
||||
(State::Unknown, '-') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::Unknown, '0'...'9') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::Unknown, '"') => {
|
||||
self.state.push(State::String(self.index + 1));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::Unknown, '{') => {
|
||||
self.state.push(State::InObject);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ObjectStart);
|
||||
}
|
||||
(State::Unknown, '[') => {
|
||||
self.state.push(State::InArray);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ArrayStart);
|
||||
}
|
||||
|
||||
// Number.
|
||||
(State::Number(_), '0'...'9') => {
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::Number(start), _) => {
|
||||
self.state.pop();
|
||||
|
||||
return Some(Token::Number(
|
||||
self.input[start..self.index].parse::<i64>().unwrap(),
|
||||
));
|
||||
}
|
||||
|
||||
// String.
|
||||
(State::String(start), '"') => {
|
||||
self.state.pop();
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::String(self.input[start..self.index - 1].into()));
|
||||
}
|
||||
(State::String(_), _) => {
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
|
||||
// Object.
|
||||
(State::InObject, '"') => {
|
||||
self.state.push(State::String(self.index + 1));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InObject, '-') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InObject, '0'...'9') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InObject, '{') => {
|
||||
self.state.push(State::InObject);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ObjectStart);
|
||||
}
|
||||
(State::InObject, '[') => {
|
||||
self.state.push(State::InArray);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ArrayStart);
|
||||
}
|
||||
(State::InObject, '}') => {
|
||||
self.state.pop();
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ObjectEnd);
|
||||
}
|
||||
|
||||
// Array.
|
||||
(State::InArray, '"') => {
|
||||
self.state.push(State::String(self.index + 1));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InArray, '-') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InArray, '0'...'9') => {
|
||||
self.state.push(State::Number(self.index));
|
||||
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
(State::InArray, '{') => {
|
||||
self.state.push(State::InObject);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ObjectStart);
|
||||
}
|
||||
(State::InArray, '[') => {
|
||||
self.state.push(State::InArray);
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ArrayStart);
|
||||
}
|
||||
(State::InArray, ']') => {
|
||||
self.state.pop();
|
||||
|
||||
self.index += 1;
|
||||
|
||||
return Some(Token::ArrayEnd);
|
||||
}
|
||||
|
||||
// Everything else.
|
||||
(_, _) => {
|
||||
self.index += 1;
|
||||
next = iter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Stack {
|
||||
sum: i64,
|
||||
in_object: bool,
|
||||
expect_key: bool,
|
||||
discard: bool,
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let mut input = String::new();
|
||||
|
||||
io::stdin()
|
||||
.read_to_string(&mut input)
|
||||
.expect("faild to read input");
|
||||
|
||||
let mut total = 0;
|
||||
let mut stack = Vec::new();
|
||||
|
||||
stack.push(Stack {
|
||||
sum: 0,
|
||||
in_object: false,
|
||||
expect_key: false,
|
||||
discard: false,
|
||||
});
|
||||
|
||||
for line in input.lines() {
|
||||
for value in Parser::new(line) {
|
||||
match value {
|
||||
Token::String(ref string) => {
|
||||
let this = stack.last_mut().unwrap();
|
||||
|
||||
if this.in_object {
|
||||
if this.expect_key {
|
||||
this.expect_key = false;
|
||||
} else if string == "red" {
|
||||
this.expect_key = true;
|
||||
this.discard = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::Number(number) => {
|
||||
let this = stack.last_mut().unwrap();
|
||||
|
||||
if this.in_object {
|
||||
this.expect_key = true;
|
||||
}
|
||||
|
||||
this.sum += number;
|
||||
}
|
||||
Token::ObjectStart => {
|
||||
stack.push(Stack {
|
||||
sum: 0,
|
||||
in_object: true,
|
||||
expect_key: true,
|
||||
discard: false,
|
||||
});
|
||||
}
|
||||
Token::ObjectEnd => {
|
||||
let this = stack.pop().unwrap();
|
||||
|
||||
if !this.discard {
|
||||
let entry = stack.last_mut().unwrap();
|
||||
|
||||
entry.sum += this.sum;
|
||||
}
|
||||
}
|
||||
Token::ArrayStart => {
|
||||
stack.push(Stack {
|
||||
sum: 0,
|
||||
in_object: false,
|
||||
expect_key: false,
|
||||
discard: false,
|
||||
});
|
||||
}
|
||||
Token::ArrayEnd => {
|
||||
let that = stack.pop().unwrap();
|
||||
let this = stack.last_mut().unwrap();
|
||||
|
||||
this.sum += that.sum;
|
||||
|
||||
if this.in_object {
|
||||
this.expect_key = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let this = stack.last_mut().unwrap();
|
||||
|
||||
total += this.sum;
|
||||
}
|
||||
|
||||
println!("total={}", total);
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn example_01() {
|
||||
let mut parser = Parser::new(r#"[1,2,3]"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::Number(1)));
|
||||
assert_eq!(parser.next(), Some(Token::Number(2)));
|
||||
assert_eq!(parser.next(), Some(Token::Number(3)));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_02() {
|
||||
let mut parser = Parser::new(r#"{"a":2,"b":4}"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ObjectStart));
|
||||
assert_eq!(parser.next(), Some(Token::String("a".into())));
|
||||
assert_eq!(parser.next(), Some(Token::Number(2)));
|
||||
assert_eq!(parser.next(), Some(Token::String("b".into())));
|
||||
assert_eq!(parser.next(), Some(Token::Number(4)));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_03() {
|
||||
let mut parser = Parser::new(r#"[[[3]]]"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::Number(3)));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_04() {
|
||||
let mut parser = Parser::new(r#"{"a":{"b":4},"c":-1}"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ObjectStart));
|
||||
assert_eq!(parser.next(), Some(Token::String("a".into())));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectStart));
|
||||
assert_eq!(parser.next(), Some(Token::String("b".into())));
|
||||
assert_eq!(parser.next(), Some(Token::Number(4)));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectEnd));
|
||||
assert_eq!(parser.next(), Some(Token::String("c".into())));
|
||||
assert_eq!(parser.next(), Some(Token::Number(-1)));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_05() {
|
||||
let mut parser = Parser::new(r#"{"a":[-1,1]}"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ObjectStart));
|
||||
assert_eq!(parser.next(), Some(Token::String("a".into())));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::Number(-1)));
|
||||
assert_eq!(parser.next(), Some(Token::Number(1)));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn example_06() {
|
||||
let mut parser = Parser::new(r#"[-1,{"a":1}]"#);
|
||||
|
||||
assert_eq!(parser.next(), Some(Token::ArrayStart));
|
||||
assert_eq!(parser.next(), Some(Token::Number(-1)));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectStart));
|
||||
assert_eq!(parser.next(), Some(Token::String("a".into())));
|
||||
assert_eq!(parser.next(), Some(Token::Number(1)));
|
||||
assert_eq!(parser.next(), Some(Token::ObjectEnd));
|
||||
assert_eq!(parser.next(), Some(Token::ArrayEnd));
|
||||
assert_eq!(parser.next(), None);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user