Day 12
6 files changed, 233 insertions(+), 3 deletions(-) M .gitignore A input/day12.example.txt A input/day12.txt M src/aoc2022.gleam A src/aoc2022/day12.gleam M src/aoc2022/utils.gleam
M .gitignore => .gitignore +1 -0
A input/day12.example.txt => input/day12.example.txt +5 -0
A input/day12.txt => input/day12.txt +41 -0
@@ 0,0 1,41 @@ abccccccaaccaaccccaaaaacccccaaaaccccccccccccccccccccccccccccccccaaaaaaaaaaaaaaaaaaaccccccccccccccccaaaccccccccccccaacccccccccccccccccccccccccccccccccccccccccaaaa abaaaaccaaaaaccccaaaaaccccccaaaaccccccccccccccccccccaaacccccccccccaaaaaaaaaaaaaaaaaaccccccccccccccccaaaaccccccaaacaaccccccccccccccccccccccccccccccccccccccccaaaaa abaaacccaaaaaaaacaaaaaacccccaaaaccccccccccccccccccccaaaaacccccccccaaaaaaaaaaaaaaaaacccccccccaaccccaaaaaacccccccaaaaaccccaaccccccccccccccacccccccccccccccccccaaaaa abaaacccccaaaaaccccaaaaccccccaaacccccccccccccccccccaaaaaccccccccccaaaaaacacaaaaaacccccccccccaaccccaaaaacccccccccaaaaaaccaaaaaaccccccccccaaaccccacccccccccccaaaaaa abaacccccaaaaaccccaacccccccccccccccaaaaacccccccccccaaaaacccccccccaaaaaaaaccaaaaaaacccccccaaaaaaaaccaaaaacccccccaaaaaaaccaaaaacccccccccccaaacccaaaccccccccccccccaa abaaacccaaacaacccccccccccccccccccccaaaaaccccccccccccaaaaacccccccaaaaaaaaaccaaccaaacccccccaaaaaaaaccaacccccccccaaaaaaccaaaaaaccccccccccccaaaacaaaaccccccccccccccaa abaaacccccccaaccccccccccccccccccccaaaaaaccccccccccccaaccccccaacccaaaccaaaaccccccaacccccccccaaaacccccccccccccccaacaaaccaaaaaaaccccccccccccajjjjjjjcccccccccccccccc abcaacccccccccccccccccccccccccccccaaaaaaccccccccccccccccccccaaaaccccccaaaaccccccccccccccaacaaaaaccccccccccccccccccaaccccaaaaaacccccccccccjjjjjjjjjcccccaaaccccccc abccccccccccccccccccccccccccccccccaaaaaaccaaccccccccccccccaaaaaacccccccaaacccccccccccaacaaaaaaaaccccccccccccccccccccccccaaccaaccccccccaiijjjjojjjjcccccaaacaccccc abcccccccccccccccccccccccaaacccccccaaacacaaacccccccccccccccaaaaccccaaccccccccccccccccaaaaaaacccaccccccccccccccccccccccccaacccccccccccaiiijjooooojjkccaaaaaaaacccc abccccccccccccccccccccccaaaaccccccccccaaaaaccccccccccccccccaaaaacccaaaaaccccccccccccccaaaaaacccccccccccccccccccccccccccccccccccccciiiiiiiioooooookkkcaaaaaaaacccc abccccccccccccccccccccccaaaaccccccccccaaaaaaaacccccccccccccaacaaccaaaaacccccccaaacccaaaaaaaaccccccccccccccccccccccccccccccccccchiiiiiiiiooooouoookkkccaaaaaaccccc abcccccccccaaccccccccccccaaaccccccccccccaaaaacccccccccccccccccccccaaaaaccccccaaaacccaaaaacaacccccccccccccaacaacccccccccccccccchhhiiiinnnooouuuuoookkkccaaaaaccccc abcccccccccaaacccccccccccccccccccccccccaaaaacccccccccccccccccccccccaaaaacccccaaaaccccccaaccccccccccccccccaaaaacccccccccccccccchhhnnnnnnnnouuuuuuppkkkkaaaaaaccccc abccccccaaaaaaaacccaaccccccccccccccccccaacaaccaacaaccccccccccccccccaacccccccccaaaccccccaacccccccccccccccaaaaacccccccccccccccchhhnnnnnnnnntuuxuuupppkkkkkacccccccc abccccccaaaaaaaacacaaaacccccccccccccccccccaaccaaaaacccccccccccccccccccccccccccccccccccccccccccccccccccccaaaaaacccccccaacccccchhhnnnnttttttuxxxuuppppkkkkkcccccccc abcccccccaaaaaaccaaaaaaccccccccccaaccccccccccaaaaaccccccccccccccccccccccccaaacccccccccccccccccccccccccccccaaaaccaaccaaacccaaahhhnnntttttttuxxxxuupppppllllccccccc abcccccccaaaaaacccaaaacccccccccaaaaaaccccccccaaaaaacccccccccccccccccccccccaaacccccccccccccccccccccccccccccacccccaaaaaaacaaaaahhhppntttxxxxxxxxuuuuvpppplllccccccc abcccccccaaaaaacccaaaacccccccccaaaaaacccccaaaaaaaaaccccccccccccccccccccaaaaaaaacccccccccccccccccccccaaaccccccaacaaaaaaccaaaaahhhpppttxxxxxxxxyuuvvvvvppplllcccccc abcccccccaaccaacccaacaccaaaaccccaaaaacccccaaaaaaaaaccccccccccccccccccccaaaaaaaacccccccccccccccccccccaaacaaaaaaaccaaaaaaaaaaaaahhppptttxxxxxxyyyyyyvvvppplllcccccc SbccccccccccccccccccccccaaaacccaaaaacccccccaaaaaaaaacaaaccccccccaacccccccaaaaaccccccccaaaaacccccccccaaaaaaaaaaaaaaaaaaaaaaaaacgggpppttxxxxEzzyyyyyvvvqqqlllcccccc abccccccccccccccccccccccaaaacccaaaaacccccccaaaaaaaaccaaaccccccccaaacaaccaaaaaaccccccccaaaaacccccccaaaaaaaaaaaaaaaaaaaaaaaaaaacgggpppsssxxxyyyyyyvvvvvqqlllccccccc abcccaaaccccccccccccccccaaaccccccccccccccccaaaaaaaaaaaaaccccccccaaaaaaccaaaaaacccccccaaaaaacccaaaccaaaaaccaaaaaaaaaaaacccccccccgggppssswwyyyyyyvvvvqqqqlllccccccc abcaaaaaccccccccccccccccccccccccccccccccccaaaaaaaaaaaaacccccccaaaaaaacccaccaaacccccccaaaaaacccaaacccaaaaaaaaaaaccccaaacccaaaaacgggppsswwwyyyyyyvvqqqqqlllcccccccc abcaaaaaaccccccccccccccccccccccccccccccccccaaccaaaaaaaaaaaccccaaaaaaacccccccccccccccccaaaaacccaaacaaaacaaaaaaaaccccaaacccaaaaacggpppsswwwywwyyyvvqqqmmmlccccccccc abcaaaaaacccccccaacaaccccccccccccccccccccccccccaaaaaaaaaaaccccccaaaaacccccccccccccccccaaaccaaaaaaaaaaacccccccaacccccccccaaaaaacggpppsswwwwwwwwyvvqqqmmmcccccccccc abcaaaaaccccccccaaaaaccccccccccccccccccccccccccccaaaaaaaacccccccaacaaacccccccccccccccccccccaaaaaaaaaccccccccccccccccccccaaaaaagggoossswwwwrrwwwvvqqmmmccccccccccc abcaaaaacccccccaaaaaccccccccccccccccccccccccccccaaaaaaacccccccccaaccccccccccccccccccccccccccaaaaaaacccccccccccaaaccccccccaaaaagggooosssssrrrrwwwvqqmmmcccaacccccc abcccccccccccccaaaaaaccccccccccccccccccccaacccccccccaaaccccccccccccccccccccccccccccccccccccccaaaaaaccccccccccccaaaaccccccaaaccgggooosssssrrrrrwwrrqmmmcccaacccccc abcccccccccccccccaaaacccccccccccccccccccaaaacccccccacaaacccccccccccccccccccccccccccccccccccccaaaaaaacccccccccaaaaaacccccccccccgffoooooosoonrrrrrrrrmmmccaaaaacccc abcccccccccccccccaccccccccccccccccccccccaaaacccccccaaaaacccccccccccccccccccccccccccccccccccccaaacaaacccccccccaaaaacccccccccccccfffoooooooonnnrrrrrmmmddcaaaaacccc abccccccccccccccccccccccccccccccccccccccaaaaccccccccaaaaacccccccccccccccccccccccccaaaccccccccaacccccccccccccccaaaaaccccccccccccffffoooooonnnnnnrnnmmmdddaaaaacccc abcccccccccccccccccccccccccccccccccccccccccccccccccaaaaaacccccccccccccccccaaaaaccaaaacccccccccccccccccccccccccaacccccccccccccccfffffffffeeeennnnnnmmdddaaaacccccc abcccccccaaaccccccccaccccccccccccccccccccccccccccccaaaaccccccccccccaaaccccaaaaaccaaaaccccccccccccccccccccccccccccccccccccccccccccfffffffeeeeennnnnmddddaaaaaccccc abcccaaccaaacccccaaaacccccaacccccccccccccccccccccccccaaacccccccccccaaacccaaaaaacccaaaccccccccccccccccccccccccccccccccccccccccccccccffffeeeeeeeedddddddcccaacccccc abcccaaaaaaacccccaaaaaaccaaacccccccccccccccccccccccccccacccccccccccaaaaccaaaaaaccccccccccccccccccccccccccaacccccccccaaaccccccccccccccaaaaaaeeeeedddddcccccccccccc abcccaaaaaacccccccaaaacccaaacaaaccccaaaacccccccccaaacaaaccccccaacccaaaacaaaaaaacccccccccccccccccccccccccaaaccccccccaaaacccccccccccccccccccaaaaeeddddccccccccccccc abccccaaaaaaaacccaaaaaaaaaaaaaaaccccaaaacccccccccaaaaaaacccccaaacccaaaaaaaaaacccccccccccccccccccccccaaacaaaccccccccaaaaccccccccccccccccccccaaaccccccccccccccaaaca abcccaaaaaaaaacccaacaaaaaaaaaaacccccaaaaccccccccccaaaaaacaaacaaacaaaaaaaaaacccccccccccccccaaacccccccaaaaaaaaaaccccccaaaccccccccccccccccccccaacccccccccccccccaaaaa abcccaaaaaaaacccccccccccaaaaaacccccccaacccccccccccaaaaaaaaaaaaaaaaaaaaaaaaccccccccccccccccaaaacccccccaaaaaaaaacccccccccccccccccccccccccccccaaacccccccccccccccaaaa abccaaaaaaacccccccccccccaaaaaaacccccccccccccccccaaaaaaaaaaaaaaaaaaaaaaaaaaacccccccccccccccaaaacccccccaaaaaaaacccccccccccccccccccccccccccccccccccccccccccccccaaaaa \ No newline at end of file
M src/aoc2022.gleam => src/aoc2022.gleam +3 -3
@@ 1,9 1,9 @@ import gleam/io import aoc2022/day10 import aoc2022/day12 pub fn main() { io.print("Part 1: ") io.debug(day10.part1()) io.debug(day12.part1()) io.print("Part 2: ") io.debug(day10.part2()) io.debug(day12.part2()) }
A src/aoc2022/day12.gleam => src/aoc2022/day12.gleam +176 -0
@@ 0,0 1,176 @@ //// --- Day 12: Hill Climbing Algorithm --- //// https://adventofcode.com/2022/day/12 import aoc2022/utils import gleam/int import gleam/list import gleam/map import gleam/option.{None, Option, Some} import gleam/queue import gleam/result import gleam/string type Pos { Pos(x: Int, y: Int) } type HeightMap = map.Map(Pos, Int) type Visited = map.Map(Pos, Option(Pos)) type Queue = queue.Queue(Pos) type State { State(end: Pos, height_map: HeightMap, queue: Queue, visited: Visited) } pub fn part1() { let #(start, end, height_map) = parse_input() play(start, end, height_map) } pub fn part2() { let #(_start, end, height_map) = parse_input() height_map |> map.filter(fn(_pos, height) { height == 0 }) |> map.keys |> list.map(play(_, end, height_map)) |> list.filter(result.is_ok) |> list.map(utils.assert_ok) |> list.reduce(int.min) } fn play(start, end, height_map) { let visited = map.from_list([#(start, None)]) let queue = queue.from_list([start]) let state = State(end, height_map, queue, visited) do_play(state) } // BFS to find path from start to end // Could be improved by A* but not really required for this one fn do_play(state: State) -> Result(Int, Nil) { case queue.pop_front(state.queue) { Ok(#(current_pos, queue)) -> case current_pos == state.end { True -> { let path = unravel_path(state.visited, current_pos) Ok(list.length(path) - 1) } False -> { let next = next_positions(current_pos, state.height_map, state.visited) let visited = add_visited(state.visited, current_pos, next) let queue = add_queue(queue, next) let state = State(state.end, state.height_map, queue, visited) do_play(state) } } // Queue depleted, no path found Error(Nil) -> Error(Nil) } } fn unravel_path(visited, end_pos) -> List(Pos) { do_unravel_path(visited, end_pos, []) } fn do_unravel_path(visited, pos, path) -> List(Pos) { case utils.assert_ok(map.get(visited, pos)) { Some(prev_pos) -> do_unravel_path(visited, prev_pos, [pos, ..path]) None -> [pos, ..path] } } fn add_visited(visited: Visited, current_pos: Pos, next: List(Pos)) { list.fold( next, visited, fn(visited, next_pos) { map.insert(visited, next_pos, Some(current_pos)) }, ) } fn add_queue(queue: Queue, next: List(Pos)) { list.fold( next, queue, fn(queue, next_pos) { queue.push_back(queue, next_pos) }, ) } fn next_positions(pos, height_map, visited) -> List(Pos) { pos |> neighbours() // Remove out of bounds |> list.filter(map.has_key(height_map, _)) // Remove visited |> list.filter(fn(neighbour) { !map.has_key(visited, neighbour) }) // Remove neighbours too high to climb |> list.filter(fn(neighbour) { assert Ok(pos_height) = map.get(height_map, pos) assert Ok(neighbour_height) = map.get(height_map, neighbour) neighbour_height <= pos_height + 1 }) } fn neighbours(pos: Pos) -> List(Pos) { [ Pos(pos.x + 1, pos.y), Pos(pos.x - 1, pos.y), Pos(pos.x, pos.y + 1), Pos(pos.x, pos.y - 1), ] } // ----------------------------------------------------------------------------- // Input Parsing // ----------------------------------------------------------------------------- fn parse_input() -> #(Pos, Pos, HeightMap) { let char_map = "day12.txt" |> utils.read_input |> parse_to_char_map let start = find_char(char_map, "S") let end = find_char(char_map, "E") let height_map = map.map_values(char_map, fn(_, v) { char_to_height(v) }) #(start, end, height_map) } fn char_to_height(char) { let char = case char { "S" -> "a" "E" -> "z" other -> other } utils.ord(char) - 97 } fn find_char(map, char) -> Pos { assert [#(pos, _)] = map |> map.filter(fn(_, v) { v == char }) |> map.to_list pos } fn parse_to_char_map(input) { input |> parse_to_nested_list |> list.flatten |> map.from_list } fn parse_to_nested_list(input) { let rows = string.split(input, "\n") use y, row <- list.index_map(rows) use x, char <- list.index_map(string.to_graphemes(row)) #(Pos(x, y), char) }
M src/aoc2022/utils.gleam => src/aoc2022/utils.gleam +7 -0