Skip to content

Commit

Permalink
2017 day 20
Browse files Browse the repository at this point in the history
  • Loading branch information
ictrobot committed Nov 3, 2024
1 parent 8e51d9d commit 65cc1ce
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 14 deletions.
10 changes: 6 additions & 4 deletions crates/utils/src/parser/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,17 +166,19 @@ pub trait Parser: Sized {
/// # use utils::parser::{self, Parser};
/// assert_eq!(
/// parser::u32()
/// .with_suffix(",".or(parser::eof()))
/// .repeat_n() // N = 3 is inferred
/// .repeat_n(",") // N = 3 is inferred
/// .parse(b"12,34,56"),
/// Ok(([12, 34, 56], &b""[..]))
/// );
/// ```
fn repeat_n<const N: usize>(self) -> RepeatN<N, Self>
fn repeat_n<const N: usize, S: Parser>(self, separator: S) -> RepeatN<N, Self, S>
where
for<'i> Self::Output<'i>: Copy + Default,
{
RepeatN { parser: self }
RepeatN {
parser: self,
separator,
}
}

/// Repeat this parser while it matches, returning a [`ArrayVec`](crate::array::ArrayVec).
Expand Down
16 changes: 13 additions & 3 deletions crates/utils/src/parser/combinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,24 +64,34 @@ impl<P: Parser> Parser for Optional<P> {
}

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

#[inline]
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
let mut output = [P::Output::default(); N];
for item in &mut output {
for (i, item) in output.iter_mut().enumerate() {
match self.parser.parse(input) {
Ok((v, remaining)) => {
*item = v;
input = remaining;
}
Err(e) => return Err(e),
}

if i < N - 1 {
match self.separator.parse(input) {
Ok((_, remaining)) => input = remaining,
Err(e) => return Err(e),
}
}
}
Ok((output, input))
}
Expand Down
6 changes: 3 additions & 3 deletions crates/utils/src/parser/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ impl Parser for Eof {
/// assert_eq!(
/// parser::u32()
/// .with_suffix(b','.or(parser::eof()))
/// .repeat_n()
/// .parse(b"12,34,56"),
/// Ok(([12, 34, 56], &b""[..]))
/// .parse_all("12,34,56")
/// .unwrap(),
/// vec![12, 34, 56],
/// );
/// ```
#[must_use]
Expand Down
7 changes: 5 additions & 2 deletions crates/utils/src/point.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! 2D point implementation.
//! 2D & 3D point implementations.

use crate::number::{Number, Signed, SignedInteger, UnsignedInteger};
use std::fmt::Debug;
Expand Down Expand Up @@ -155,4 +155,7 @@ impl<T: Signed> Point2D<T> {
}
}

// point_impl! {pub struct Point3D{x, y, z}}
point_impl! {
/// Struct representing a 3D point or vector.
pub struct Point3D{x, y, z}
}
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_n()
.repeat_n(parser::noop())
.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_n::<3>(),
.repeat_n(parser::noop()),
)
.map_res(|(x, y, [size, used, avail])| {
if size == used + avail {
Expand Down
109 changes: 109 additions & 0 deletions crates/year2017/src/day20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use std::collections::HashMap;
use utils::point::Point3D;
use utils::prelude::*;

/// Simulating colliding particles.
#[derive(Clone, Debug)]
pub struct Day20 {
particles: Vec<Particle>,
}

#[derive(Clone, Debug)]
struct Particle {
position: Point3D<i64>,
velocity: Point3D<i64>,
acceleration: Point3D<i64>,
}

impl Day20 {
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
let vector = parser::i64()
.repeat_n(b',')
.map(|[x, y, z]| Point3D::new(x, y, z));

Ok(Self {
particles: vector
.with_prefix("p=<")
.then(vector.with_prefix(">, v=<"))
.then(vector.with_prefix(">, a=<").with_suffix(">"))
.map(|(position, velocity, acceleration)| Particle {
position,
velocity,
acceleration,
})
.parse_lines(input)?,
})
}

#[must_use]
pub fn part1(&self) -> usize {
self.particles
.iter()
.enumerate()
.min_by_key(|&(_, p)| p.position_at_time(1_000_000).manhattan_distance_unsigned())
.unwrap()
.0
}

#[must_use]
pub fn part2(&self) -> usize {
let mut particles = self.particles.clone();
let mut destroyed = vec![false; particles.len()];

let mut positions = HashMap::new();
let mut last_destroyed = 0;
for t in 0.. {
positions.clear();

for (i, p) in particles.iter_mut().enumerate() {
if destroyed[i] {
continue;
}

p.tick();

if let Some(j) = positions.insert(p.position, i) {
destroyed[i] = true;
destroyed[j] = true;
last_destroyed = t;
}
}

// Stop when nothing has been destroyed for 10 turns and at least one particle has been
// destroyed.
if last_destroyed <= t - 10 && destroyed.iter().any(|&x| x) {
break;
}
}

particles.len() - destroyed.iter().filter(|&&p| p).count()
}
}

impl Particle {
fn position_at_time(&self, time: u64) -> Point3D<i64> {
self.position
+ (self.velocity * time as i64)
+ (self.acceleration * (time as i64 * time as i64 / 2))
}

fn tick(&mut self) {
self.velocity += self.acceleration;
self.position += self.velocity;
}
}

examples!(Day20 -> (usize, usize) [
{
input: "p=<3,0,0>, v=<2,0,0>, a=<-1,0,0>\n\
p=<4,0,0>, v=<0,0,0>, a=<-2,0,0>",
part1: 0,
},
{
input: "p=<-6,0,0>, v=<3,0,0>, a=<0,0,0>\n\
p=<-4,0,0>, v=<2,0,0>, a=<0,0,0>\n\
p=<-2,0,0>, v=<1,0,0>, a=<0,0,0>\n\
p=<3,0,0>, v=<-1,0,0>, a=<0,0,0>",
part2: 1,
},
]);
1 change: 1 addition & 0 deletions crates/year2017/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ utils::year!(2017 => year2017, ${
17 => day17::Day17,
18 => day18::Day18,
19 => day19::Day19,
20 => day20::Day20,
});

0 comments on commit 65cc1ce

Please sign in to comment.