feat: added day 15 part 1 and 2
All checks were successful
Build and run challenges / Challenge for day (1) (push) Successful in 5s
Build and run challenges / Challenge for day (12) (push) Successful in 3s
Build and run challenges / Challenge for day (14) (push) Successful in 3s
Build and run challenges / Challenge for day (10) (push) Successful in 3s
Build and run challenges / Challenge for day (11) (push) Successful in 3s
Build and run challenges / Challenge for day (13) (push) Successful in 3s
Build and run challenges / Challenge for day (15) (push) Successful in 3s
Build and run challenges / Challenge for day (2) (push) Successful in 3s
Build and run challenges / Challenge for day (4) (push) Successful in 5s
Build and run challenges / Challenge for day (5) (push) Successful in 5s
Build and run challenges / Challenge for day (6) (push) Successful in 5s
Build and run challenges / Challenge for day (7) (push) Successful in 4s
Build and run challenges / Challenge for day (3) (push) Successful in 12s
Build and run challenges / Challenge for day (8) (push) Successful in 3s
Build and run challenges / Challenge for day (9) (push) Successful in 3s
All checks were successful
Build and run challenges / Challenge for day (1) (push) Successful in 5s
Build and run challenges / Challenge for day (12) (push) Successful in 3s
Build and run challenges / Challenge for day (14) (push) Successful in 3s
Build and run challenges / Challenge for day (10) (push) Successful in 3s
Build and run challenges / Challenge for day (11) (push) Successful in 3s
Build and run challenges / Challenge for day (13) (push) Successful in 3s
Build and run challenges / Challenge for day (15) (push) Successful in 3s
Build and run challenges / Challenge for day (2) (push) Successful in 3s
Build and run challenges / Challenge for day (4) (push) Successful in 5s
Build and run challenges / Challenge for day (5) (push) Successful in 5s
Build and run challenges / Challenge for day (6) (push) Successful in 5s
Build and run challenges / Challenge for day (7) (push) Successful in 4s
Build and run challenges / Challenge for day (3) (push) Successful in 12s
Build and run challenges / Challenge for day (8) (push) Successful in 3s
Build and run challenges / Challenge for day (9) (push) Successful in 3s
Signed-off-by: Louis Vallat <contact@louis-vallat.dev>
This commit is contained in:
parent
31af19e368
commit
ade16938e1
@ -11,7 +11,7 @@ jobs:
|
|||||||
name: Challenge for day
|
name: Challenge for day
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
day_number: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
|
day_number: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
|
||||||
runs-on: rust-bookworm
|
runs-on: rust-bookworm
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
|
6
day15/Cargo.toml
Normal file
6
day15/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "day15"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
180
day15/src/main.rs
Normal file
180
day15/src/main.rs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
|
enum Position {
|
||||||
|
Free,
|
||||||
|
Box,
|
||||||
|
RightHalfBox,
|
||||||
|
LeftHalfBox,
|
||||||
|
Wall,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_input(path: &str) -> String {
|
||||||
|
fs::read_to_string(path).expect("Cannot read file.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_input(
|
||||||
|
input: &str,
|
||||||
|
) -> (
|
||||||
|
Vec<Vec<Position>>,
|
||||||
|
Vec<Vec<Position>>,
|
||||||
|
Vec<(i32, i32)>,
|
||||||
|
(usize, usize),
|
||||||
|
) {
|
||||||
|
let mut map = Vec::new();
|
||||||
|
let mut enlarged_map = Vec::new();
|
||||||
|
let mut moves = Vec::new();
|
||||||
|
let mut robot = (0, 0);
|
||||||
|
let (raw_map, raw_moves) = input.split_once("\n\n").unwrap();
|
||||||
|
for (row, line) in raw_map.lines().enumerate() {
|
||||||
|
map.push(Vec::new());
|
||||||
|
enlarged_map.push(Vec::new());
|
||||||
|
for (col, char) in line.chars().enumerate() {
|
||||||
|
match char {
|
||||||
|
'#' => {
|
||||||
|
map.last_mut().unwrap().push(Position::Wall);
|
||||||
|
enlarged_map
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.extend(vec![Position::Wall; 2]);
|
||||||
|
}
|
||||||
|
'O' => {
|
||||||
|
map.last_mut().unwrap().push(Position::Box);
|
||||||
|
enlarged_map
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.extend(vec![Position::LeftHalfBox, Position::RightHalfBox]);
|
||||||
|
}
|
||||||
|
'.' | '@' => {
|
||||||
|
map.last_mut().unwrap().push(Position::Free);
|
||||||
|
enlarged_map
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
.extend(vec![Position::Free; 2]);
|
||||||
|
if char == '@' {
|
||||||
|
robot = (row, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for line in raw_moves.lines().filter(|l| !l.is_empty()) {
|
||||||
|
for movement in line.chars() {
|
||||||
|
match movement {
|
||||||
|
'^' => moves.push((-1, 0)),
|
||||||
|
'>' => moves.push((0, 1)),
|
||||||
|
'v' => moves.push((1, 0)),
|
||||||
|
'<' => moves.push((0, -1)),
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moves.reverse();
|
||||||
|
(map, enlarged_map, moves, robot)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn boxes_to_move(
|
||||||
|
map: &Vec<Vec<Position>>,
|
||||||
|
pos: &(usize, usize),
|
||||||
|
movement: &(i32, i32),
|
||||||
|
) -> Option<Vec<(usize, usize, Position)>> {
|
||||||
|
let target_pos = (
|
||||||
|
(pos.0 as i32 + movement.0) as usize,
|
||||||
|
(pos.1 as i32 + movement.1) as usize,
|
||||||
|
);
|
||||||
|
match map[pos.0][pos.1] {
|
||||||
|
Position::Free => return Some(vec![]),
|
||||||
|
Position::Wall => return None,
|
||||||
|
Position::Box => {
|
||||||
|
if let Some(mut boxes) = boxes_to_move(&map, &target_pos, movement) {
|
||||||
|
boxes.push((pos.0, pos.1, Position::Box));
|
||||||
|
return Some(boxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Position::LeftHalfBox | Position::RightHalfBox => {
|
||||||
|
let other_box;
|
||||||
|
let offset;
|
||||||
|
if map[pos.0][pos.1] == Position::LeftHalfBox {
|
||||||
|
other_box = Position::RightHalfBox;
|
||||||
|
offset = 1;
|
||||||
|
} else {
|
||||||
|
other_box = Position::LeftHalfBox;
|
||||||
|
offset = -1;
|
||||||
|
}
|
||||||
|
let target_other_half = (target_pos.0, (target_pos.1 as i32 + offset) as usize);
|
||||||
|
if let Some(mut boxes) = boxes_to_move(&map, &target_pos, movement) {
|
||||||
|
boxes.push((pos.0, pos.1, map[pos.0][pos.1]));
|
||||||
|
if movement.0 != 0 {
|
||||||
|
let other_boxes = boxes_to_move(&map, &target_other_half, movement);
|
||||||
|
return if other_boxes.is_some() {
|
||||||
|
boxes.append(&mut other_boxes.unwrap());
|
||||||
|
boxes.push((pos.0, (pos.1 as i32 + offset) as usize, other_box));
|
||||||
|
Some(boxes)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Some(boxes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_all_moves(map: &mut Vec<Vec<Position>>, robot: &(usize, usize), moves: &Vec<(i32, i32)>) {
|
||||||
|
let mut robot = *robot;
|
||||||
|
for movement in moves.iter().rev() {
|
||||||
|
let target_pos = (
|
||||||
|
(robot.0 as i32 + movement.0) as usize,
|
||||||
|
(robot.1 as i32 + movement.1) as usize,
|
||||||
|
);
|
||||||
|
if let Some(box_positions) = boxes_to_move(map, &target_pos, &movement) {
|
||||||
|
let mut positions_moved = HashSet::new();
|
||||||
|
for box_position in box_positions {
|
||||||
|
if positions_moved.insert(box_position) {
|
||||||
|
map[(box_position.0 as i32 + movement.0) as usize]
|
||||||
|
[(box_position.1 as i32 + movement.1) as usize] = box_position.2;
|
||||||
|
map[box_position.0][box_position.1] = Position::Free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
robot = target_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_gps_score(map: &Vec<Vec<Position>>) -> usize {
|
||||||
|
let mut sum = 0;
|
||||||
|
for (row, line) in map.iter().enumerate() {
|
||||||
|
for (col, position) in line.iter().enumerate() {
|
||||||
|
if *position == Position::Box || *position == Position::LeftHalfBox {
|
||||||
|
sum += 100 * row + col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
for arg in args.iter().skip(1) {
|
||||||
|
let input = read_input(&arg);
|
||||||
|
let (mut map, mut enlarged_map, moves, robot) = parse_input(&input);
|
||||||
|
apply_all_moves(&mut map, &robot, &moves);
|
||||||
|
apply_all_moves(&mut enlarged_map, &(robot.0, robot.1 * 2), &moves);
|
||||||
|
println!("[{}]", &arg);
|
||||||
|
println!("\t[Part 1] => Answer is '{}'.", compute_gps_score(&map));
|
||||||
|
println!(
|
||||||
|
"\t[Part 2] => Answer is '{}'.",
|
||||||
|
compute_gps_score(&enlarged_map)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user