day 15 p1

This commit is contained in:
Hamcha 2024-12-15 19:48:18 +01:00
parent 72661aa48e
commit 552cdd2d95
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89
3 changed files with 194 additions and 0 deletions

21
sample/day15-sample.txt Normal file
View file

@ -0,0 +1,21 @@
##########
#..O..O.O#
#......O.#
#.OO..O.O#
#..O@..O.#
#O#..O...#
#O..O..O.#
#.OO.O.OO#
#....O...#
##########
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^

10
sample/day15-sample2.txt Normal file
View file

@ -0,0 +1,10 @@
########
#..O.O.#
##@.O..#
#...O..#
#.#.O..#
#...O..#
#......#
########
<^^>>>vv<v>>v<<

163
src/day15_p1.gleam Normal file
View file

@ -0,0 +1,163 @@
import gleam/dict.{type Dict}
import gleam/io
import gleam/iterator
import gleam/list.{filter, map}
import gleam/string
import stdin.{stdin}
pub fn main() {
stdin()
|> read_input
|> calculate
|> io.debug
}
fn calculate(input: #(Dict(#(Int, Int), Item), List(Movement))) -> Int {
let #(textmap, movements) = input
let #(robot, restmap) = extract_robot(textmap)
do_movements(restmap, robot, movements)
|> dict.filter(fn(_, v) { v == Box })
|> dict.fold(0, fn(acc, k, _) {
let #(x, y) = k
acc + x + y * 100
})
}
fn do_movements(
textmap: Dict(#(Int, Int), Item),
robot: #(Int, Int),
movements: List(Movement),
) -> Dict(#(Int, Int), Item) {
case movements {
[] -> textmap
[next, ..rest] -> {
let #(newmap, newrobot) = move_robot(textmap, robot, next)
do_movements(newmap, newrobot, rest)
}
}
}
fn move_robot(
textmap: Dict(#(Int, Int), Item),
robot: #(Int, Int),
movement: Movement,
) -> #(Dict(#(Int, Int), Item), #(Int, Int)) {
let next_pos = calculate_next_position(robot, movement)
case dict.get(textmap, next_pos) {
Ok(Wall) -> #(textmap, robot)
Ok(Box) ->
case try_move_box(textmap, next_pos, movement) {
Ok(new_map) -> #(new_map, next_pos)
_ -> #(textmap, robot)
}
_ -> #(textmap, next_pos)
}
}
fn try_move_box(
textmap: Dict(#(Int, Int), Item),
box_pos: #(Int, Int),
movement: Movement,
) -> Result(Dict(#(Int, Int), Item), Nil) {
let next_pos = calculate_next_position(box_pos, movement)
case dict.get(textmap, next_pos) {
Ok(Wall) -> Error(Nil)
Ok(Box) ->
case try_move_box(textmap, next_pos, movement) {
Ok(new_map) ->
Ok(new_map |> dict.delete(box_pos) |> dict.insert(next_pos, Box))
_ -> Error(Nil)
}
_ -> Ok(textmap |> dict.delete(box_pos) |> dict.insert(next_pos, Box))
}
}
fn calculate_next_position(
current: #(Int, Int),
movement: Movement,
) -> #(Int, Int) {
let #(x, y) = current
case movement {
Up -> #(x, y - 1)
Down -> #(x, y + 1)
Left -> #(x - 1, y)
Right -> #(x + 1, y)
}
}
fn extract_robot(
objects: Dict(#(Int, Int), Item),
) -> #(#(Int, Int), Dict(#(Int, Int), Item)) {
let assert [robot] =
objects |> dict.filter(fn(_, v) { v == Robot }) |> dict.keys
#(robot, objects |> dict.delete(robot))
}
pub type Item {
Box
Wall
Robot
}
pub type Movement {
Up
Left
Right
Down
}
fn read_input(
it: iterator.Iterator(String),
) -> #(Dict(#(Int, Int), Item), List(Movement)) {
let #(map_lines, movement_lines) =
it
|> iterator.to_list
|> map(string.trim)
|> filter(not(string.is_empty))
|> list.split_while(fn(s) { s |> string.starts_with("#") })
let map_objects =
map_lines
|> list.index_fold(dict.new(), parse_map_line)
let movements =
movement_lines
|> string.concat
|> string.to_graphemes
|> list.map(parse_movement)
#(map_objects, movements)
}
fn parse_map_line(
acc: Dict(#(Int, Int), Item),
line: String,
y: Int,
) -> Dict(#(Int, Int), Item) {
line
|> string.to_graphemes
|> list.index_fold(acc, fn(a, char, x) {
case char {
"#" -> dict.insert(a, #(x, y), Wall)
"O" -> dict.insert(a, #(x, y), Box)
"@" -> dict.insert(a, #(x, y), Robot)
_ -> a
}
})
}
fn parse_movement(char: String) -> Movement {
case char {
"^" -> Up
"<" -> Left
">" -> Right
"v" -> Down
_ -> panic as "invalid char"
}
}
fn not(a: fn(a) -> Bool) {
fn(param: a) -> Bool { !a(param) }
}