147 lines
4.5 KiB
Rust
147 lines
4.5 KiB
Rust
use crate::utils;
|
|
use std::collections::HashMap;
|
|
|
|
pub fn task1() {
|
|
let (map, mut carts) = read_input();
|
|
println!("We have {} carts initially", carts.len());
|
|
loop {
|
|
perform_round(&map, &mut carts);
|
|
}
|
|
}
|
|
|
|
fn read_input() -> (Vec<Vec<char>>, Vec<Cart>) {
|
|
let input = utils::read_file("input/day13.txt");
|
|
let input: Vec<&str> = input.lines().collect();
|
|
let width = input[0].len();
|
|
let height = input.len();
|
|
let mut map = Vec::new();
|
|
let mut inner_vec = Vec::new();
|
|
inner_vec.resize(height, ' ');
|
|
map.resize(width, inner_vec);
|
|
let mut carts = Vec::new();
|
|
let tiles = vec!['|', '-', '/', '\\', '+'];
|
|
for (y, line) in input.iter().enumerate() {
|
|
for (x, c) in line.chars().enumerate() {
|
|
if tiles.contains(&c) {
|
|
map[x][y] = c;
|
|
} else if c != ' ' {
|
|
map[x][y] = match c {
|
|
'>' => '-',
|
|
'<' => '-',
|
|
'^' => '-',
|
|
'v' => '-',
|
|
_ => panic!("{} is invalid input char at this point", c),
|
|
};
|
|
carts.push(Cart {
|
|
x,
|
|
y,
|
|
direction: c,
|
|
intersections_visited: 0,
|
|
active: true,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
(map, carts)
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct Cart {
|
|
x: usize,
|
|
y: usize,
|
|
direction: char,
|
|
intersections_visited: usize,
|
|
active: bool,
|
|
}
|
|
|
|
fn perform_round(map: &[Vec<char>], carts: &mut Vec<Cart>) {
|
|
carts.sort_unstable_by(|a, b| {
|
|
if a.y == b.y {
|
|
a.x.cmp(&b.x)
|
|
} else {
|
|
a.y.cmp(&b.y)
|
|
}
|
|
});
|
|
let mut positions: HashMap<(usize, usize), usize> = carts
|
|
.iter()
|
|
.enumerate()
|
|
.filter(|(_, cart)| cart.active)
|
|
.map(|(i, cart)| ((cart.x, cart.y), i))
|
|
.collect();
|
|
|
|
for cart_index in 0..carts.len() {
|
|
let cart = &mut carts[cart_index];
|
|
if !cart.active {
|
|
continue;
|
|
}
|
|
|
|
let pos_old = (cart.x, cart.y);
|
|
match cart.direction {
|
|
'>' => cart.x += 1,
|
|
'<' => cart.x -= 1,
|
|
'^' => cart.y -= 1,
|
|
'v' => cart.y += 1,
|
|
c => panic!("invalid direction {}", c),
|
|
}
|
|
cart.direction = match (cart.direction, map[cart.x][cart.y]) {
|
|
('>', '/') => '^',
|
|
('>', '\\') => 'v',
|
|
('<', '/') => 'v',
|
|
('<', '\\') => '^',
|
|
('^', '/') => '>',
|
|
('^', '\\') => '<',
|
|
('v', '/') => '<',
|
|
('v', '\\') => '>',
|
|
(direction, '+') => {
|
|
let new_direction = match cart.intersections_visited % 3 {
|
|
0 => match direction {
|
|
'>' => '^',
|
|
'^' => '<',
|
|
'<' => 'v',
|
|
'v' => '>',
|
|
_ => panic!("Invalid direction"),
|
|
},
|
|
1 => direction,
|
|
2 => match direction {
|
|
'>' => 'v',
|
|
'^' => '>',
|
|
'<' => '^',
|
|
'v' => '<',
|
|
_ => panic!("Invalid direction"),
|
|
},
|
|
_ => panic!("modulo 3 cannot be larger than 2"),
|
|
};
|
|
cart.intersections_visited += 1;
|
|
new_direction
|
|
}
|
|
(_, _) => cart.direction,
|
|
};
|
|
if positions.contains_key(&(cart.x, cart.y)) {
|
|
// Task1: panic here with coordinates
|
|
println!("We have a collision at {},{}!", cart.x, cart.y);
|
|
let other_index = positions[&(cart.x, cart.y)];
|
|
cart.active = false;
|
|
if !carts[other_index].active {
|
|
panic!("that one crashed already before!");
|
|
}
|
|
carts[other_index].active = false;
|
|
positions.remove(&(carts[cart_index].x, carts[cart_index].y));
|
|
positions.remove(&pos_old);
|
|
println!(
|
|
"{} carts left",
|
|
carts.iter().filter(|cart| cart.active).count()
|
|
);
|
|
} else {
|
|
positions.remove(&pos_old);
|
|
positions.insert((cart.x, cart.y), cart_index);
|
|
}
|
|
}
|
|
if carts.iter().filter(|cart| cart.active).count() == 1 {
|
|
panic!(
|
|
"exactly one active cart left: {:?}",
|
|
carts.iter().find(|cart| cart.active)
|
|
);
|
|
}
|
|
}
|