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

Signed-off-by: Louis Vallat <contact@louis-vallat.dev>
This commit is contained in:
Louis Vallat 2024-12-16 23:27:32 +01:00
parent 31af19e368
commit ade16938e1
Signed by: louis
SSH Key Fingerprint: SHA256:0iPwDU/PZtEy/K13Oar4TzmcunmI9H5U9IsOR3jyT/Q
3 changed files with 187 additions and 1 deletions

View File

@ -11,7 +11,7 @@ jobs:
name: Challenge for day
strategy:
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
steps:
- name: Check out repository code

6
day15/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "day15"
version = "0.1.0"
edition = "2021"
[dependencies]

180
day15/src/main.rs Normal file
View 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)
);
}
}