this repo has no description
at master 8.7 kB view raw
1<!-- livebook:{"persist_outputs":true} --> 2 3# Day 14 4 5```elixir 6Mix.install( 7 [ 8 {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}, 9 :image 10 ], 11 consolidate_protocols: false 12) 13 14# defimpl Kino.Render, for: Vix.Vips.Image do 15# alias Vix.Vips.Image, as: VImg 16 17# def to_livebook(image) do 18# format = "png" 19 20# {:ok, image_bin} = VImg.write_to_buffer(image, ".#{format}") 21# Kino.Output.image(image_bin, "image/#{format}") 22# end 23# end 24``` 25 26<!-- livebook:{"output":true} --> 27 28``` 29:ok 30``` 31 32## Setup 33 34<!-- livebook:{"attrs":{"day":"14","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 35 36```elixir 37{:ok, puzzle_input} = 38 KinoAOC.download_puzzle("2022", "14", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 39``` 40 41<!-- livebook:{"output":true} --> 42 43``` 44{:ok, 45 "492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n481,92 -> 481,96 -> 476,96 -> 476,99 -> 487,99 -> 487,96 -> 485,96 -> 485,92\n460,73 -> 460,70 -> 460,73 -> 462,73 -> 462,69 -> 462,73 -> 464,73 -> 464,65 -> 464,73 -> 466,73 -> 466,65 -> 466,73 -> 468,73 -> 468,64 -> 468,73 -> 470,73 -> 470,68 -> 470,73 -> 472,73 -> 472,68 -> 472,73\n470,76 -> 470,80 -> 466,80 -> 466,84 -> 481,84 -> 481,80 -> 474,80 -> 474,76\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n495,155 -> 499,155\n460,73 -> 460,70 -> 460,73 -> 462,73 -> 462,69 -> 462,73 -> 464,73 -> 464,65 -> 464,73 -> 466,73 -> 466,65 -> 466,73 -> 468,73 -> 468,64 -> 468,73 -> 470,73 -> 470,68 -> 470,73 -> 472,73 -> 472,68 -> 472,73\n500,138 -> 505,138\n484,39 -> 484,38 -> 484,39 -> 486,39 -> 486,33 -> 486,39 -> 488,39 -> 488,30 -> 488,39 -> 490,39 -> 490,35 -> 490,39 -> 492,39 -> 492,38 -> 492,39 -> 494,39 -> 494,30 -> 494,39 -> 496,39 -> 496,36 -> 496,39\n481,92 -> 481,96 -> 476,96 -> 476,99 -> 487,99 -> 487,96 -> 485,96 -> 485,92\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n460,73 -> 460,70 -> 460,73 -> 462,73 -> 462,69 -> 462,73 -> 464,73 -> 464,65 -> 464,73 -> 466,73 -> 466,65 -> 466,73 -> 468,73 -> 468,64 -> 468,73 -> 470,73 -> 470,68 -> 470,73 -> 472,73 -> 472,68 -> 472,73\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n460,73 -> 460,70 -> 460,73 -> 462,73 -> 462,69 -> 462,73 -> 464,73 -> 464,65 -> 464,73 -> 466,73 -> 466,65 -> 466,73 -> 468,73 -> 468,64 -> 468,73 -> 470,73 -> 470,68 -> 470,73 -> 472,73 -> 472,68 -> 472,73\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n489,115 -> 489,119 -> 481,119 -> 481,126 -> 494,126 -> 494,119 -> 493,119 -> 493,115\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n485,112 -> 485,102 -> 485,112 -> 487,112 -> 487,111 -> 487,112 -> 489,112 -> 489,105 -> 489,112\n481,92 -> 481,96 -> 476,96 -> 476,99 -> 487,99 -> 487,96 -> 485,96 -> 485,92\n484,39 -> 484,38 -> 484,39 -> 486,39 -> 486,33 -> 486,39 -> 488,39 -> 488,30 -> 488,39 -> 490,39 -> 490,35 -> 490,39 -> 492,39 -> 492,38 -> 492,39 -> 494,39 -> 494,30 -> 494,39 -> 496,39 -> 496,36 -> 496,39\n470,49 -> 470,53 -> 468,53 -> 468,60 -> 477,60 -> 477,53 -> 476,53 -> 476,49\n483,160 -> 487,160\n492,26 -> 492,17 -> 492,26 -> 494,26 -> 494,16 -> 494,26 -> 496,26 -> 496,22 -> 496,26 -> 498,26 -> 498,17 -> 498,26 -> 500,26 -> 500,20 -> 500,26 -> 502,26 -> 502,25 -> 502,26 -> 504,26 -> 504,23 -> 504,26 -> 506,26 -> 506,21 -> 506,26 -> 508,26 -> 508,16 -> 508,26 -> 510,26 -> 510,24 -> 510,26\n460,73 -> 460,70 -> 460,73 -> 462,73 -> 462,69 -> 462,73 -> 464,73 -> 464,65 -> 464,73 -> 466,73 -> 466,65 -> 466,73 -> 468,73 -> 468,64 -> 468,73 -> 47" <> ...} 46``` 47 48```elixir 49defmodule Cave do 50 defstruct map: %{}, width: nil, height: 0, start: {500, 0} 51 52 def parse(input, start \\ {500, 0}) do 53 map = 54 input 55 |> String.split("\n", trim: true) 56 |> Enum.map(&Cave.parse_line/1) 57 |> Enum.reduce(&Map.merge/2) 58 59 {width, height} = 60 for {{x, y}, _} <- map, 61 reduce: {nil, nil} do 62 {nil, nil} -> 63 {x..x, y} 64 65 {min_x..max_x, max_y} -> 66 {min(min_x, x)..max(max_x, x), max(max_y, y)} 67 end 68 69 %__MODULE__{map: map, start: start, width: width, height: height} 70 end 71 72 def parse_point(str) do 73 [x, y] = String.split(str, ",") 74 75 {String.to_integer(x), String.to_integer(y)} 76 end 77 78 def parse_line(line) do 79 points = 80 line 81 |> String.split(" -> ") 82 |> Enum.map(&parse_point/1) 83 |> Enum.chunk_every(2, 1, :discard) 84 |> Enum.flat_map(fn 85 [{x, y1}, {x, y2}] -> 86 for y <- y1..y2, do: {x, y} 87 88 [{x1, y}, {x2, y}] -> 89 for x <- x1..x2, do: {x, y} 90 end) 91 |> Map.new(&{&1, :rock}) 92 93 points 94 end 95 96 def drop_sand(%__MODULE__{} = cave), do: drop_sand(cave, cave.start) 97 98 def drop_sand(%__MODULE__{height: h} = cave, {_, sy} = p) 99 when sy >= h, 100 do: {p, struct(cave, map: Map.put(cave.map, p, :sand))} 101 102 def drop_sand(%__MODULE__{map: map} = cave, {sx, sy} = p) do 103 cond do 104 not Map.has_key?(map, {sx, sy + 1}) -> drop_sand(cave, {sx, sy + 1}) 105 not Map.has_key?(map, {sx - 1, sy + 1}) -> drop_sand(cave, {sx - 1, sy + 1}) 106 not Map.has_key?(map, {sx + 1, sy + 1}) -> drop_sand(cave, {sx + 1, sy + 1}) 107 true -> {p, struct(cave, map: Map.put(cave.map, p, :sand))} 108 end 109 end 110 111 def to_image(%__MODULE__{} = cave) do 112 {{{x0, _}, _}, {{x1, _}, _}} = Enum.min_max_by(cave.map, fn {{x, _}, _} -> x end) 113 {sx, sy} = cave.start 114 image = Image.new!(x1 - x0 + 3, cave.height + 3) 115 116 {:ok, image} = 117 Image.mutate(image, fn im -> 118 Image.Draw.point(im, sx - x0 + 1, sy + 1, color: :red) 119 120 cave.map 121 |> Enum.sort() 122 |> Enum.each(fn {{x, y}, type} -> 123 case type do 124 :rock -> Image.Draw.point(im, x - x0 + 1, y + 1, color: :white) 125 :sand -> Image.Draw.point(im, x - x0 + 1, y + 1, color: :tan) 126 end 127 end) 128 129 :ok 130 end) 131 132 image 133 end 134end 135 136defimpl Kino.Render, for: Cave do 137 def to_livebook(%@for{} = cave) do 138 cave 139 |> @for.to_image() 140 |> Image.resize!(4, interpolate: :nearest) 141 |> Kino.Render.to_livebook() 142 end 143end 144``` 145 146<!-- livebook:{"output":true} --> 147 148``` 149{:module, Kino.Render.Cave, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:to_livebook, 1}} 150``` 151 152```elixir 153cave = Cave.parse(puzzle_input) 154 155floor = cave.height + 1 156 157cave = struct(cave, height: floor) 158``` 159 160## Task 1 161 162```elixir 163frame = Kino.Frame.new() |> Kino.render() 164 165image = Cave.to_image(cave) 166 167cave 168|> Stream.unfold(fn cave -> 169 {_, new_cave} = ret = Cave.drop_sand(cave) 170 171 {ret, new_cave} 172end) 173|> Enum.reduce_while(0, fn {{_x, y}, cave}, acc -> 174 if y < cave.height do 175 {:cont, acc + 1} 176 else 177 Kino.Frame.render(frame, Image.resize!(Cave.to_image(cave), 4, interpolate: :nearest)) 178 {:halt, acc} 179 end 180end) 181``` 182 183<!-- livebook:{"output":true} --> 184 185``` 186768 187``` 188 189## Task 2 190 191```elixir 192{grains, pyramid} = 193 Stream.unfold(cave, fn cave -> 194 {_, new_cave} = ret = Cave.drop_sand(cave) 195 196 {ret, new_cave} 197 end) 198 |> Enum.reduce_while(0, fn {p, cave}, acc -> 199 if p != {500, 0} do 200 {:cont, acc + 1} 201 else 202 {:halt, {acc + 1, cave}} 203 end 204 end) 205 206grains 207``` 208 209<!-- livebook:{"output":true} --> 210 211``` 21226686 213``` 214 215```elixir 216Kino.render(pyramid) 217 218:ok 219``` 220 221<!-- livebook:{"output":true} --> 222 223``` 224:ok 225```