mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 10:19:55 +00:00
Add day 9 solution
This commit is contained in:
parent
2960b6bea6
commit
cc4b2d86b0
5 changed files with 182 additions and 0 deletions
4
2017/day/9/Cargo.lock
generated
Normal file
4
2017/day/9/Cargo.lock
generated
Normal file
|
@ -0,0 +1,4 @@
|
|||
[[package]]
|
||||
name = "day9"
|
||||
version = "0.1.0"
|
||||
|
6
2017/day/9/Cargo.toml
Normal file
6
2017/day/9/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day9"
|
||||
version = "0.1.0"
|
||||
authors = ["Wesley Moore <wes@wezm.net>"]
|
||||
|
||||
[dependencies]
|
1
2017/day/9/input
Normal file
1
2017/day/9/input
Normal file
File diff suppressed because one or more lines are too long
46
2017/day/9/problem.txt
Normal file
46
2017/day/9/problem.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
--- Day 9: Stream Processing ---
|
||||
|
||||
A large stream blocks your path. According to the locals, it's not safe to cross the stream at the moment because it's full of garbage. You look down at the stream; rather than water, you discover that it's a stream of characters.
|
||||
|
||||
You sit for a while and record part of the stream (your puzzle input). The characters represent groups - sequences that begin with { and end with }. Within a group, there are zero or more other things, separated by commas: either another group or garbage. Since groups can contain other groups, a } only closes the most-recently-opened unclosed group - that is, they are nestable. Your puzzle input represents a single, large group which itself contains many smaller ones.
|
||||
|
||||
Sometimes, instead of a group, you will find garbage. Garbage begins with < and ends with >. Between those angle brackets, almost any character can appear, including { and }. Within garbage, < has no special meaning.
|
||||
|
||||
In a futile attempt to clean up the garbage, some program has canceled some of the characters within it using !: inside garbage, any character that comes after ! should be ignored, including <, >, and even another !.
|
||||
|
||||
You don't see any characters that deviate from these rules. Outside garbage, you only find well-formed groups, and garbage always terminates according to the rules above.
|
||||
|
||||
Here are some self-contained pieces of garbage:
|
||||
|
||||
<>, empty garbage.
|
||||
<random characters>, garbage containing random characters.
|
||||
<<<<>, because the extra < are ignored.
|
||||
<{!>}>, because the first > is canceled.
|
||||
<!!>, because the second ! is canceled, allowing the > to terminate the garbage.
|
||||
<!!!>>, because the second ! and the first > are canceled.
|
||||
<{o"i!a,<{i<a>, which ends at the first >.
|
||||
|
||||
Here are some examples of whole streams and the number of groups they contain:
|
||||
|
||||
{}, 1 group.
|
||||
{{{}}}, 3 groups.
|
||||
{{},{}}, also 3 groups.
|
||||
{{{},{},{{}}}}, 6 groups.
|
||||
{<{},{},{{}}>}, 1 group (which itself contains garbage).
|
||||
{<a>,<a>,<a>,<a>}, 1 group.
|
||||
{{<a>},{<a>},{<a>},{<a>}}, 5 groups.
|
||||
{{<!>},{<!>},{<!>},{<a>}}, 2 groups (since all but the last > are canceled).
|
||||
|
||||
Your goal is to find the total score for all groups in your input. Each group is assigned a score which is one more than the score of the group that immediately contains it. (The outermost group gets a score of 1.)
|
||||
|
||||
{}, score of 1.
|
||||
{{{}}}, score of 1 + 2 + 3 = 6.
|
||||
{{},{}}, score of 1 + 2 + 2 = 5.
|
||||
{{{},{},{{}}}}, score of 1 + 2 + 3 + 3 + 3 + 4 = 16.
|
||||
{<a>,<a>,<a>,<a>}, score of 1.
|
||||
{{<ab>},{<ab>},{<ab>},{<ab>}}, score of 1 + 2 + 2 + 2 + 2 = 9.
|
||||
{{<!!>},{<!!>},{<!!>},{<!!>}}, score of 1 + 2 + 2 + 2 + 2 = 9.
|
||||
{{<a!>},{<a!>},{<a!>},{<ab>}}, score of 1 + 2 = 3.
|
||||
|
||||
What is the total score for all groups in your input?
|
||||
|
125
2017/day/9/src/main.rs
Normal file
125
2017/day/9/src/main.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
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);
|
||||
|
||||
println!("{}", stream(reader));
|
||||
}
|
||||
|
||||
fn stream<R>(reader: R) -> usize where R: Read {
|
||||
let mut state = State { group_depth: 0, flags: Flags::Normal };
|
||||
let mut score = 0;
|
||||
|
||||
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 },
|
||||
(Flags::Normal, Some('!')) => State { group_depth: state.group_depth, flags: Flags::CancelNext },
|
||||
(_, Some(_)) => state,
|
||||
(_, None) => panic!("error reading/converting byte")
|
||||
};
|
||||
|
||||
// println!("{:?}", state);
|
||||
}
|
||||
|
||||
score
|
||||
}
|
||||
|
||||
// {}, score of 1.
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
use std::io::Cursor;
|
||||
|
||||
let cursor = Cursor::new(b"{}");
|
||||
assert_eq!(stream(cursor), 1);
|
||||
}
|
||||
|
||||
// {{{}}}, score of 1 + 2 + 3 = 6.
|
||||
#[test]
|
||||
fn test_empty_nested() {
|
||||
use std::io::Cursor;
|
||||
|
||||
let cursor = Cursor::new(b"{{{}}}");
|
||||
assert_eq!(stream(cursor), 6);
|
||||
}
|
||||
|
||||
// {{},{}}, score of 1 + 2 + 2 = 5.
|
||||
#[test]
|
||||
fn test_empty_empty() {
|
||||
use std::io::Cursor;
|
||||
|
||||
let cursor = Cursor::new(b"{{},{}}");
|
||||
assert_eq!(stream(cursor), 5);
|
||||
}
|
||||
|
||||
// {{{},{},{{}}}}, 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"{{{},{},{{}}}}");
|
||||
assert_eq!(stream(cursor), 16);
|
||||
}
|
||||
|
||||
// {<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>}");
|
||||
assert_eq!(stream(cursor), 1);
|
||||
}
|
||||
|
||||
// {{<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>}}");
|
||||
assert_eq!(stream(cursor), 9);
|
||||
}
|
||||
|
||||
// {{<!!>},{<!!>},{<!!>},{<!!>}}, score of 1 + 2 + 2 + 2 + 2 = 9.
|
||||
#[test]
|
||||
fn test_groups_with_cancellations() {
|
||||
use std::io::Cursor;
|
||||
|
||||
let cursor = Cursor::new(b"{{<!!>},{<!!>},{<!!>},{<!!>}}");
|
||||
assert_eq!(stream(cursor), 9);
|
||||
}
|
||||
|
||||
// {{<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>}}");
|
||||
assert_eq!(stream(cursor), 3);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in a new issue