Skip to content

Commit

Permalink
Year 2018 Day 13
Browse files Browse the repository at this point in the history
  • Loading branch information
maneatingape committed Jul 27, 2024
1 parent b27f5e7 commit b93ddb3
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ Performance is reasonable even on older hardware, for example a 2011 MacBook Pro
| 10 | [The Stars Align](https://adventofcode.com/2018/day/10) | [Source](src/year2018/day10.rs) | 12 |
| 11 | [Chronal Charge](https://adventofcode.com/2018/day/11) | [Source](src/year2018/day11.rs) | 1552 |
| 12 | [Subterranean Sustainability](https://adventofcode.com/2018/day/12) | [Source](src/year2018/day12.rs) | 75 |
| 13 | [Mine Cart Madness](https://adventofcode.com/2018/day/13) | [Source](src/year2018/day13.rs) | 391 |

## 2017

Expand Down
1 change: 1 addition & 0 deletions benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ mod year2018 {
benchmark!(year2018, day10);
benchmark!(year2018, day11);
benchmark!(year2018, day12);
benchmark!(year2018, day13);
}

mod year2019 {
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ pub mod year2018 {
pub mod day10;
pub mod day11;
pub mod day12;
pub mod day13;
}

/// # Rescue Santa from deep space with a solar system adventure.
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ fn year2018() -> Vec<Solution> {
solution!(year2018, day10),
solution!(year2018, day11),
solution!(year2018, day12),
solution!(year2018, day13),
]
}

Expand Down
142 changes: 142 additions & 0 deletions src/year2018/day13.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! # Mine Cart Madness
//!
//! Simulates the mine carts for both parts. When checking the grid we only care about `\`, `/`
//! and `+` characters, all other characters can be ignored. Carts are sorted by `y` and then by
//! `x` before each tick as the movement order is important to resolve collisions or near misses
//! correctly.
use crate::util::grid::*;
use crate::util::point::*;

pub struct Input {
grid: Grid<u8>,
carts: Vec<Cart>,
}

#[derive(Clone, Copy)]
pub struct Cart {
position: Point,
direction: Point,
turns: u32,
active: bool,
}

impl Cart {
fn new(position: Point, direction: Point) -> Cart {
Cart { position, direction, turns: 0, active: true }
}

fn tick(&mut self, grid: &Grid<u8>) {
self.position += self.direction;

match grid[self.position] {
b'\\' => {
self.direction = match self.direction {
UP => LEFT,
DOWN => RIGHT,
LEFT => UP,
RIGHT => DOWN,
_ => unreachable!(),
}
}
b'/' => {
self.direction = match self.direction {
UP => RIGHT,
DOWN => LEFT,
LEFT => DOWN,
RIGHT => UP,
_ => unreachable!(),
}
}
b'+' => {
self.direction = match self.turns {
0 => self.direction.counter_clockwise(),
1 => self.direction,
2 => self.direction.clockwise(),
_ => unreachable!(),
};
self.turns = (self.turns + 1) % 3;
}
_ => (),
}
}
}

pub fn parse(input: &str) -> Input {
let grid = Grid::parse(input);
let mut carts = Vec::new();

for (i, b) in grid.bytes.iter().enumerate() {
let result = match b {
b'^' => Some(UP),
b'v' => Some(DOWN),
b'<' => Some(LEFT),
b'>' => Some(RIGHT),
_ => None,
};

if let Some(direction) = result {
let x = i as i32 % grid.width;
let y = i as i32 / grid.width;
carts.push(Cart::new(Point::new(x, y), direction));
}
}

Input { grid, carts }
}

pub fn part1(input: &Input) -> String {
let mut carts = input.carts.clone();
let mut occupied = input.grid.default_copy();

loop {
// Turn order is important.
carts.sort_unstable_by_key(|c| input.grid.width * c.position.y + c.position.x);

for cart in &mut carts {
// Follow tracks to next position.
occupied[cart.position] = false;
cart.tick(&input.grid);
let next = cart.position;

if occupied[next] {
return format!("{},{}", next.x, next.y);
}

occupied[next] = true;
}
}
}

pub fn part2(input: &Input) -> String {
let mut carts = input.carts.clone();
let mut occupied = input.grid.default_copy();

while carts.len() > 1 {
// Turn order is important.
carts.sort_unstable_by_key(|c| input.grid.width * c.position.y + c.position.x);

for i in 0..carts.len() {
// Crashed carts may not have been removed yet.
if carts[i].active {
// Follow tracks to next position.
occupied[carts[i].position] = false;
carts[i].tick(&input.grid);
let next = carts[i].position;

if occupied[next] {
// Mark both carts as crashed.
carts.iter_mut().filter(|c| c.position == next).for_each(|c| c.active = false);
occupied[next] = false;
} else {
occupied[next] = true;
}
}
}

// Removed crashed carts to speed up future ticks.
carts.retain(|c| c.active);
}

let last = carts[0].position;
format!("{},{}", last.x, last.y)
}
1 change: 1 addition & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ mod year2018 {
mod day10_test;
mod day11_test;
mod day12_test;
mod day13_test;
}

mod year2019 {
Expand Down
28 changes: 28 additions & 0 deletions tests/year2018/day13_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use aoc::year2018::day13::*;

const FIRST_EXAMPLE: &str = r"/->-\ .
| | /----\ .
| /-+--+-\ | .
| | | | v | .
\-+-/ \-+--/ .
\------/ .";

const SECOND_EXAMPLE: &str = r"/>-<\ .
| | .
| /<+-\ .
| | | v .
\>+</ | .
| ^ .
\<->/ .";

#[test]
fn part1_test() {
let input = parse(FIRST_EXAMPLE);
assert_eq!(part1(&input), "7,3");
}

#[test]
fn part2_test() {
let input = parse(SECOND_EXAMPLE);
assert_eq!(part2(&input), "6,4");
}

0 comments on commit b93ddb3

Please sign in to comment.