advent-of-code/2017/day/9/src/main.rs

209 lines
5.4 KiB
Rust
Raw Normal View History

2017-12-12 10:05:25 +00:00
use std::fs::File;
use std::io::{Read, BufReader};
use std::char;
#[derive(Debug, Copy, Clone)]
enum Flags {
InGarbage,
CancelNext,
CancelNextInGarbage,
Normal
}
#[derive(Debug)]
struct State {
group_depth: usize,
flags: Flags,
}
fn main() {
let file = File::open("input").expect("unable to open input file");
let reader = BufReader::new(file);
2017-12-12 10:34:42 +00:00
let (score, garbage_count) = stream(reader);
println!("{}", score);
println!("{}", garbage_count);
2017-12-12 10:05:25 +00:00
}
2017-12-12 10:34:42 +00:00
fn stream<R>(reader: R) -> (usize, usize) where R: Read {
2017-12-12 10:05:25 +00:00
let mut state = State { group_depth: 0, flags: Flags::Normal };
let mut score = 0;
2017-12-12 10:34:42 +00:00
let mut garbage_count = 0;
2017-12-12 10:05:25 +00:00
for byte in reader.bytes() {
state = match (state.flags, byte.ok().and_then(|b| char::from_u32(b as u32))) {
(Flags::CancelNext, _) => State { group_depth: state.group_depth, flags: Flags::Normal },
(Flags::CancelNextInGarbage, _) => State { group_depth: state.group_depth, flags: Flags::InGarbage },
(Flags::Normal, Some('{')) => State { group_depth: state.group_depth + 1, flags: Flags::Normal },
(Flags::Normal, Some('}')) => {
score += state.group_depth;
State { group_depth: state.group_depth - 1, flags: Flags::Normal }
},
(Flags::Normal, Some('<')) => State { group_depth: state.group_depth, flags: Flags::InGarbage },
(Flags::InGarbage, Some('>')) => State { group_depth: state.group_depth, flags: Flags::Normal },
(Flags::InGarbage, Some('!')) => State { group_depth: state.group_depth, flags: Flags::CancelNextInGarbage },
2017-12-12 10:34:42 +00:00
(Flags::InGarbage, Some(_)) => {
garbage_count += 1;
State { group_depth: state.group_depth, flags: Flags::InGarbage }
},
2017-12-12 10:05:25 +00:00
(Flags::Normal, Some('!')) => State { group_depth: state.group_depth, flags: Flags::CancelNext },
(_, Some(_)) => state,
(_, None) => panic!("error reading/converting byte")
};
}
2017-12-12 10:34:42 +00:00
(score, garbage_count)
2017-12-12 10:05:25 +00:00
}
// {}, score of 1.
#[test]
fn test_empty() {
use std::io::Cursor;
let cursor = Cursor::new(b"{}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 1);
2017-12-12 10:05:25 +00:00
}
// {{{}}}, score of 1 + 2 + 3 = 6.
#[test]
fn test_empty_nested() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{{}}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 6);
2017-12-12 10:05:25 +00:00
}
// {{},{}}, score of 1 + 2 + 2 = 5.
#[test]
fn test_empty_empty() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{},{}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 5);
2017-12-12 10:05:25 +00:00
}
// {{{},{},{{}}}}, score of 1 + 2 + 3 + 3 + 3 + 4 = 16.
#[test]
fn test_empty_empty_nested_empty() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{{},{},{{}}}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 16);
2017-12-12 10:05:25 +00:00
}
// {<a>,<a>,<a>,<a>}, score of 1.
#[test]
fn test_four_garbage() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<a>,<a>,<a>,<a>}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 1);
2017-12-12 10:05:25 +00:00
}
// {{<ab>},{<ab>},{<ab>},{<ab>}}, score of 1 + 2 + 2 + 2 + 2 = 9.
#[test]
fn test_groups_with_garbage() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{<ab>},{<ab>},{<ab>},{<ab>}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 9);
2017-12-12 10:05:25 +00:00
}
// {{<!!>},{<!!>},{<!!>},{<!!>}}, score of 1 + 2 + 2 + 2 + 2 = 9.
#[test]
fn test_groups_with_cancellations() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{<!!>},{<!!>},{<!!>},{<!!>}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 9);
2017-12-12 10:05:25 +00:00
}
// {{<a!>},{<a!>},{<a!>},{<ab>}}, score of 1 + 2 = 3.
#[test]
fn test_groups_with_garbage_exclamation() {
use std::io::Cursor;
let cursor = Cursor::new(b"{{<a!>},{<a!>},{<a!>},{<ab>}}");
2017-12-12 10:34:42 +00:00
let (score, _) = stream(cursor);
assert_eq!(score, 3);
}
// Part Two
// <>, 0 characters.
#[test]
fn test_garbage_empty() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 0);
}
// <random characters>, 17 characters.
#[test]
fn test_garbage_count_random_characters() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<random characters>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 17);
}
// <<<<>, 3 characters.
#[test]
fn test_garbage_repeated_start() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<<<<>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 3);
2017-12-12 10:05:25 +00:00
}
2017-12-12 10:34:42 +00:00
// <{!>}>, 2 characters.
#[test]
fn test_garbage_cancel_one() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<{!>}>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 2);
}
// <!!>, 0 characters.
#[test]
fn test_garbage_cancel_cancel() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<!!>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 0);
}
2017-12-12 10:05:25 +00:00
2017-12-12 10:34:42 +00:00
// <!!!>>, 0 characters.
#[test]
fn test_garbage_cancel_cancel_end() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<!!!>>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 0);
}
// <{o"i!a,<{i<a>, 10 characters.
#[test]
fn test_garbage_gibberish() {
use std::io::Cursor;
let cursor = Cursor::new(b"{<{o\"i!a,<{i<a>}");
let (_, garbage_count) = stream(cursor);
assert_eq!(garbage_count, 10);
}