Skip to content

Commit 65cc1ce

Browse files
committed
2017 day 20
1 parent 8e51d9d commit 65cc1ce

File tree

8 files changed

+139
-14
lines changed

8 files changed

+139
-14
lines changed

crates/utils/src/parser/base.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,19 @@ pub trait Parser: Sized {
166166
/// # use utils::parser::{self, Parser};
167167
/// assert_eq!(
168168
/// parser::u32()
169-
/// .with_suffix(",".or(parser::eof()))
170-
/// .repeat_n() // N = 3 is inferred
169+
/// .repeat_n(",") // N = 3 is inferred
171170
/// .parse(b"12,34,56"),
172171
/// Ok(([12, 34, 56], &b""[..]))
173172
/// );
174173
/// ```
175-
fn repeat_n<const N: usize>(self) -> RepeatN<N, Self>
174+
fn repeat_n<const N: usize, S: Parser>(self, separator: S) -> RepeatN<N, Self, S>
176175
where
177176
for<'i> Self::Output<'i>: Copy + Default,
178177
{
179-
RepeatN { parser: self }
178+
RepeatN {
179+
parser: self,
180+
separator,
181+
}
180182
}
181183

182184
/// Repeat this parser while it matches, returning a [`ArrayVec`](crate::array::ArrayVec).

crates/utils/src/parser/combinator.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,34 @@ impl<P: Parser> Parser for Optional<P> {
6464
}
6565

6666
#[derive(Copy, Clone)]
67-
pub struct RepeatN<const N: usize, P> {
67+
pub struct RepeatN<const N: usize, P, S> {
6868
pub(super) parser: P,
69+
pub(super) separator: S,
6970
}
70-
impl<const N: usize, P: for<'i> Parser<Output<'i>: Copy + Default>> Parser for RepeatN<N, P> {
71+
impl<const N: usize, P: for<'i> Parser<Output<'i>: Copy + Default>, S: Parser> Parser
72+
for RepeatN<N, P, S>
73+
{
7174
type Output<'i> = [P::Output<'i>; N];
7275
type Then<T: Parser> = Then2<Self, T>;
7376

7477
#[inline]
7578
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
7679
let mut output = [P::Output::default(); N];
77-
for item in &mut output {
80+
for (i, item) in output.iter_mut().enumerate() {
7881
match self.parser.parse(input) {
7982
Ok((v, remaining)) => {
8083
*item = v;
8184
input = remaining;
8285
}
8386
Err(e) => return Err(e),
8487
}
88+
89+
if i < N - 1 {
90+
match self.separator.parse(input) {
91+
Ok((_, remaining)) => input = remaining,
92+
Err(e) => return Err(e),
93+
}
94+
}
8595
}
8696
Ok((output, input))
8797
}

crates/utils/src/parser/simple.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ impl Parser for Eof {
162162
/// assert_eq!(
163163
/// parser::u32()
164164
/// .with_suffix(b','.or(parser::eof()))
165-
/// .repeat_n()
166-
/// .parse(b"12,34,56"),
167-
/// Ok(([12, 34, 56], &b""[..]))
165+
/// .parse_all("12,34,56")
166+
/// .unwrap(),
167+
/// vec![12, 34, 56],
168168
/// );
169169
/// ```
170170
#[must_use]

crates/utils/src/point.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! 2D point implementation.
1+
//! 2D & 3D point implementations.
22
33
use crate::number::{Number, Signed, SignedInteger, UnsignedInteger};
44
use std::fmt::Debug;
@@ -155,4 +155,7 @@ impl<T: Signed> Point2D<T> {
155155
}
156156
}
157157

158-
// point_impl! {pub struct Point3D{x, y, z}}
158+
point_impl! {
159+
/// Struct representing a 3D point or vector.
160+
pub struct Point3D{x, y, z}
161+
}

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_n()
14+
.repeat_n(parser::noop())
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_n::<3>(),
38+
.repeat_n(parser::noop()),
3939
)
4040
.map_res(|(x, y, [size, used, avail])| {
4141
if size == used + avail {

crates/year2017/src/day20.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::collections::HashMap;
2+
use utils::point::Point3D;
3+
use utils::prelude::*;
4+
5+
/// Simulating colliding particles.
6+
#[derive(Clone, Debug)]
7+
pub struct Day20 {
8+
particles: Vec<Particle>,
9+
}
10+
11+
#[derive(Clone, Debug)]
12+
struct Particle {
13+
position: Point3D<i64>,
14+
velocity: Point3D<i64>,
15+
acceleration: Point3D<i64>,
16+
}
17+
18+
impl Day20 {
19+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
20+
let vector = parser::i64()
21+
.repeat_n(b',')
22+
.map(|[x, y, z]| Point3D::new(x, y, z));
23+
24+
Ok(Self {
25+
particles: vector
26+
.with_prefix("p=<")
27+
.then(vector.with_prefix(">, v=<"))
28+
.then(vector.with_prefix(">, a=<").with_suffix(">"))
29+
.map(|(position, velocity, acceleration)| Particle {
30+
position,
31+
velocity,
32+
acceleration,
33+
})
34+
.parse_lines(input)?,
35+
})
36+
}
37+
38+
#[must_use]
39+
pub fn part1(&self) -> usize {
40+
self.particles
41+
.iter()
42+
.enumerate()
43+
.min_by_key(|&(_, p)| p.position_at_time(1_000_000).manhattan_distance_unsigned())
44+
.unwrap()
45+
.0
46+
}
47+
48+
#[must_use]
49+
pub fn part2(&self) -> usize {
50+
let mut particles = self.particles.clone();
51+
let mut destroyed = vec![false; particles.len()];
52+
53+
let mut positions = HashMap::new();
54+
let mut last_destroyed = 0;
55+
for t in 0.. {
56+
positions.clear();
57+
58+
for (i, p) in particles.iter_mut().enumerate() {
59+
if destroyed[i] {
60+
continue;
61+
}
62+
63+
p.tick();
64+
65+
if let Some(j) = positions.insert(p.position, i) {
66+
destroyed[i] = true;
67+
destroyed[j] = true;
68+
last_destroyed = t;
69+
}
70+
}
71+
72+
// Stop when nothing has been destroyed for 10 turns and at least one particle has been
73+
// destroyed.
74+
if last_destroyed <= t - 10 && destroyed.iter().any(|&x| x) {
75+
break;
76+
}
77+
}
78+
79+
particles.len() - destroyed.iter().filter(|&&p| p).count()
80+
}
81+
}
82+
83+
impl Particle {
84+
fn position_at_time(&self, time: u64) -> Point3D<i64> {
85+
self.position
86+
+ (self.velocity * time as i64)
87+
+ (self.acceleration * (time as i64 * time as i64 / 2))
88+
}
89+
90+
fn tick(&mut self) {
91+
self.velocity += self.acceleration;
92+
self.position += self.velocity;
93+
}
94+
}
95+
96+
examples!(Day20 -> (usize, usize) [
97+
{
98+
input: "p=<3,0,0>, v=<2,0,0>, a=<-1,0,0>\n\
99+
p=<4,0,0>, v=<0,0,0>, a=<-2,0,0>",
100+
part1: 0,
101+
},
102+
{
103+
input: "p=<-6,0,0>, v=<3,0,0>, a=<0,0,0>\n\
104+
p=<-4,0,0>, v=<2,0,0>, a=<0,0,0>\n\
105+
p=<-2,0,0>, v=<1,0,0>, a=<0,0,0>\n\
106+
p=<3,0,0>, v=<-1,0,0>, a=<0,0,0>",
107+
part2: 1,
108+
},
109+
]);

crates/year2017/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ utils::year!(2017 => year2017, ${
2323
17 => day17::Day17,
2424
18 => day18::Day18,
2525
19 => day19::Day19,
26+
20 => day20::Day20,
2627
});

0 commit comments

Comments
 (0)