Skip to content

Commit 32fa300

Browse files
committed
2017 day 2
1 parent c243e3e commit 32fa300

File tree

7 files changed

+141
-9
lines changed

7 files changed

+141
-9
lines changed

crates/utils/src/input.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ impl InputError {
4848
pub fn new(input: &str, index: impl ToIndex, source: impl Into<Box<dyn Error>>) -> Self {
4949
let index = index.input_index(input);
5050
let (line_number, column_number, line) = Self::line_position(input, index);
51+
let line = line.replace('\t', " ");
5152

5253
InputError {
5354
line_number,

crates/utils/src/parser/base.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::input::{InputError, MapWithInputExt};
2-
use crate::parser::combinator::{Map, MapResult, Optional, Or, Repeat, WithPrefix, WithSuffix};
2+
use crate::parser::combinator::{
3+
Map, MapResult, Optional, Or, RepeatN, RepeatVec, WithPrefix, WithSuffix,
4+
};
35
use crate::parser::error::WithErrorMsg;
46
use crate::parser::simple::Eol;
57
use crate::parser::then::Then2;
@@ -152,24 +154,72 @@ pub trait Parser: Sized {
152154
Optional { parser: self }
153155
}
154156

155-
/// Repeat this parser `N` times, returning an array.
157+
/// Repeat this parser `N` times, returning an [`array`].
158+
///
159+
/// See also [`repeat`](Self::repeat) which returns a [`Vec`] instead, for unknown or varying
160+
/// number of repeats.
156161
///
157162
/// # Examples
158163
/// ```
159164
/// # use utils::parser::{self, Parser};
160165
/// assert_eq!(
161166
/// parser::u32()
162167
/// .with_suffix(",".optional())
163-
/// .repeat() // N = 3 is inferred
168+
/// .repeat_n() // N = 3 is inferred
164169
/// .parse(b"12,34,56"),
165170
/// Ok(([12, 34, 56], &b""[..]))
166171
/// );
167172
/// ```
168-
fn repeat<const N: usize>(self) -> Repeat<N, Self>
173+
fn repeat_n<const N: usize>(self) -> RepeatN<N, Self>
169174
where
170175
for<'i> Self::Output<'i>: Copy + Default,
171176
{
172-
Repeat { parser: self }
177+
RepeatN { parser: self }
178+
}
179+
180+
/// Repeat this parser while it matches, returning a [`Vec`].
181+
///
182+
/// If the number of items is constant and known in advance, prefer [`repeat_n`](Self::repeat_n)
183+
/// as it avoids allocating.
184+
///
185+
/// See also [`repeat_min`](Self::repeat_min), which ensures at least N items are parsed.
186+
///
187+
/// # Examples
188+
/// ```
189+
/// # use utils::parser::{self, Parser};
190+
/// assert_eq!(
191+
/// parser::u32()
192+
/// .with_suffix(",".optional())
193+
/// .repeat()
194+
/// .parse(b"12,34,56,78"),
195+
/// Ok((vec![12, 34, 56, 78], &b""[..]))
196+
/// );
197+
/// ```
198+
fn repeat(self) -> RepeatVec<Self> {
199+
RepeatVec {
200+
parser: self,
201+
min_elements: 0,
202+
}
203+
}
204+
205+
/// Repeat this parser at least N times, returning a [`Vec`].
206+
///
207+
/// See also [`repeat`](Self::repeat).
208+
///
209+
/// # Examples
210+
/// ```
211+
/// # use utils::parser::{self, Parser};
212+
/// let parser = parser::u32()
213+
/// .with_suffix(",".optional())
214+
/// .repeat_min(3);
215+
/// assert_eq!(parser.parse(b"12,34,56,78"), Ok((vec![12, 34, 56, 78], &b""[..])));
216+
/// assert!(parser.parse(b"12,34").is_err());
217+
/// ```
218+
fn repeat_min(self, min_elements: usize) -> RepeatVec<Self> {
219+
RepeatVec {
220+
parser: self,
221+
min_elements,
222+
}
173223
}
174224

175225
/// Parse a prefix (normally a string literal) before this parser.

crates/utils/src/parser/combinator.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ impl<P: Parser> Parser for Optional<P> {
7474
}
7575

7676
#[derive(Copy, Clone)]
77-
pub struct Repeat<const N: usize, P> {
77+
pub struct RepeatN<const N: usize, P> {
7878
pub(super) parser: P,
7979
}
80-
impl<const N: usize, P: for<'i> Parser<Output<'i>: Copy + Default>> Parser for Repeat<N, P> {
80+
impl<const N: usize, P: for<'i> Parser<Output<'i>: Copy + Default>> Parser for RepeatN<N, P> {
8181
type Output<'i> = [P::Output<'i>; N];
8282
type Then<T: Parser> = Then2<Self, T>;
8383

@@ -101,6 +101,34 @@ impl<const N: usize, P: for<'i> Parser<Output<'i>: Copy + Default>> Parser for R
101101
}
102102
}
103103

104+
#[derive(Copy, Clone)]
105+
pub struct RepeatVec<P> {
106+
pub(super) parser: P,
107+
pub(super) min_elements: usize,
108+
}
109+
impl<P: Parser> Parser for RepeatVec<P> {
110+
type Output<'i> = Vec<P::Output<'i>>;
111+
type Then<T: Parser> = Then2<Self, T>;
112+
113+
#[inline]
114+
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
115+
let mut output = Vec::new();
116+
while let Ok((v, remaining)) = self.parser.parse(input) {
117+
output.push(v);
118+
input = remaining;
119+
}
120+
if output.len() >= self.min_elements {
121+
Ok((output, input))
122+
} else {
123+
Err((ParseError::ExpectedMatches(self.min_elements), input))
124+
}
125+
}
126+
127+
fn then<T: Parser>(self, next: T) -> Self::Then<T> {
128+
Then2::new(self, next)
129+
}
130+
}
131+
104132
#[derive(Copy, Clone)]
105133
pub struct Or<A, B> {
106134
pub(super) first: A,

crates/year2016/src/day03.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ impl Day03 {
1111
Ok(Self {
1212
input: parser::u32()
1313
.with_prefix(parser::take_while(u8::is_ascii_whitespace))
14-
.repeat()
14+
.repeat_n()
1515
.parse_lines(input)?,
1616
})
1717
}

crates/year2016/src/day22.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl Day22 {
3535
parser::u32()
3636
.with_prefix(parser::take_while1(u8::is_ascii_whitespace))
3737
.with_suffix(b'T')
38-
.repeat::<3>(),
38+
.repeat_n::<3>(),
3939
)
4040
.map_res(|(x, y, [size, used, avail])| {
4141
if size == used + avail {

crates/year2017/src/day02.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use utils::prelude::*;
2+
3+
/// Calculating spreadsheet checksums.
4+
#[derive(Clone, Debug)]
5+
pub struct Day02 {
6+
rows: Vec<Vec<u32>>,
7+
}
8+
9+
impl Day02 {
10+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
11+
Ok(Self {
12+
rows: parser::u32()
13+
.with_suffix(b' '.or(b'\t').optional())
14+
.repeat_min(2)
15+
.map(|mut v| {
16+
v.sort_unstable();
17+
v
18+
})
19+
.parse_lines(input)?,
20+
})
21+
}
22+
23+
#[must_use]
24+
pub fn part1(&self) -> u32 {
25+
self.rows
26+
.iter()
27+
.map(|row| row[row.len() - 1] - row[0])
28+
.sum()
29+
}
30+
31+
#[must_use]
32+
pub fn part2(&self) -> u32 {
33+
self.rows
34+
.iter()
35+
.map(|row| {
36+
for i in 0..row.len() - 1 {
37+
for j in i + 1..row.len() {
38+
if row[j] % row[i] == 0 {
39+
return row[j] / row[i];
40+
}
41+
}
42+
}
43+
panic!("no solution found")
44+
})
45+
.sum()
46+
}
47+
}
48+
49+
examples!(Day02 -> (u32, u32) [
50+
{input: "5 1 9 5\n7 5 3\n2 4 6 8", part1: 18},
51+
{input: "5 9 2 8\n9 4 7 3\n3 8 6 5", part2: 9},
52+
]);

crates/year2017/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33

44
utils::year!(2017 => year2017, ${
55
1 => day01::Day01<'_>,
6+
2 => day02::Day02,
67
});

0 commit comments

Comments
 (0)