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 {
carts.sort_unstable_by_key(|c| input.grid.width * c.position.y + c.position.x);
for cart in &mut carts {
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 {
carts.sort_unstable_by_key(|c| input.grid.width * c.position.y + c.position.x);
for i in 0..carts.len() {
if carts[i].active {
occupied[carts[i].position] = false;
carts[i].tick(&input.grid);
let next = carts[i].position;
if occupied[next] {
carts.iter_mut().filter(|c| c.position == next).for_each(|c| c.active = false);
occupied[next] = false;
} else {
occupied[next] = true;
}
}
}
carts.retain(|c| c.active);
}
let last = carts[0].position;
format!("{},{}", last.x, last.y)
}