Skip to content

Commit

Permalink
2017 day 2
Browse files Browse the repository at this point in the history
  • Loading branch information
ictrobot committed Oct 24, 2024
1 parent c243e3e commit 32fa300
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 9 deletions.
1 change: 1 addition & 0 deletions crates/utils/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl InputError {
pub fn new(input: &str, index: impl ToIndex, source: impl Into<Box<dyn Error>>) -> Self {
let index = index.input_index(input);
let (line_number, column_number, line) = Self::line_position(input, index);
let line = line.replace('\t', " ");

InputError {
line_number,
Expand Down
60 changes: 55 additions & 5 deletions crates/utils/src/parser/base.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::input::{InputError, MapWithInputExt};
use crate::parser::combinator::{Map, MapResult, Optional, Or, Repeat, WithPrefix, WithSuffix};
use crate::parser::combinator::{
Map, MapResult, Optional, Or, RepeatN, RepeatVec, WithPrefix, WithSuffix,
};
use crate::parser::error::WithErrorMsg;
use crate::parser::simple::Eol;
use crate::parser::then::Then2;
Expand Down Expand Up @@ -152,24 +154,72 @@ pub trait Parser: Sized {
Optional { parser: self }
}

/// Repeat this parser `N` times, returning an array.
/// Repeat this parser `N` times, returning an [`array`].
///
/// See also [`repeat`](Self::repeat) which returns a [`Vec`] instead, for unknown or varying
/// number of repeats.
///
/// # Examples
/// ```
/// # use utils::parser::{self, Parser};
/// assert_eq!(
/// parser::u32()
/// .with_suffix(",".optional())
/// .repeat() // N = 3 is inferred
/// .repeat_n() // N = 3 is inferred
/// .parse(b"12,34,56"),
/// Ok(([12, 34, 56], &b""[..]))
/// );
/// ```
fn repeat<const N: usize>(self) -> Repeat<N, Self>
fn repeat_n<const N: usize>(self) -> RepeatN<N, Self>
where
for<'i> Self::Output<'i>: Copy + Default,
{
Repeat { parser: self }
RepeatN { parser: self }
}

/// Repeat this parser while it matches, returning a [`Vec`].
///
/// If the number of items is constant and known in advance, prefer [`repeat_n`](Self::repeat_n)
/// as it avoids allocating.
///
/// See also [`repeat_min`](Self::repeat_min), which ensures at least N items are parsed.
///
/// # Examples
/// ```
/// # use utils::parser::{self, Parser};
/// assert_eq!(
/// parser::u32()
/// .with_suffix(",".optional())
/// .repeat()
/// .parse(b"12,34,56,78"),
/// Ok((vec![12, 34, 56, 78], &b""[..]))
/// );
/// ```
fn repeat(self) -> RepeatVec<Self> {
RepeatVec {
parser: self,
min_elements: 0,
}
}

/// Repeat this parser at least N times, returning a [`Vec`].
///
/// See also [`repeat`](Self::repeat).
///
/// # Examples
/// ```
/// # use utils::parser::{self, Parser};
/// let parser = parser::u32()
/// .with_suffix(",".optional())
/// .repeat_min(3);
/// assert_eq!(parser.parse(b"12,34,56,78"), Ok((vec![12, 34, 56, 78], &b""[..])));
/// assert!(parser.parse(b"12,34").is_err());
/// ```
fn repeat_min(self, min_elements: usize) -> RepeatVec<Self> {
RepeatVec {
parser: self,
min_elements,
}
}

/// Parse a prefix (normally a string literal) before this parser.
Expand Down
32 changes: 30 additions & 2 deletions crates/utils/src/parser/combinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ impl<P: Parser> Parser for Optional<P> {
}

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

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

#[derive(Copy, Clone)]
pub struct RepeatVec<P> {
pub(super) parser: P,
pub(super) min_elements: usize,
}
impl<P: Parser> Parser for RepeatVec<P> {
type Output<'i> = Vec<P::Output<'i>>;
type Then<T: Parser> = Then2<Self, T>;

#[inline]
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
let mut output = Vec::new();
while let Ok((v, remaining)) = self.parser.parse(input) {
output.push(v);
input = remaining;
}
if output.len() >= self.min_elements {
Ok((output, input))
} else {
Err((ParseError::ExpectedMatches(self.min_elements), input))
}
}

fn then<T: Parser>(self, next: T) -> Self::Then<T> {
Then2::new(self, next)
}
}

#[derive(Copy, Clone)]
pub struct Or<A, B> {
pub(super) first: A,
Expand Down
2 changes: 1 addition & 1 deletion crates/year2016/src/day03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl Day03 {
Ok(Self {
input: parser::u32()
.with_prefix(parser::take_while(u8::is_ascii_whitespace))
.repeat()
.repeat_n()
.parse_lines(input)?,
})
}
Expand Down
2 changes: 1 addition & 1 deletion crates/year2016/src/day22.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl Day22 {
parser::u32()
.with_prefix(parser::take_while1(u8::is_ascii_whitespace))
.with_suffix(b'T')
.repeat::<3>(),
.repeat_n::<3>(),
)
.map_res(|(x, y, [size, used, avail])| {
if size == used + avail {
Expand Down
52 changes: 52 additions & 0 deletions crates/year2017/src/day02.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use utils::prelude::*;

/// Calculating spreadsheet checksums.
#[derive(Clone, Debug)]
pub struct Day02 {
rows: Vec<Vec<u32>>,
}

impl Day02 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
Ok(Self {
rows: parser::u32()
.with_suffix(b' '.or(b'\t').optional())
.repeat_min(2)
.map(|mut v| {
v.sort_unstable();
v
})
.parse_lines(input)?,
})
}

#[must_use]
pub fn part1(&self) -> u32 {
self.rows
.iter()
.map(|row| row[row.len() - 1] - row[0])
.sum()
}

#[must_use]
pub fn part2(&self) -> u32 {
self.rows
.iter()
.map(|row| {
for i in 0..row.len() - 1 {
for j in i + 1..row.len() {
if row[j] % row[i] == 0 {
return row[j] / row[i];
}
}
}
panic!("no solution found")
})
.sum()
}
}

examples!(Day02 -> (u32, u32) [
{input: "5 1 9 5\n7 5 3\n2 4 6 8", part1: 18},
{input: "5 9 2 8\n9 4 7 3\n3 8 6 5", part2: 9},
]);
1 change: 1 addition & 0 deletions crates/year2017/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

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

0 comments on commit 32fa300

Please sign in to comment.