extern crate advent_of_code_2018; use advent_of_code_2018::*; use std::error::Error; use std::path::PathBuf; // cargo watch -cs "cargo run --release --bin day_13" #[derive(Debug)] enum Road { LeftRight, UpDown, LeftUpRightDown, RightUpLeftDown, Intersection, None } #[derive(Debug)] struct Cart { next_turn: TurnDirection, facing: FacingDirection, x: usize, y: usize, crashed: bool } #[derive(Debug, Clone, Copy)] enum FacingDirection { Up, Down, Left, Right } #[derive(Debug, Clone, Copy)] enum TurnDirection { Left, Straight, Right } impl TurnDirection { fn next(&self) -> TurnDirection { use TurnDirection::*; match *self { Left => Straight, Straight => Right, Right => Left } } fn rotate(&self, facing: &FacingDirection) -> FacingDirection { match *self { TurnDirection::Left => match *facing { FacingDirection::Up => FacingDirection::Left, FacingDirection::Left => FacingDirection::Down, FacingDirection::Down => FacingDirection::Right, FacingDirection::Right => FacingDirection::Up }, TurnDirection::Right => match *facing { FacingDirection::Up => FacingDirection::Right, FacingDirection::Left => FacingDirection::Up, FacingDirection::Down => FacingDirection::Left, FacingDirection::Right => FacingDirection::Down }, TurnDirection::Straight => facing.clone() } } } fn main() -> Result<(), Box> { let input = read_file(&PathBuf::from("inputs/13.txt"))?; // for i in &input { // println!("{}", i); // } let mut map: Vec> = Vec::new(); let mut carts: Vec = Vec::new(); for (y, line) in input.iter().enumerate() { let mut map_row = Vec::new(); for (x, c) in line.chars().enumerate() { let tile = match c { ' ' => Road::None, '-' => Road::LeftRight, '|' => Road::UpDown, '/' => Road::LeftUpRightDown, '\\' => Road::RightUpLeftDown, '+' => Road::Intersection, '^' => { carts.push(Cart { next_turn: TurnDirection::Left, facing: FacingDirection::Up, x: x, y: y, crashed: false }); Road::UpDown }, '<' => { carts.push(Cart { next_turn: TurnDirection::Left, facing: FacingDirection::Left, x: x, y: y, crashed: false }); Road::LeftRight }, 'v' => { carts.push(Cart { next_turn: TurnDirection::Left, facing: FacingDirection::Down, x: x, y: y, crashed: false }); Road::UpDown }, '>' => { carts.push(Cart { next_turn: TurnDirection::Left, facing: FacingDirection::Right, x: x, y: y, crashed: false }); Road::LeftRight }, _ => { panic!("Unknown character {}", c); } }; map_row.push(tile); } map.push(map_row); } while carts.len() > 1 { carts.sort_unstable_by(|a, b| a.y.cmp(&b.y).then(a.x.cmp(&b.x))); for i in 0..carts.len() { { let mut cart = &mut carts[i]; let road = &map[cart.y][cart.x]; match (road, cart.facing, cart.next_turn) { (Road::LeftRight, FacingDirection::Left, _) => { cart.x -= 1; }, (Road::LeftRight, FacingDirection::Right, _) => { cart.x += 1; }, (Road::LeftRight, _, _) => { panic!("Sideways cart heading left-right"); }, (Road::UpDown, FacingDirection::Up, _) => { cart.y -= 1; }, (Road::UpDown, FacingDirection::Down, _) => { cart.y += 1; }, (Road::UpDown, _, _) => { panic!("Sideways cart heading up-down"); }, // / (Road::LeftUpRightDown, FacingDirection::Down, _) => { cart.x -= 1; cart.facing = FacingDirection::Left; }, (Road::LeftUpRightDown, FacingDirection::Right, _) => { cart.y -= 1; cart.facing = FacingDirection::Up; }, (Road::LeftUpRightDown, FacingDirection::Left, _) => { cart.y += 1; cart.facing = FacingDirection::Down; }, (Road::LeftUpRightDown, FacingDirection::Up, _) => { cart.x += 1; cart.facing = FacingDirection::Right; }, // \ (Road::RightUpLeftDown, FacingDirection::Up, _) => { cart.x -= 1; cart.facing = FacingDirection::Left; }, (Road::RightUpLeftDown, FacingDirection::Left, _) => { cart.y -= 1; cart.facing = FacingDirection::Up; }, (Road::RightUpLeftDown, FacingDirection::Right, _) => { cart.y += 1; cart.facing = FacingDirection::Down; }, (Road::RightUpLeftDown, FacingDirection::Down, _) => { cart.x += 1; cart.facing = FacingDirection::Right; }, (Road::Intersection, f, d) => { cart.facing = d.rotate(&f); cart.next_turn = d.next(); match cart.facing { FacingDirection::Up => { cart.y -= 1 }, FacingDirection::Down => { cart.y += 1 }, FacingDirection::Left => { cart.x -= 1 }, FacingDirection::Right => { cart.x += 1 }, } }, (Road::None, _, _) => { panic!("Offroad cart!"); } } } let collisions = carts.iter() .enumerate() .filter(|(other_i, other)| *other_i != i && other.x == carts[i].x && other.y == carts[i].y) .map(|(other_i, _)| other_i) .collect::>(); for other_i in collisions { let crash_location = (carts[i].x, carts[i].y); debug!(crash_location); carts[i].crashed = true; carts[other_i].crashed = true; } } carts.retain(|cart| !cart.crashed); } debug!(carts); Ok(()) }