advent_of_code_2022

My (attempted) solutions to the 2022 Advent of Code
git clone https://git.eamoncaddigan.net/advent_of_code_2022.git
Log | Files | Refs | README

day_14.jl (3567B)


      1 #!/usr/bin/env julia
      2 # https://adventofcode.com/2022/day/14
      3 using AdventOfCode
      4 
      5 example = readlines(IOBuffer("""
      6 	498,4 -> 498,6 -> 496,6
      7 	503,4 -> 502,4 -> 502,9 -> 494,9"""))
      8 input = readlines("data/day_14.txt")
      9 
     10 module Maps
     11     # Let's see if we can solve this by just making a Set of filled blocks.
     12     # Could be too slow or memory hungry, IDK.
     13     struct MapState
     14        filled_blocks::Set{Tuple{Int,Int}}
     15        lowest_row::Int
     16        has_floor::Bool
     17     end
     18 
     19     function MapState(input::Vector{<:AbstractString},
     20                       add_floor = false)
     21         filled_blocks = Set{Tuple{Int,Int}}()
     22         lowest_row = -Inf
     23         for path = input
     24             lines = map(x -> parse.(Int, split(x, ",")), split(path, " -> "))
     25             for i = 2:length(lines)
     26                 xline = range(minmax(lines[i-1][1], lines[i][1])...,
     27                               step = 1)
     28                 yline = range(minmax(lines[i-1][2], lines[i][2])...,
     29                               step = 1)
     30                 for x = xline, y = yline
     31                     push!(filled_blocks, (x, y))
     32                     lowest_row = max(lowest_row, y)
     33                 end
     34             end
     35         end
     36         MapState(filled_blocks, lowest_row, add_floor)
     37     end
     38 
     39     # I'm going to try to keep these function signatures implementation-neutral
     40     # in case I need to change my approach. Ideally I can leave the basic
     41     # sand-filling algorithm alone and only change the underlying
     42     # datastructures and methods (if necessary).
     43     """
     44     Return true IFF sand at the given coordinate is destined to fall forever.
     45     """
     46     function isfallingforever(mapstate::MapState, coord::Tuple{Int,Int})
     47         !mapstate.has_floor && coord[2] > mapstate.lowest_row
     48     end
     49 
     50     """
     51     Return true IFF the given coordinate is filled with sand or stone.
     52     """
     53     function isfilled(mapstate::MapState, coord::Tuple{Int,Int})
     54         (mapstate.has_floor && coord[2] >= mapstate.lowest_row + 2) ||
     55             coord in mapstate.filled_blocks
     56     end
     57 
     58     """
     59     Fill the given block with sand.
     60     """
     61     function fillblock!(mapstate::MapState, coord::Tuple{Int,Int})
     62         push!(mapstate.filled_blocks, coord)
     63     end
     64 
     65     """
     66     Drop a block from (500, 0) until it comes to rest or falls forever.
     67 
     68     Returns true if the block comes to rest and false if it falls forever or
     69     the map is "full". Updates mapstate.
     70     """
     71     function dropblock!(mapstate::MapState)
     72         coord = (500, 0)
     73         while !isfallingforever(mapstate, coord) && !isfilled(mapstate, coord)
     74             if !isfilled(mapstate, coord .+ (0, 1))
     75                 coord = coord .+ (0, 1)
     76             elseif !isfilled(mapstate, coord .+ (-1, 1))
     77                 coord = coord .+ (-1, 1)
     78             elseif !isfilled(mapstate, coord .+ (1, 1))
     79                 coord = coord .+ (1, 1)
     80             else
     81                 fillblock!(mapstate, coord)
     82                 return true
     83             end
     84         end
     85         return false
     86     end
     87 
     88     """
     89     Fill the map with sand until all sand will fall forever or the source is filled.
     90 
     91     Return the number of blocks that came to rest
     92     """
     93     function fillmap!(mapstate::MapState)
     94         blocks_at_rest = 0
     95         while dropblock!(mapstate)
     96             blocks_at_rest += 1
     97         end
     98         blocks_at_rest
     99     end
    100 end
    101 
    102 function part_1(input)
    103     Maps.fillmap!(Maps.MapState(input))
    104 end
    105 @assert part_1(example) == 24
    106 @info part_1(input)
    107 
    108 function part_2(input)
    109     Maps.fillmap!(Maps.MapState(input, true))
    110 end
    111 @assert part_2(example) == 93
    112 @info part_2(input)