Skip to content

Commit d35815a

Browse files
committed
2018 day 8
1 parent eaf554d commit d35815a

File tree

7 files changed

+140
-3
lines changed

7 files changed

+140
-3
lines changed

crates/utils/src/parser/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ pub trait Parser<'i>: Sized {
355355
fn parse_complete(&self, input: &'i str) -> Result<Self::Output, InputError> {
356356
match self.parse(input.as_bytes()).map_with_input(input)? {
357357
(v, []) => Ok(v),
358-
(_, remaining) => Err(InputError::new(input, remaining, "expected end of input")),
358+
(_, remaining) => Err(InputError::new(input, remaining, ParseError::ExpectedEof())),
359359
}
360360
}
361361

crates/utils/src/parser/combinator.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl<'i, P: Parser<'i>, S: Parser<'i>> Parser<'i> for RepeatVec<P, S> {
198198
fn parse_complete(&self, input: &'i str) -> Result<Self::Output, InputError> {
199199
match self.helper(input.as_bytes(), true).map_with_input(input)? {
200200
(v, []) => Ok(v),
201-
(_, remaining) => Err(InputError::new(input, remaining, "expected end of input")),
201+
(_, remaining) => Err(InputError::new(input, remaining, ParseError::ExpectedEof())),
202202
}
203203
}
204204
}

crates/utils/src/parser/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ pub enum ParseError {
1919
ExpectedMatches(usize),
2020
/// Expected $n items or less.
2121
ExpectedLessItems(usize),
22+
/// Expected end of input.
23+
ExpectedEof(),
2224
/// Expected number <= $num.
2325
NumberTooLarge(i128),
2426
/// Expected number >= $num.
@@ -66,6 +68,7 @@ impl Display for ParseError {
6668
max.escape_ascii().to_string(),
6769
)
6870
}
71+
ParseError::ExpectedEof() => write!(f, "expected end of input"),
6972
ParseError::ExpectedMatches(x) => write!(f, "expected at least {x} match"),
7073
ParseError::ExpectedLessItems(x) => write!(f, "expected {x} items or less"),
7174
ParseError::NumberTooLarge(x) => write!(f, "expected number <= {x}"),

crates/utils/src/parser/iterator.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,26 @@ impl<'a, P: Parser<'a>> Iterator for ParserIterator<'a, P> {
3737

3838
impl<'a, P: Parser<'a>> FusedIterator for ParserIterator<'a, P> {}
3939

40+
impl<'a, P: Parser<'a>> ParserIterator<'a, P> {
41+
/// Returns the remaining input.
42+
///
43+
/// # Examples
44+
/// ```
45+
/// # use utils::input::InputError;
46+
/// # use utils::parser::{self, Parser};
47+
/// let mut iterator = parser::u32()
48+
/// .with_suffix(parser::eol())
49+
/// .parse_iterator("12\n34\n56\n78");
50+
/// assert_eq!(iterator.next().unwrap().unwrap(), 12);
51+
/// assert_eq!(iterator.next().unwrap().unwrap(), 34);
52+
/// assert_eq!(iterator.remaining(), b"56\n78");
53+
/// ```
54+
#[inline]
55+
pub fn remaining(&self) -> &'a [u8] {
56+
self.remaining
57+
}
58+
}
59+
4060
/// An iterator which returns successful parse outputs only, skipping over errors.
4161
///
4262
/// See [`Parser::matches_iterator`].
@@ -64,3 +84,22 @@ impl<'a, P: Parser<'a>> Iterator for ParserMatchesIterator<'a, P> {
6484
}
6585

6686
impl<'a, P: Parser<'a>> FusedIterator for ParserMatchesIterator<'a, P> {}
87+
88+
impl<'a, P: Parser<'a>> ParserMatchesIterator<'a, P> {
89+
/// Returns the remaining input.
90+
///
91+
/// # Examples
92+
/// ```
93+
/// # use utils::input::InputError;
94+
/// # use utils::parser::{self, Parser};
95+
/// let mut iterator = parser::u32()
96+
/// .matches_iterator("abc123d456e7xyz");
97+
/// assert_eq!(iterator.next().unwrap(), 123);
98+
/// assert_eq!(iterator.next().unwrap(), 456);
99+
/// assert_eq!(iterator.remaining(), b"e7xyz");
100+
/// ```
101+
#[inline]
102+
pub fn remaining(&self) -> &'a [u8] {
103+
self.remaining
104+
}
105+
}

crates/utils/src/parser/simple.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ impl<'i> Parser<'i> for Eof {
138138
fn parse(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output> {
139139
match input {
140140
[] => Ok(((), input)),
141-
_ => Err((ParseError::Expected("end of input"), input)),
141+
_ => Err((ParseError::ExpectedEof(), input)),
142142
}
143143
}
144144

crates/year2018/src/day08.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use utils::parser::ParseError;
2+
use utils::prelude::*;
3+
4+
/// Summing nested node metadata.
5+
#[derive(Clone, Debug)]
6+
pub struct Day08 {
7+
part1: u32,
8+
part2: u32,
9+
}
10+
11+
impl Day08 {
12+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13+
let mut iter = parser::u32()
14+
.with_consumed()
15+
.with_suffix(b' '.or(parser::eof()))
16+
.parse_iterator(input);
17+
18+
let (part1, part2) = Self::parse_node(&mut |name, min_bound, max_bound| {
19+
let min_bound = min_bound.unwrap_or(0);
20+
let max_bound = max_bound.unwrap_or(u32::MAX);
21+
match iter.next() {
22+
None => Err(InputError::new(
23+
input,
24+
input.len(),
25+
ParseError::Expected(name),
26+
)),
27+
Some(Ok((n, pos))) if n < min_bound => Err(InputError::new(
28+
input,
29+
pos,
30+
ParseError::NumberTooSmall(min_bound.into()),
31+
)),
32+
Some(Ok((n, pos))) if n > max_bound => Err(InputError::new(
33+
input,
34+
pos,
35+
ParseError::NumberTooLarge(max_bound.into()),
36+
)),
37+
Some(Ok((n, _))) => Ok(n),
38+
Some(Err(e)) => Err(e),
39+
}
40+
})?;
41+
42+
let remaining = iter.remaining();
43+
if !remaining.is_empty() {
44+
return Err(InputError::new(input, remaining, ParseError::ExpectedEof()));
45+
}
46+
47+
Ok(Self { part1, part2 })
48+
}
49+
50+
fn parse_node(
51+
next: &mut impl FnMut(&'static str, Option<u32>, Option<u32>) -> Result<u32, InputError>,
52+
) -> Result<(u32, u32), InputError> {
53+
let children = next("child count", None, Some(16))?;
54+
let metadata = next("metadata count", Some(1), None)?;
55+
56+
let mut part1 = 0;
57+
let mut child_values = [0; 16];
58+
for i in 0..children {
59+
let (p1, p2) = Self::parse_node(next)?;
60+
part1 += p1;
61+
child_values[i as usize] = p2;
62+
}
63+
64+
let mut part2 = 0;
65+
for _ in 0..metadata {
66+
let e = next("metadata entry", None, None)?;
67+
part1 += e;
68+
part2 += child_values
69+
.get(e.wrapping_sub(1) as usize)
70+
.copied()
71+
.unwrap_or(0);
72+
}
73+
74+
if children == 0 {
75+
part2 = part1;
76+
}
77+
78+
Ok((part1, part2))
79+
}
80+
81+
#[must_use]
82+
pub fn part1(&self) -> u32 {
83+
self.part1
84+
}
85+
86+
#[must_use]
87+
pub fn part2(&self) -> u32 {
88+
self.part2
89+
}
90+
}
91+
92+
examples!(Day08 -> (u32, u32) [
93+
{input: "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2", part1: 138, part2: 66},
94+
]);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ utils::year!(2018 => year2018, ${
99
5 => day05::Day05,
1010
6 => day06::Day06,
1111
7 => day07::Day07,
12+
8 => day08::Day08,
1213
});

0 commit comments

Comments
 (0)