this repo has no description

Update year 2022

hauleth.dev ef17f468 4d54275b

verified
+2 -8
2022/day01.livemd
··· 4 4 5 5 ```elixir 6 6 Mix.install([ 7 - {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 7 + {:kino_aoc, ">= 0.0.0"} 8 8 ]) 9 9 ``` 10 10 11 - <!-- livebook:{"output":true} --> 12 - 13 - ``` 14 - :ok 15 - ``` 16 - 17 11 ## Setup 18 12 19 - <!-- livebook:{"attrs":{"day":"1","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 13 + <!-- livebook:{"attrs":{"day":"1","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 14 21 15 ```elixir 22 16 {:ok, puzzle_input} =
+1 -1
2022/day06.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"6","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"6","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day07.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"7","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"7","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day08.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"8","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"8","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day09.livemd
··· 16 16 17 17 ## Setup 18 18 19 - <!-- livebook:{"attrs":{"day":"9","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"9","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day10.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"10","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"10","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day11.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"11","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"11","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+1 -1
2022/day12.livemd
··· 17 17 18 18 ## Section 19 19 20 - <!-- livebook:{"attrs":{"day":"12","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 + <!-- livebook:{"attrs":{"day":"12","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 21 21 22 22 ```elixir 23 23 {:ok, puzzle_input} =
+1 -1
2022/day13.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"13","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"13","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} =
+92 -56
2022/day14.livemd
··· 10 10 ], 11 11 consolidate_protocols: false 12 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 13 24 ``` 14 25 15 26 <!-- livebook:{"output":true} --> ··· 20 31 21 32 ## Setup 22 33 23 - <!-- livebook:{"attrs":{"day":"14","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 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"} --> 24 35 25 36 ```elixir 26 37 {:ok, puzzle_input} = ··· 36 47 37 48 ```elixir 38 49 defmodule Cave do 39 - defstruct map: MapSet.new(), occupied: MapSet.new(), width: nil, height: 0, start: {500, 0} 50 + defstruct map: %{}, width: nil, height: 0, start: {500, 0} 40 51 41 52 def parse(input, start \\ {500, 0}) do 42 53 map = 43 54 input 44 55 |> String.split("\n", trim: true) 45 56 |> Enum.map(&Cave.parse_line/1) 46 - |> Enum.reduce(&MapSet.union/2) 57 + |> Enum.reduce(&Map.merge/2) 47 58 48 59 {width, height} = 49 - for {x, y} <- map, 60 + for {{x, y}, _} <- map, 50 61 reduce: {nil, nil} do 51 62 {nil, nil} -> 52 63 {x..x, y} ··· 55 66 {min(min_x, x)..max(max_x, x), max(max_y, y)} 56 67 end 57 68 58 - %__MODULE__{map: map, occupied: map, start: start, width: width, height: height} 59 - end 60 - 61 - def add_line(%__MODULE__{} = cave, line) do 62 - {width, height} = 63 - Enum.reduce(line, {cave.width, cave.height}, fn {x, y}, {x0..x1, h} -> 64 - {min(x, x0)..max(x, x1), max(y, h)} 65 - end) 66 - 67 - struct(cave, 68 - width: width, 69 - height: height, 70 - map: MapSet.union(cave.map, line), 71 - occupied: MapSet.union(cave.occupied, line) 72 - ) 69 + %__MODULE__{map: map, start: start, width: width, height: height} 73 70 end 74 71 75 72 def parse_point(str) do ··· 91 88 [{x1, y}, {x2, y}] -> 92 89 for x <- x1..x2, do: {x, y} 93 90 end) 94 - |> MapSet.new() 91 + |> Map.new(&{&1, :rock}) 95 92 96 93 points 97 94 end 98 95 99 96 def drop_sand(%__MODULE__{} = cave), do: drop_sand(cave, cave.start) 100 97 101 - def drop_sand(%__MODULE__{height: h, width: x0..x1} = cave, {sx, sy}) 102 - when sx not in x0..x1 or sy >= h, 103 - do: {:fall_out, cave} 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))} 104 101 105 - def drop_sand(%__MODULE__{} = cave, {sx, sy}) do 102 + def drop_sand(%__MODULE__{map: map} = cave, {sx, sy} = p) do 106 103 cond do 107 - {sx, sy + 1} not in cave.occupied -> drop_sand(cave, {sx, sy + 1}) 108 - {sx - 1, sy + 1} not in cave.occupied -> drop_sand(cave, {sx - 1, sy + 1}) 109 - {sx + 1, sy + 1} not in cave.occupied -> drop_sand(cave, {sx + 1, sy + 1}) 110 - true -> {{sx, sy}, struct(cave, occupied: MapSet.put(cave.occupied, {sx, sy}))} 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))} 111 108 end 112 109 end 113 - end 114 110 115 - defimpl Kino.Render, for: Cave do 116 - def to_livebook(%@for{} = cave) do 117 - x0..x1 = cave.width 111 + def to_image(%__MODULE__{} = cave) do 112 + {{{x0, _}, _}, {{x1, _}, _}} = Enum.min_max_by(cave.map, fn {{x, _}, _} -> x end) 118 113 {sx, sy} = cave.start 119 114 image = Image.new!(x1 - x0 + 3, cave.height + 3) 120 115 ··· 122 117 Image.mutate(image, fn im -> 123 118 Image.Draw.point(im, sx - x0 + 1, sy + 1, color: :red) 124 119 125 - for {x, y} <- cave.occupied do 126 - Image.Draw.point(im, x - x0 + 1, y + 1, color: :tan) 127 - end 128 - 129 - for {x, y} <- cave.map do 130 - Image.Draw.point(im, x - x0 + 1, y + 1, color: :white) 131 - end 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) 132 128 133 129 :ok 134 130 end) 135 131 136 - buf = 137 - image 138 - |> Image.resize!(4, interpolate: :nearest) 139 - |> Image.write!(:memory, suffix: ".png") 132 + image 133 + end 134 + end 140 135 141 - Kino.Output.image(buf, "image/png") 136 + defimpl 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 142 end 143 143 end 144 144 ``` ··· 146 146 <!-- livebook:{"output":true} --> 147 147 148 148 ``` 149 - {:module, Kino.Render.Cave, <<70, 79, 82, 49, 0, 0, 16, ...>>, {:to_livebook, 1}} 149 + {:module, Kino.Render.Cave, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:to_livebook, 1}} 150 150 ``` 151 151 152 152 ```elixir 153 153 cave = Cave.parse(puzzle_input) 154 + 155 + floor = cave.height + 1 156 + 157 + cave = struct(cave, height: floor) 154 158 ``` 155 159 156 160 ## Task 1 157 161 158 162 ```elixir 159 - Stream.unfold(cave, &Cave.drop_sand/1) 160 - |> Enum.take_while(&(&1 != :fall_out)) 161 - |> length() 163 + frame = Kino.Frame.new() |> Kino.render() 164 + 165 + image = Cave.to_image(cave) 166 + 167 + cave 168 + |> Stream.unfold(fn cave -> 169 + {_, new_cave} = ret = Cave.drop_sand(cave) 170 + 171 + {ret, new_cave} 172 + end) 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 180 + end) 162 181 ``` 163 182 164 183 <!-- livebook:{"output":true} --> ··· 170 189 ## Task 2 171 190 172 191 ```elixir 173 - floor_y = cave.height + 2 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 + 206 + grains 207 + ``` 174 208 175 - floor = for x <- 0..(cave.width.last * 2), into: MapSet.new(), do: {x, floor_y} 209 + <!-- livebook:{"output":true} --> 176 210 177 - cave = Cave.add_line(cave, floor) 211 + ``` 212 + 26686 213 + ``` 178 214 179 - Stream.unfold(cave, &Cave.drop_sand/1) 180 - |> Enum.take_while(&(&1 != cave.start)) 181 - |> length() 182 - |> then(&(&1 + 1)) 215 + ```elixir 216 + Kino.render(pyramid) 217 + 218 + :ok 183 219 ``` 184 220 185 221 <!-- livebook:{"output":true} --> 186 222 187 223 ``` 188 - 26686 224 + :ok 189 225 ```
+25 -5
2022/day15.livemd
··· 16 16 17 17 ## Section 18 18 19 - <!-- livebook:{"attrs":{"day":"15","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 19 + <!-- livebook:{"attrs":{"day":"15","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 20 21 21 ```elixir 22 22 {:ok, puzzle_input} = ··· 108 108 a 109 109 end 110 110 111 + def continuous?(%__MODULE__{ranges: []}), do: true 112 + def continuous?(%__MODULE__{ranges: [_]}), do: true 113 + def continuous?(%__MODULE__{ranges: _}), do: false 114 + 115 + def gaps(%__MODULE__{ranges: []} = set), do: set 116 + def gaps(%__MODULE__{ranges: [_]}), do: %__MODULE__{ranges: []} 117 + 111 118 def gaps(%__MODULE__{ranges: ranges}) do 112 119 gaps = 113 120 ranges ··· 199 206 <!-- livebook:{"output":true} --> 200 207 201 208 ``` 202 - {:module, RangeSet, <<70, 79, 82, 49, 0, 0, 37, ...>>, {:squash, 1}} 209 + {:module, RangeSet, <<70, 79, 82, 49, 0, 0, 39, ...>>, {:squash, 1}} 203 210 ``` 204 211 205 212 ```elixir ··· 272 279 273 280 circles 274 281 |> Beacons.covered_at_line(a_y) 282 + |> IO.inspect() 275 283 |> RangeSet.remove(beacons_at_line) 276 284 |> RangeSet.length() 277 285 ``` ··· 279 287 <!-- livebook:{"output":true} --> 280 288 281 289 ``` 290 + %RangeSet{ranges: [-101830..5006266]} 291 + ``` 292 + 293 + <!-- livebook:{"output":true} --> 294 + 295 + ``` 282 296 5108096 283 297 ``` 284 298 ··· 293 307 |> Enum.find_value(fn y -> 294 308 covered = Beacons.covered_at_line(circles, y) 295 309 296 - gaps = RangeSet.gaps(covered) 297 - 298 - if not RangeSet.empty?(gaps) do 310 + if not RangeSet.continuous?(covered) do 311 + gaps = RangeSet.gaps(covered) 299 312 {y, RangeSet.to_list(gaps)} 300 313 end 301 314 end) 315 + |> Kino.render() 302 316 303 317 x * 4_000_000 + y 318 + ``` 319 + 320 + <!-- livebook:{"output":true} --> 321 + 322 + ``` 323 + {2650264, [2638485]} 304 324 ``` 305 325 306 326 <!-- livebook:{"output":true} -->
+985
2022/day16.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 16 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}, 8 + {:libgraph, github: "hauleth/libgraph", ref: "perf/bellman-ford-implementation"} 9 + ]) 10 + ``` 11 + 12 + <!-- livebook:{"output":true} --> 13 + 14 + ``` 15 + :ok 16 + ``` 17 + 18 + ## Setup 19 + 20 + <!-- livebook:{"attrs":{"day":"16","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 21 + 22 + ```elixir 23 + {:ok, puzzle_input} = 24 + KinoAOC.download_puzzle("2022", "16", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 25 + ``` 26 + 27 + <!-- livebook:{"output":true} --> 28 + 29 + ``` 30 + {:ok, 31 + "Valve QJ has flow rate=11; tunnels lead to valves HB, GL\nValve VZ has flow rate=10; tunnel leads to valve NE\nValve TX has flow rate=19; tunnels lead to valves MG, OQ, HM\nValve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR\nValve IH has flow rate=0; tunnels lead to valves YB, QS\nValve QS has flow rate=22; tunnel leads to valve IH\nValve QB has flow rate=0; tunnels lead to valves QX, ES\nValve NX has flow rate=0; tunnels lead to valves UH, OP\nValve PJ has flow rate=0; tunnels lead to valves OC, UH\nValve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD\nValve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ\nValve UC has flow rate=0; tunnels lead to valves AA, BY\nValve QX has flow rate=0; tunnels lead to valves AA, QB\nValve IZ has flow rate=0; tunnels lead to valves OC, SX\nValve AG has flow rate=13; tunnels lead to valves NW, GL, SM\nValve ON has flow rate=0; tunnels lead to valves MO, ZI\nValve XT has flow rate=18; tunnels lead to valves QZ, PG\nValve AX has flow rate=0; tunnels lead to valves UH, MO\nValve JD has flow rate=0; tunnels lead to valves OR, SM\nValve HM has flow rate=0; tunnels lead to valves TX, QH\nValve LF has flow rate=0; tunnels lead to valves ZI, UH\nValve QH has flow rate=0; tunnels lead to valves OR, HM\nValve RT has flow rate=21; tunnel leads to valve PG\nValve NE has flow rate=0; tunnels lead to valves VZ, TA\nValve OQ has flow rate=0; tunnels lead to valves TX, GE\nValve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH\nValve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF\nValve GE has flow rate=0; tunnels lead to valves YB, OQ\nValve EH has flow rate=0; tunnels lead to valves AA, MO\nValve MG has flow rate=0; tunnels lead to valves TX, NW\nValve YB has flow rate=20; tunnels lead to valves IH, GE, XG\nValve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB\nValve JR has flow rate=0; tunnels lead to valves ZI, OC\nValve GL has flow rate=0; tunnels lead to valves AG, QJ\nValve SM has flow rate=0; tunnels lead to valves JD, AG\nValve HB has flow rate=0; tunnels lead to valves OR, QJ\nValve TA has flow rate=0; tunnels lead to valves OC, NE\nValve PG has flow rate=0; tunnels lead to valves RT, XT\nValve XG has flow rate=0; tunnels lead to valves CB, YB\nValve ES has flow rate=9; tunnels lead to valves QB, FL\nValve BH has flow rate=0; tunnels lead to valves RU, OR\nValve FL has flow rate=0; tunnels lead to valves SX, ES\nValve CB has flow rate=0; tunnels lead to valves MO, XG\nValve QZ has flow rate=0; tunnels lead to valves AA, XT\nValve BY has flow rate=0; tunnels lead to valves UC, ZI\nValve ZH has flow rate=0; tunnels lead to valves MO, OC\nValve OP has flow rate=0; tunnels lead to valves NX, AA\nValve NW has flow rate=0; tunnels lead to valves MG, AG\nValve RU has flow rate=0; tunnels lead to valves ZI, BH\nValve SX has flow rate=16; tunnels lead to valves IZ, FL"} 32 + ``` 33 + 34 + ```elixir 35 + # puzzle_input = """ 36 + # Valve AA has flow rate=0; tunnels lead to valves DD, II, BB 37 + # Valve BB has flow rate=13; tunnels lead to valves CC, AA 38 + # Valve CC has flow rate=2; tunnels lead to valves DD, BB 39 + # Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE 40 + # Valve EE has flow rate=3; tunnels lead to valves FF, DD 41 + # Valve FF has flow rate=0; tunnels lead to valves EE, GG 42 + # Valve GG has flow rate=0; tunnels lead to valves FF, HH 43 + # Valve HH has flow rate=22; tunnel leads to valve GG 44 + # Valve II has flow rate=0; tunnels lead to valves AA, JJ 45 + # Valve JJ has flow rate=21; tunnel leads to valve II 46 + # """ 47 + ``` 48 + 49 + <!-- livebook:{"output":true} --> 50 + 51 + ``` 52 + nil 53 + ``` 54 + 55 + ```elixir 56 + {{start, _}, valves} = 57 + valves = 58 + puzzle_input 59 + |> String.split("\n", trim: true) 60 + |> Kino.render() 61 + |> Enum.map(fn line -> 62 + %{ 63 + "name" => name, 64 + "rate" => rate, 65 + "routes" => routes 66 + } = 67 + Regex.named_captures( 68 + ~r/Valve (?<name>..).*rate=(?<rate>\d+);.*valves? (?<routes>.*)$/, 69 + line 70 + ) 71 + 72 + {name, %{rate: String.to_integer(rate), routes: String.split(routes, ~r/,\s*/, trim: true)}} 73 + end) 74 + |> then(&{hd(&1), Map.new(&1)}) 75 + ``` 76 + 77 + <!-- livebook:{"output":true} --> 78 + 79 + ``` 80 + ["Valve QJ has flow rate=11; tunnels lead to valves HB, GL", 81 + "Valve VZ has flow rate=10; tunnel leads to valve NE", 82 + "Valve TX has flow rate=19; tunnels lead to valves MG, OQ, HM", 83 + "Valve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR", 84 + "Valve IH has flow rate=0; tunnels lead to valves YB, QS", 85 + "Valve QS has flow rate=22; tunnel leads to valve IH", 86 + "Valve QB has flow rate=0; tunnels lead to valves QX, ES", 87 + "Valve NX has flow rate=0; tunnels lead to valves UH, OP", 88 + "Valve PJ has flow rate=0; tunnels lead to valves OC, UH", 89 + "Valve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD", 90 + "Valve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ", 91 + "Valve UC has flow rate=0; tunnels lead to valves AA, BY", 92 + "Valve QX has flow rate=0; tunnels lead to valves AA, QB", 93 + "Valve IZ has flow rate=0; tunnels lead to valves OC, SX", 94 + "Valve AG has flow rate=13; tunnels lead to valves NW, GL, SM", 95 + "Valve ON has flow rate=0; tunnels lead to valves MO, ZI", 96 + "Valve XT has flow rate=18; tunnels lead to valves QZ, PG", 97 + "Valve AX has flow rate=0; tunnels lead to valves UH, MO", 98 + "Valve JD has flow rate=0; tunnels lead to valves OR, SM", 99 + "Valve HM has flow rate=0; tunnels lead to valves TX, QH", 100 + "Valve LF has flow rate=0; tunnels lead to valves ZI, UH", 101 + "Valve QH has flow rate=0; tunnels lead to valves OR, HM", 102 + "Valve RT has flow rate=21; tunnel leads to valve PG", 103 + "Valve NE has flow rate=0; tunnels lead to valves VZ, TA", 104 + "Valve OQ has flow rate=0; tunnels lead to valves TX, GE", 105 + "Valve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH", 106 + "Valve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF", 107 + "Valve GE has flow rate=0; tunnels lead to valves YB, OQ", 108 + "Valve EH has flow rate=0; tunnels lead to valves AA, MO", 109 + "Valve MG has flow rate=0; tunnels lead to valves TX, NW", 110 + "Valve YB has flow rate=20; tunnels lead to valves IH, GE, XG", 111 + "Valve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB", 112 + "Valve JR has flow rate=0; tunnels lead to valves ZI, OC", 113 + "Valve GL has flow rate=0; tunnels lead to valves AG, QJ", 114 + "Valve SM has flow rate=0; tunnels lead to valves JD, AG", 115 + "Valve HB has flow rate=0; tunnels lead to valves OR, QJ", 116 + "Valve TA has flow rate=0; tunnels lead to valves OC, NE", 117 + "Valve PG has flow rate=0; tunnels lead to valves RT, XT", 118 + "Valve XG has flow rate=0; tunnels lead to valves CB, YB", 119 + "Valve ES has flow rate=9; tunnels lead to valves QB, FL", 120 + "Valve BH has flow rate=0; tunnels lead to valves RU, OR", 121 + "Valve FL has flow rate=0; tunnels lead to valves SX, ES", 122 + "Valve CB has flow rate=0; tunnels lead to valves MO, XG", 123 + "Valve QZ has flow rate=0; tunnels lead to valves AA, XT", 124 + "Valve BY has flow rate=0; tunnels lead to valves UC, ZI", 125 + "Valve ZH has flow rate=0; tunnels lead to valves MO, OC", 126 + "Valve OP has flow rate=0; tunnels lead to valves NX, AA", 127 + "Valve NW has flow rate=0; tunnels lead to valves MG, AG", 128 + "Valve RU has flow rate=0; tunnels lead to valves ZI, BH", 129 + "Valve SX has flow rate=16; tunnels lead to valves IZ, FL"] 130 + ``` 131 + 132 + <!-- livebook:{"output":true} --> 133 + 134 + ``` 135 + {{"QJ", %{rate: 11, routes: ["HB", "GL"]}}, 136 + %{ 137 + "CB" => %{rate: 0, routes: ["MO", "XG"]}, 138 + "EH" => %{rate: 0, routes: ["AA", "MO"]}, 139 + "YB" => %{rate: 20, routes: ["IH", "GE", "XG"]}, 140 + "ON" => %{rate: 0, routes: ["MO", "ZI"]}, 141 + "ES" => %{rate: 9, routes: ["QB", "FL"]}, 142 + "XG" => %{rate: 0, routes: ["CB", "YB"]}, 143 + "TX" => %{rate: 19, routes: ["MG", "OQ", "HM"]}, 144 + "RT" => %{rate: 21, routes: ["PG"]}, 145 + "GL" => %{rate: 0, routes: ["AG", "QJ"]}, 146 + "XT" => %{rate: 18, routes: ["QZ", "PG"]}, 147 + "BY" => %{rate: 0, routes: ["UC", "ZI"]}, 148 + "QJ" => %{rate: 11, routes: ["HB", "GL"]}, 149 + "QB" => %{rate: 0, routes: ["QX", "ES"]}, 150 + "QH" => %{rate: 0, routes: ["OR", "HM"]}, 151 + "SX" => %{rate: 16, routes: ["IZ", "FL"]}, 152 + "ZI" => %{rate: 5, routes: ["BY", "ON", "RU", "LF", "JR"]}, 153 + "OC" => %{rate: 7, routes: ["IZ", "JR", "TA", "ZH", "PJ"]}, 154 + "NW" => %{rate: 0, routes: ["MG", "AG"]}, 155 + "UH" => %{rate: 17, routes: ["PJ", "NX", "AX", "LF"]}, 156 + "VZ" => %{rate: 10, routes: ["NE"]}, 157 + "MO" => %{rate: 15, routes: ["EH", "ON", "AX", "ZH", "CB"]}, 158 + "ZH" => %{rate: 0, routes: ["MO", "OC"]}, 159 + "RU" => %{rate: 0, routes: ["ZI", "BH"]}, 160 + "FL" => %{rate: 0, routes: ["SX", "ES"]}, 161 + "SM" => %{rate: 0, routes: ["JD", "AG"]}, 162 + "AA" => %{rate: 0, routes: ["QZ", "UC", "OP", "QX", "EH"]}, 163 + "JR" => %{rate: 0, routes: ["ZI", "OC"]}, 164 + "QS" => %{rate: 22, routes: ["IH"]}, 165 + "AG" => %{rate: 13, routes: ["NW", "GL", "SM"]}, 166 + "JD" => %{rate: 0, routes: ["OR", "SM"]}, 167 + "QZ" => %{rate: 0, routes: ["AA", "XT"]}, 168 + "MG" => %{rate: 0, routes: ["TX", "NW"]}, 169 + "UC" => %{rate: 0, routes: ["AA", "BY"]}, 170 + "AX" => %{rate: 0, routes: ["UH", "MO"]}, 171 + "HM" => %{rate: 0, routes: ["TX", "QH"]}, 172 + "LF" => %{rate: 0, routes: ["ZI", "UH"]}, 173 + "BH" => %{rate: 0, routes: ["RU", "OR"]}, 174 + "OR" => %{rate: 6, routes: ["QH", "BH", "HB", "JD"]}, 175 + "GE" => %{rate: 0, routes: ["YB", "OQ"]}, 176 + "QX" => %{rate: 0, routes: ["AA", "QB"]}, 177 + "IZ" => %{rate: 0, routes: ["OC", "SX"]}, 178 + "PG" => %{rate: 0, routes: ["RT", "XT"]}, 179 + "NX" => %{rate: 0, routes: ["UH", "OP"]}, 180 + "OP" => %{rate: 0, routes: ["NX", "AA"]}, 181 + "TA" => %{rate: 0, routes: ["OC", ...]}, 182 + "IH" => %{rate: 0, routes: [...]}, 183 + "HB" => %{rate: 0, ...}, 184 + "PJ" => %{...}, 185 + ... 186 + }} 187 + ``` 188 + 189 + ```elixir 190 + graph = Graph.new(type: :directed) 191 + 192 + edges = 193 + Enum.flat_map(valves, fn {a, %{routes: routes}} -> 194 + for b <- routes, p <- [{a, b, weight: 1}, {b, a, weight: 1}], do: p 195 + end) 196 + 197 + graph = 198 + Graph.add_edges(graph, edges) 199 + |> Kino.render() 200 + 201 + paths = 202 + for v <- Graph.vertices(graph), into: %{} do 203 + routes = 204 + graph 205 + |> Graph.bellman_ford(v) 206 + |> Enum.filter(fn {k, _} -> valves[k].rate > 0 and k != v end) 207 + |> Map.new() 208 + 209 + {v, routes} 210 + end 211 + ``` 212 + 213 + <!-- livebook:{"output":true} --> 214 + 215 + ``` 216 + #Graph<type: directed, vertices: ["LF", "CB", "AX", "ZI", "ZH", "VZ", "AA", "UH", "OC", "IH", "FL", 217 + "JR", "QB", "EH", "QH", "ON", "TA", "PJ", "SX", "YB", "UC", "BH", "MO", "OQ", "HM", "JD", "OR", 218 + "NE", "QS", "XT", "IZ", "QZ", "BY", "PG", "NW", "HB", "AG", "QJ", "RT", "TX", "GE", "QX", "XG", 219 + "NX", "GL", "RU", "SM", "ES", "MG", 220 + "OP"], edges: ["LF" -> "UH", "LF" -> "ZI", "CB" -> "MO", "CB" -> "XG", "AX" -> "UH", "AX" -> "MO", "ZI" -> "BY", "ZI" -> "RU", "ZI" -> "ON", "ZI" -> "LF", "ZI" -> "JR", "ZH" -> "OC", "ZH" -> "MO", "VZ" -> "NE", "AA" -> "UC", "AA" -> "EH", "AA" -> "QX", "AA" -> "OP", "AA" -> "QZ", "UH" -> "LF", "UH" -> "PJ", "UH" -> "AX", "UH" -> "NX", "OC" -> "ZH", "OC" -> "IZ", "OC" -> "TA", "OC" -> "PJ", "OC" -> "JR", "IH" -> "YB", "IH" -> "QS", "FL" -> "SX", "FL" -> "ES", "JR" -> "OC", "JR" -> "ZI", "QB" -> "QX", "QB" -> "ES", "EH" -> "MO", "EH" -> "AA", "QH" -> "OR", "QH" -> "HM", "ON" -> "MO", "ON" -> "ZI", "TA" -> "OC", "TA" -> "NE", "PJ" -> "OC", "PJ" -> "UH", "SX" -> "IZ", "SX" -> "FL", "YB" -> "GE", "YB" -> "IH", "YB" -> "XG", "UC" -> "BY", "UC" -> "AA", "BH" -> "OR", "BH" -> "RU", "MO" -> "ZH", "MO" -> "EH", "MO" -> "ON", "MO" -> "CB", "MO" -> "AX", "OQ" -> "GE", "OQ" -> "TX", "HM" -> "TX", "HM" -> "QH", "JD" -> "OR", "JD" -> "SM", "OR" -> "BH", "OR" -> "HB", "OR" -> "JD", "OR" -> "QH", "NE" -> "TA", "NE" -> "VZ", "QS" -> "IH", "XT" -> "QZ", "XT" -> "PG", "IZ" -> "OC", "IZ" -> "SX", "QZ" -> "AA", "QZ" -> "XT", "BY" -> "UC", "BY" -> "ZI", "PG" -> "RT", "PG" -> "XT", "NW" -> "MG", "NW" -> "AG", "HB" -> "OR", "HB" -> "QJ", "AG" -> "SM", "AG" -> "GL", "AG" -> "NW", "QJ" -> "GL", "QJ" -> "HB", "RT" -> "PG", "TX" -> "OQ", "TX" -> "MG", "TX" -> "HM", "GE" -> "OQ", "GE" -> "YB", "QX" -> "QB", "QX" -> "AA", "XG" -> "YB", "XG" -> "CB", "NX" -> "UH", "NX" -> "OP", "GL" -> "QJ", "GL" -> "AG", "RU" -> "BH", "RU" -> "ZI", "SM" -> "AG", "SM" -> "JD", "ES" -> "QB", "ES" -> "FL", "MG" -> "NW", "MG" -> "TX", "OP" -> "AA", "OP" -> "NX"]> 221 + ``` 222 + 223 + <!-- livebook:{"output":true} --> 224 + 225 + ``` 226 + %{ 227 + "CB" => %{ 228 + "AG" => 8, 229 + "ES" => 6, 230 + "MO" => 1, 231 + "OC" => 3, 232 + "OR" => 6, 233 + "QJ" => 8, 234 + "QS" => 4, 235 + "RT" => 7, 236 + "SX" => 5, 237 + "TX" => 5, 238 + "UH" => 3, 239 + "VZ" => 6, 240 + "XT" => 5, 241 + "YB" => 2, 242 + "ZI" => 3 243 + }, 244 + "EH" => %{ 245 + "AG" => 9, 246 + "ES" => 4, 247 + "MO" => 1, 248 + "OC" => 3, 249 + "OR" => 6, 250 + "QJ" => 8, 251 + "QS" => 6, 252 + "RT" => 5, 253 + "SX" => 5, 254 + "TX" => 7, 255 + "UH" => 3, 256 + "VZ" => 6, 257 + "XT" => 3, 258 + "YB" => 4, 259 + "ZI" => 3 260 + }, 261 + "YB" => %{ 262 + "AG" => 6, 263 + "ES" => 8, 264 + "MO" => 3, 265 + "OC" => 5, 266 + "OR" => 6, 267 + "QJ" => 8, 268 + "QS" => 2, 269 + "RT" => 9, 270 + "SX" => 7, 271 + "TX" => 3, 272 + "UH" => 5, 273 + "VZ" => 8, 274 + "XT" => 7, 275 + "ZI" => 5 276 + }, 277 + "ON" => %{ 278 + "AG" => 7, 279 + "ES" => 6, 280 + "MO" => 1, 281 + "OC" => 3, 282 + "OR" => 4, 283 + "QJ" => 6, 284 + "QS" => 6, 285 + "RT" => 7, 286 + "SX" => 5, 287 + "TX" => 7, 288 + "UH" => 3, 289 + "VZ" => 6, 290 + "XT" => 5, 291 + "YB" => 4, 292 + "ZI" => 1 293 + }, 294 + "ES" => %{ 295 + "AG" => 12, 296 + "MO" => 5, 297 + "OC" => 4, 298 + "OR" => 9, 299 + "QJ" => 11, 300 + "QS" => 10, 301 + "RT" => 7, 302 + "SX" => 2, 303 + "TX" => 11, 304 + "UH" => 6, 305 + "VZ" => 7, 306 + "XT" => 5, 307 + "YB" => 8, 308 + "ZI" => 6 309 + }, 310 + "XG" => %{ 311 + "AG" => 7, 312 + "ES" => 7, 313 + "MO" => 2, 314 + "OC" => 4, 315 + "OR" => 7, 316 + "QJ" => 9, 317 + "QS" => 3, 318 + "RT" => 8, 319 + "SX" => 6, 320 + "TX" => 4, 321 + "UH" => 4, 322 + "VZ" => 7, 323 + "XT" => 6, 324 + "YB" => 1, 325 + "ZI" => 4 326 + }, 327 + "TX" => %{ 328 + "AG" => 3, 329 + "ES" => 11, 330 + "MO" => 6, 331 + "OC" => 8, 332 + "OR" => 3, 333 + "QJ" => 5, 334 + "QS" => 5, 335 + "RT" => 12, 336 + "SX" => 10, 337 + "UH" => 8, 338 + "VZ" => 11, 339 + "XT" => 10, 340 + "YB" => 3, 341 + "ZI" => 6 342 + }, 343 + "RT" => %{ 344 + "AG" => 13, 345 + "ES" => 7, 346 + "MO" => 6, 347 + "OC" => 8, 348 + "OR" => 10, 349 + "QJ" => 12, 350 + "QS" => 11, 351 + "SX" => 9, 352 + "TX" => 12, 353 + "UH" => 7, 354 + "VZ" => 11, 355 + "XT" => 2, 356 + "YB" => 9, 357 + "ZI" => 7 358 + }, 359 + "GL" => %{ 360 + "AG" => 1, 361 + "ES" => 12, 362 + "MO" => 8, 363 + "OC" => 8, 364 + "OR" => 3, 365 + "QJ" => 1, 366 + "QS" => 9, 367 + "RT" => 13, 368 + "SX" => 10, 369 + "TX" => 4, 370 + "UH" => 8, 371 + "VZ" => 11, 372 + "XT" => 11, 373 + "YB" => 7, 374 + "ZI" => 6 375 + }, 376 + "XT" => %{ 377 + "AG" => 11, 378 + "ES" => 5, 379 + "MO" => 4, 380 + "OC" => 6, 381 + "OR" => 8, 382 + "QJ" => 10, 383 + "QS" => 9, 384 + "RT" => 2, 385 + "SX" => 7, 386 + "TX" => 10, 387 + "UH" => 5, 388 + "VZ" => 9, 389 + "YB" => 7, 390 + "ZI" => 5 391 + }, 392 + "BY" => %{ 393 + "AG" => 7, 394 + "ES" => 5, 395 + "MO" => 3, 396 + "OC" => 3, 397 + "OR" => 4, 398 + "QJ" => 6, 399 + "QS" => 8, 400 + "RT" => 6, 401 + "SX" => 5, 402 + "TX" => 7, 403 + "UH" => 3, 404 + "VZ" => 6, 405 + "XT" => 4, 406 + "YB" => 6, 407 + "ZI" => 1 408 + }, 409 + "QJ" => %{ 410 + "AG" => 2, 411 + "ES" => 11, 412 + "MO" => 7, 413 + "OC" => 7, 414 + "OR" => 2, 415 + "QS" => 10, 416 + "RT" => 12, 417 + "SX" => 9, 418 + "TX" => 5, 419 + "UH" => 7, 420 + "VZ" => 10, 421 + "XT" => 10, 422 + "YB" => 8, 423 + "ZI" => 5 424 + }, 425 + "QB" => %{ 426 + "AG" => 11, 427 + "ES" => 1, 428 + "MO" => 4, 429 + "OC" => 5, 430 + "OR" => 8, 431 + "QJ" => 10, 432 + "QS" => 9, 433 + "RT" => 6, 434 + "SX" => 3, 435 + "TX" => 10, 436 + "UH" => 5, 437 + "VZ" => 8, 438 + "XT" => 4, 439 + "YB" => 7, 440 + "ZI" => 5 441 + }, 442 + "QH" => %{ 443 + "AG" => 4, 444 + "ES" => 10, 445 + "MO" => 6, 446 + "OC" => 6, 447 + "OR" => 1, 448 + "QJ" => 3, 449 + "QS" => 7, 450 + "RT" => 11, 451 + "SX" => 8, 452 + "TX" => 2, 453 + "UH" => 6, 454 + "VZ" => 9, 455 + "XT" => 9, 456 + "YB" => 5, 457 + "ZI" => 4 458 + }, 459 + "SX" => %{ 460 + "AG" => 10, 461 + "ES" => 2, 462 + "MO" => 4, 463 + "OC" => 2, 464 + "OR" => 7, 465 + "QJ" => 9, 466 + "QS" => 9, 467 + "RT" => 9, 468 + "TX" => 10, 469 + "UH" => 4, 470 + "VZ" => 5, 471 + "XT" => 7, 472 + "YB" => 7, 473 + "ZI" => 4 474 + }, 475 + "ZI" => %{ 476 + "AG" => 6, 477 + "ES" => 6, 478 + "MO" => 2, 479 + "OC" => 2, 480 + "OR" => 3, 481 + "QJ" => 5, 482 + "QS" => 7, 483 + "RT" => 7, 484 + "SX" => 4, 485 + "TX" => 6, 486 + "UH" => 2, 487 + "VZ" => 5, 488 + "XT" => 5, 489 + "YB" => 5 490 + }, 491 + "OC" => %{ 492 + "AG" => 8, 493 + "ES" => 4, 494 + "MO" => 2, 495 + "OR" => 5, 496 + "QJ" => 7, 497 + "QS" => 7, 498 + "RT" => 8, 499 + "SX" => 2, 500 + "TX" => 8, 501 + "UH" => 2, 502 + "VZ" => 3, 503 + "XT" => 6, 504 + "YB" => 5, 505 + "ZI" => 2 506 + }, 507 + "NW" => %{ 508 + "AG" => 1, 509 + "ES" => 13, 510 + "MO" => 8, 511 + "OC" => 9, 512 + "OR" => 4, 513 + "QJ" => 3, 514 + "QS" => 7, 515 + "RT" => 14, 516 + "SX" => 11, 517 + "TX" => 2, 518 + "UH" => 9, 519 + "VZ" => 12, 520 + "XT" => 12, 521 + "YB" => 5, 522 + "ZI" => 7 523 + }, 524 + "UH" => %{ 525 + "AG" => 8, 526 + "ES" => 6, 527 + "MO" => 2, 528 + "OC" => 2, 529 + "OR" => 5, 530 + "QJ" => 7, 531 + "QS" => 7, 532 + "RT" => 7, 533 + "SX" => 4, 534 + "TX" => 8, 535 + "VZ" => 5, 536 + "XT" => 5, 537 + "YB" => 5, 538 + "ZI" => 2 539 + }, 540 + "VZ" => %{ 541 + "AG" => 11, 542 + "ES" => 7, 543 + "MO" => 5, 544 + "OC" => 3, 545 + "OR" => 8, 546 + "QJ" => 10, 547 + "QS" => 10, 548 + "RT" => 11, 549 + "SX" => 5, 550 + "TX" => 11, 551 + "UH" => 5, 552 + "XT" => 9, 553 + "YB" => 8, 554 + "ZI" => 5 555 + }, 556 + "MO" => %{ 557 + "AG" => 8, 558 + "ES" => 5, 559 + "OC" => 2, 560 + "OR" => 5, 561 + "QJ" => 7, 562 + "QS" => 5, 563 + "RT" => 6, 564 + "SX" => 4, 565 + "TX" => 6, 566 + "UH" => 2, 567 + "VZ" => 5, 568 + "XT" => 4, 569 + "YB" => 3, 570 + "ZI" => 2 571 + }, 572 + "ZH" => %{ 573 + "AG" => 9, 574 + "ES" => 5, 575 + "MO" => 1, 576 + "OC" => 1, 577 + "OR" => 6, 578 + "QJ" => 8, 579 + "QS" => 6, 580 + "RT" => 7, 581 + "SX" => 3, 582 + "TX" => 7, 583 + "UH" => 3, 584 + "VZ" => 4, 585 + "XT" => 5, 586 + "YB" => 4, 587 + "ZI" => 3 588 + }, 589 + "RU" => %{ 590 + "AG" => 5, 591 + "ES" => 7, 592 + "MO" => 3, 593 + "OC" => 3, 594 + "OR" => 2, 595 + "QJ" => 4, 596 + "QS" => 8, 597 + "RT" => 8, 598 + "SX" => 5, 599 + "TX" => 5, 600 + "UH" => 3, 601 + "VZ" => 6, 602 + "XT" => 6, 603 + "YB" => 6, 604 + "ZI" => 1 605 + }, 606 + "FL" => %{ 607 + "AG" => 11, 608 + "ES" => 1, 609 + "MO" => 5, 610 + "OC" => 3, 611 + "OR" => 8, 612 + "QJ" => 10, 613 + "QS" => 10, 614 + "RT" => 8, 615 + "SX" => 1, 616 + "TX" => 11, 617 + "UH" => 5, 618 + "VZ" => 6, 619 + "XT" => 6, 620 + "YB" => 8, 621 + "ZI" => 5 622 + }, 623 + "SM" => %{ 624 + "AG" => 1, 625 + "ES" => 11, 626 + "MO" => 7, 627 + "OC" => 7, 628 + "OR" => 2, 629 + "QJ" => 3, 630 + "QS" => 9, 631 + "RT" => 12, 632 + "SX" => 9, 633 + "TX" => 4, 634 + "UH" => 7, 635 + "VZ" => 10, 636 + "XT" => 10, 637 + "YB" => 7, 638 + "ZI" => 5 639 + }, 640 + "AA" => %{ 641 + "AG" => 9, 642 + "ES" => 3, 643 + "MO" => 2, 644 + "OC" => 4, 645 + "OR" => 6, 646 + "QJ" => 8, 647 + "QS" => 7, 648 + "RT" => 4, 649 + "SX" => 5, 650 + "TX" => 8, 651 + "UH" => 3, 652 + "VZ" => 7, 653 + "XT" => 2, 654 + "YB" => 5, 655 + "ZI" => 3 656 + }, 657 + "JR" => %{ 658 + "AG" => 7, 659 + "ES" => 5, 660 + "MO" => 3, 661 + "OC" => 1, 662 + "OR" => 4, 663 + "QJ" => 6, 664 + "QS" => 8, 665 + "RT" => 8, 666 + "SX" => 3, 667 + "TX" => 7, 668 + "UH" => 3, 669 + "VZ" => 4, 670 + "XT" => 6, 671 + "YB" => 6, 672 + "ZI" => 1 673 + }, 674 + "QS" => %{ 675 + "AG" => 8, 676 + "ES" => 10, 677 + "MO" => 5, 678 + "OC" => 7, 679 + "OR" => 8, 680 + "QJ" => 10, 681 + "RT" => 11, 682 + "SX" => 9, 683 + "TX" => 5, 684 + "UH" => 7, 685 + "VZ" => 10, 686 + "XT" => 9, 687 + "YB" => 2, 688 + "ZI" => 7 689 + }, 690 + "AG" => %{ 691 + "ES" => 12, 692 + "MO" => 8, 693 + "OC" => 8, 694 + "OR" => 3, 695 + "QJ" => 2, 696 + "QS" => 8, 697 + "RT" => 13, 698 + "SX" => 10, 699 + "TX" => 3, 700 + "UH" => 8, 701 + "VZ" => 11, 702 + "XT" => 11, 703 + "YB" => 6, 704 + "ZI" => 6 705 + }, 706 + "JD" => %{ 707 + "AG" => 2, 708 + "ES" => 10, 709 + "MO" => 6, 710 + "OC" => 6, 711 + "OR" => 1, 712 + "QJ" => 3, 713 + "QS" => 9, 714 + "RT" => 11, 715 + "SX" => 8, 716 + "TX" => 4, 717 + "UH" => 6, 718 + "VZ" => 9, 719 + "XT" => 9, 720 + "YB" => 7, 721 + "ZI" => 4 722 + }, 723 + "QZ" => %{ 724 + "AG" => 10, 725 + "ES" => 4, 726 + "MO" => 3, 727 + "OC" => 5, 728 + "OR" => 7, 729 + "QJ" => 9, 730 + "QS" => 8, 731 + "RT" => 3, 732 + "SX" => 6, 733 + "TX" => 9, 734 + "UH" => 4, 735 + "VZ" => 8, 736 + "XT" => 1, 737 + "YB" => 6, 738 + "ZI" => 4 739 + }, 740 + "MG" => %{ 741 + "AG" => 2, 742 + "ES" => 12, 743 + "MO" => 7, 744 + "OC" => 9, 745 + "OR" => 4, 746 + "QJ" => 4, 747 + "QS" => 6, 748 + "RT" => 13, 749 + "SX" => 11, 750 + "TX" => 1, 751 + "UH" => 9, 752 + "VZ" => 12, 753 + "XT" => 11, 754 + "YB" => 4, 755 + "ZI" => 7 756 + }, 757 + "UC" => %{ 758 + "AG" => 8, 759 + "ES" => 4, 760 + "MO" => 3, 761 + "OC" => 4, 762 + "OR" => 5, 763 + "QJ" => 7, 764 + "QS" => 8, 765 + "RT" => 5, 766 + "SX" => 6, 767 + "TX" => 8, 768 + "UH" => 4, 769 + "VZ" => 7, 770 + "XT" => 3, 771 + "YB" => 6, 772 + "ZI" => 2 773 + }, 774 + "AX" => %{ 775 + "AG" => 9, 776 + "ES" => 6, 777 + "MO" => 1, 778 + "OC" => 3, 779 + "OR" => 6, 780 + "QJ" => 8, 781 + "QS" => 6, 782 + "RT" => 7, 783 + "SX" => 5, 784 + "TX" => 7, 785 + "UH" => 1, 786 + "VZ" => 6, 787 + "XT" => 5, 788 + "YB" => 4, 789 + "ZI" => 3 790 + }, 791 + "HM" => %{ 792 + "AG" => 4, 793 + "ES" => 11, 794 + "MO" => 7, 795 + "OC" => 7, 796 + "OR" => 2, 797 + "QJ" => 4, 798 + "QS" => 6, 799 + "RT" => 12, 800 + "SX" => 9, 801 + "TX" => 1, 802 + "UH" => 7, 803 + "VZ" => 10, 804 + "XT" => 10, 805 + "YB" => 4, 806 + "ZI" => 5 807 + }, 808 + "LF" => %{ 809 + "AG" => 7, 810 + "ES" => 7, 811 + "MO" => 3, 812 + "OC" => 3, 813 + "OR" => 4, 814 + "QJ" => 6, 815 + "QS" => 8, 816 + "RT" => 8, 817 + "SX" => 5, 818 + "TX" => 7, 819 + "UH" => 1, 820 + "VZ" => 6, 821 + "XT" => 6, 822 + "YB" => 6, 823 + ... 824 + }, 825 + "BH" => %{ 826 + "AG" => 4, 827 + "ES" => 8, 828 + "MO" => 4, 829 + "OC" => 4, 830 + "OR" => 1, 831 + "QJ" => 3, 832 + "QS" => 9, 833 + "RT" => 9, 834 + "SX" => 6, 835 + "TX" => 4, 836 + "UH" => 4, 837 + "VZ" => 7, 838 + "XT" => 7, 839 + ... 840 + }, 841 + "OR" => %{ 842 + "AG" => 3, 843 + "ES" => 9, 844 + "MO" => 5, 845 + "OC" => 5, 846 + "QJ" => 2, 847 + "QS" => 8, 848 + "RT" => 10, 849 + "SX" => 7, 850 + "TX" => 3, 851 + "UH" => 5, 852 + "VZ" => 8, 853 + "XT" => 8, 854 + ... 855 + }, 856 + "GE" => %{ 857 + "AG" => 5, 858 + "ES" => 9, 859 + "MO" => 4, 860 + "OC" => 6, 861 + "OR" => 5, 862 + "QJ" => 7, 863 + "QS" => 3, 864 + "RT" => 10, 865 + "SX" => 8, 866 + "TX" => 2, 867 + "UH" => 6, 868 + ... 869 + }, 870 + "QX" => %{ 871 + "AG" => 10, 872 + "ES" => 2, 873 + "MO" => 3, 874 + "OC" => 5, 875 + "OR" => 7, 876 + "QJ" => 9, 877 + "QS" => 8, 878 + "RT" => 5, 879 + "SX" => 4, 880 + "TX" => 9, 881 + ... 882 + }, 883 + "IZ" => %{ 884 + "AG" => 9, 885 + "ES" => 3, 886 + "MO" => 3, 887 + "OC" => 1, 888 + "OR" => 6, 889 + "QJ" => 8, 890 + "QS" => 8, 891 + "RT" => 9, 892 + "SX" => 1, 893 + ... 894 + }, 895 + "PG" => %{ 896 + "AG" => 12, 897 + "ES" => 6, 898 + "MO" => 5, 899 + "OC" => 7, 900 + "OR" => 9, 901 + "QJ" => 11, 902 + "QS" => 10, 903 + "RT" => 1, 904 + ... 905 + }, 906 + "NX" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 3, "OR" => 6, "QJ" => 8, "QS" => 8, ...}, 907 + "OP" => %{"AG" => 10, "ES" => 4, "MO" => 3, "OC" => 4, "OR" => 7, "QJ" => 9, ...}, 908 + "TA" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 1, "OR" => 6, ...}, 909 + "IH" => %{"AG" => 7, "ES" => 9, "MO" => 4, "OC" => 6, ...}, 910 + "HB" => %{"AG" => 3, "ES" => 10, "MO" => 6, ...}, 911 + "PJ" => %{"AG" => 9, "ES" => 5, ...}, 912 + "OQ" => %{"AG" => 4, ...}, 913 + "NE" => %{...} 914 + } 915 + ``` 916 + 917 + ## Task 1 918 + 919 + ```elixir 920 + defmodule Alone do 921 + def visit(current, valves, paths, left, opened) when left >= 0 do 922 + {left, rate, opened} = 923 + case valves[current].rate do 924 + 0 -> {left, 0, opened} 925 + other -> {left - 1, other, Map.put(opened, current, left - 1)} 926 + end 927 + 928 + rate = rate * left 929 + 930 + paths[current] 931 + |> Enum.map(fn 932 + {next, weight} when weight + 1 < left and not is_map_key(opened, next) -> 933 + {val, opened} = visit(next, valves, paths, left - weight, opened) 934 + {val + rate, opened} 935 + 936 + _ -> 937 + {rate, opened} 938 + end) 939 + |> Enum.max_by(&elem(&1, 0)) 940 + end 941 + end 942 + ``` 943 + 944 + <!-- livebook:{"output":true} --> 945 + 946 + ``` 947 + {:module, Valves, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:visit, 5}} 948 + ``` 949 + 950 + ```elixir 951 + {t, v} = Alone.visit("AA", valves, paths, 30, %{}) 952 + ``` 953 + 954 + <!-- livebook:{"output":true} --> 955 + 956 + ``` 957 + {1820, %{"AG" => 6, "MO" => 23, "QJ" => 3, "QS" => 16, "TX" => 10, "UH" => 26, "YB" => 19}} 958 + ``` 959 + 960 + ## Task 2 961 + 962 + ```elixir 963 + defmodule Alone do 964 + def visit(current, valves, paths, left, opened) when left >= 0 do 965 + {left, rate, opened} = 966 + case valves[current].rate do 967 + 0 -> {left, 0, opened} 968 + other -> {left - 1, other, Map.put(opened, current, left - 1)} 969 + end 970 + 971 + rate = rate * left 972 + 973 + paths[current] 974 + |> Enum.map(fn 975 + {next, weight} when weight + 1 < left and not is_map_key(opened, next) -> 976 + {val, opened} = visit(next, valves, paths, left - weight, opened) 977 + {val + rate, opened} 978 + 979 + _ -> 980 + {rate, opened} 981 + end) 982 + |> Enum.max_by(&elem(&1, 0)) 983 + end 984 + end 985 + ```
+188
2022/day17.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 17 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + <!-- livebook:{"output":true} --> 12 + 13 + ``` 14 + * Getting kino_aoc (https://github.com/ljgago/kino_aoc) 15 + remote: Enumerating objects: 103, done. 16 + remote: Counting objects: 100% (103/103), done. 17 + remote: Compressing objects: 100% (68/68), done. 18 + remote: Total 103 (delta 40), reused 84 (delta 25), pack-reused 0 19 + origin/HEAD set to main 20 + Resolving Hex dependencies... 21 + Resolution completed in 0.336s 22 + New: 23 + castore 1.0.3 24 + finch 0.16.0 25 + hpax 0.1.2 26 + jason 1.4.1 27 + kino 0.10.0 28 + mime 2.0.5 29 + mint 1.5.1 30 + nimble_options 1.0.2 31 + nimble_pool 1.0.0 32 + req 0.3.10 33 + table 0.1.2 34 + telemetry 1.2.1 35 + * Getting kino (Hex package) 36 + * Getting req (Hex package) 37 + * Getting finch (Hex package) 38 + * Getting jason (Hex package) 39 + * Getting mime (Hex package) 40 + * Getting castore (Hex package) 41 + * Getting mint (Hex package) 42 + * Getting nimble_options (Hex package) 43 + * Getting nimble_pool (Hex package) 44 + * Getting telemetry (Hex package) 45 + * Getting hpax (Hex package) 46 + * Getting table (Hex package) 47 + ==> table 48 + Compiling 5 files (.ex) 49 + Generated table app 50 + ==> mime 51 + Compiling 1 file (.ex) 52 + Generated mime app 53 + ==> nimble_options 54 + Compiling 3 files (.ex) 55 + Generated nimble_options app 56 + ==> kino 57 + Compiling 41 files (.ex) 58 + Generated kino app 59 + ===> Analyzing applications... 60 + ===> Compiling telemetry 61 + ==> jason 62 + Compiling 10 files (.ex) 63 + Generated jason app 64 + ==> hpax 65 + Compiling 4 files (.ex) 66 + Generated hpax app 67 + ==> nimble_pool 68 + Compiling 2 files (.ex) 69 + Generated nimble_pool app 70 + ==> castore 71 + Compiling 1 file (.ex) 72 + Generated castore app 73 + ==> mint 74 + Compiling 1 file (.erl) 75 + Compiling 19 files (.ex) 76 + Generated mint app 77 + ==> finch 78 + Compiling 13 files (.ex) 79 + Generated finch app 80 + ==> req 81 + Compiling 5 files (.ex) 82 + Generated req app 83 + ==> kino_aoc 84 + Compiling 3 files (.ex) 85 + Generated kino_aoc app 86 + ``` 87 + 88 + <!-- livebook:{"output":true} --> 89 + 90 + ``` 91 + :ok 92 + ``` 93 + 94 + ## Section 95 + 96 + <!-- livebook:{"attrs":{"day":"17","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 97 + 98 + ```elixir 99 + {:ok, puzzle_input} = 100 + KinoAOC.download_puzzle("2022", "17", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 101 + ``` 102 + 103 + <!-- livebook:{"output":true} --> 104 + 105 + ``` 106 + {:ok, 107 + ">><<<>><<<<>>><>><>>><<<>>>><>>><<><<<>>>><<<><<<><<><<<>>>><<><<>>><<<<>><<>><<<><<<<>><<<<><>>><<<<>>><<<>>>><<<>>>><<<<>>><<>>><<>>>><<<<>>>><<<<>><>>>><<<<>>><<>><>>><>>><<<<>>><<>>><>><<<>>>><<>>>><<<>>><<<>>>><<<<><<<><<>>><>><<<<>><>><<><<<<>>><<>>><<<>>>><<<<>>><<>>>><<<<>><>><<<><<>><<<>>>><<<>><<<<>>>><<<><<<<>>><<><>>><<>><<<>>><<<<>>><<>>>><<<>>><<<<>>><<>>>><<<<>><<>>>><<<>>>><<>>><<><<<>>><<<<>>>><<<<>>><<<>>>><<<<>><<<>>>><>>><><<>>><<<><<>>>><<<>>>><<><<<<>>>><<<><<>><<<<>>>><<>>><>>>><<<<>><<>>><<>>><<>><>><><<<<>>>><<<>><<>>><<><<<<>>>><<<<><<<<>>>><><<>>><><>>><<>>><>>><>>>><<>><><<>><>>><<>>>><<>>>><<<<><<<>>>><>><>>>><<<<><<<><<<>>>><<><<>><<<>>><<<<>>><<<<><<>>><<<>>>><<><<<<>><<<<>><<<><>><>>>><><<<>>><<<<><<<<>><>>><<<>><<<<><<<>>>><<<>>>><<<>><<>><<<<>><<<<>><>>>><<>>>><<<<>>><<>>>><<>>>><>><<<>>>><<<<>>><<<<><>>>><<><<<>><<<<>>>><<<<>><>>>><<<>>>><<<<>>>><<<<>>><<<<>><>>><<<<><>>>><<><>>>><>><<>>>><>>>><<>><<>>><<<>>>><<><<<>>>><<><<>><<<<>>><<<>>><<<<>><<<><<<>>><<><<>>>><<<>>><<>>><<<><<<<>>><>>>><<<>>><<<>>>><<><><<>>>><<>>>><<>>>><<>>><<>><<><<<>>><>>><<<<>>>><>>>><<<>><>><<<<>>><<<<>>><<>>><<<<><<<>>><>>>><<>><<<<>><<<<>><<<<><>><<<<>>>><<>>><>><<<>><<>><<<<>><<>>><<<<>>><<<<>>><<><<<>>><<><<<><<>>>><>><<><<<<><<>><<<>>>><><<<<><><><>>><<<>>><<>>><<<>>>><<><<>><<>><<<><<<<>>>><>>>><<>>>><<<>>>><<>>>><<<>><>><<<>>><<>>>><<><<>>>><<<><<<<>>><<<>>>><<<>>><<<><>>><<>>><<<>>>><<<>>>><<<>>>><<<>><>><<<>>><<<<>>>><><<<>>>><<>>>><><>>><<>>>><<>><<>>>><<<>><<<>>>><<>>>><<<<>><<<>><<<>><<>><<<>>><<><>>><<><<><>>>><<<>>>><<<<>><<>>>><<<<>><><<<>>><<<<>><<>>><<<>><<>><<>><>>>><<><<>>>><>>>><<><><<<><<<<>>>><<<<>><<><<><<>>>><>>><<<><<<<><<>><<<><<>><><<><<<>>>><>>>><<>>>><>><><><<<><<><<>>><<<<><<>><<<>>>><<><<<<>>>><<<<>><><<<<>><<>><>><<<<>>>><<>>>><<<<><<<>><<>>><<<>>><>>><<>>>><<<><<<<><<>>>><<<<>><<<>>>><<<>><<<<><<<>><<<<>><<<>>>><<>>>><><>>><>>><<<>>>><<>>><<<>><>>>><<<>>>><<<<><<<>>><<<<>><<>><<>><<<><<<<>>><><>><<<><<<>>><<<><<<<>>>><><<<<>><<>><>>><<<>>>><<>>><<<>><<<<>>><<<>><<>><<>><<<<><<>>><>><<>>><<><<<><<<>><<<<>>><>><><<<<>>>><<<><<<>><>><<>>>><<<>>>><<<><<<>>><<>>><><>><<<>><>>>><<<<>>>><<<<>>><<<<>>><<<<>><<<<><><<>><>><<>>><<>><<><<<<>>>><<<<>>>><<>>>><<<<>>>><<>>>><>>>><<>><<><<<><><>><<<><<<<>>>><<<<>><<<>>>><<<<>>>><>>>><><<<<>><>>><<<<><<>>>><>><<<<>><<<><<<>>>><<>><<>>><>>>><<><>>>><<<<><<><<<>>>><<<>>>><<><>><<<>><<<>><<<<><<>>><>><<>>><<>>><>>>><<<>>><<>><<><><<>>>><<<>>><<<>><<<>>><<<>>>><<>>><>>>><>>>><>>><<>>>><<<>><<<<>><<<<>><<>>>><><>>>><<>>>><<<><<<<><<>>>><<<<>><<<<>>>><><<<><>><<<<>>>><>>>><<<<>>>><<><>><<<<><<<>>><<<<>><>><>>>><<>>>><>>><>>>><>><<>>><<<><>><>>>><<<>><<<>><<<<><<<<>>><<<>>><<<>>>><>><>>><<<<>><<<><<>>><>>><<><>>>><<<>>>><<<<>>>><><<<>>><<<<>>><>><>>>><<<>><<>>>><>>><<<<>>>><<<>><<<>>>><<<<>><<<>>><<<<><<<<>>>><><<<>>><<<<>>>><<<<>><<>><<<>>><>>><>><<>>><<<>><><<><>><<>><>><<<><<<<>>><<<>><<<><<<>>>><<>>><<<<><<><<<>>><<<<>>><<>><>>><>>><<<><<>>>><<<>><<<<><<<>><<<<>><>><<>><>>>><>>>><<>>><<<<>>><><><><<<>>><<<>><<>>><<<<>>>><>><<<>>>><<>><<<<>><<>><>><<<>>>><>>><<<<>>><>><<>>><<<>><<<<>>>><<<>><<>><>><<<<>><<<><<<>><>><<<><<<>>>><<<<>>><<><<<<><<<<>>>><<<><>><<><>>><<<><<><<<<>>><<>>>><>><<<<>><<<<>>><<>>>><>>><<<>>><<<>>>><<>>><>>>><<<<><>><<>>>><<<>>><>>><>><<<>>>><<><<<>>>><<><<<<>>>><<<<>>>><><<<<>>>><<<>>>><<><<<>>>><<>><>><>>><<<<><<<>>>><<<<>>>><<<><<>>>><<<><>>>><<<<>>>><>>><<<>><<<<><<>>><<>>><<>>><>>><<<><><><<<>>>><<>>>><<<<><>>>><<<>><<>>>><<><<<<><<<<>><><<<<><<>>>><<<>><<<<>><<>><<><<>>>><<><<<><<<<><<<<>>><<<>>>><<<<>>><><<<>>><>>>><>>><<<<>>><<<>>><<<<><<<<><<>><><<<>>><>>><<><<><<>><<<<>>>><<<>><<<><<<<>>><<<<>>><<>><<<<>><>>>><>><<<><>>>><<<>>><<><<>><<<><<<>><<<<>><<<<>><<<<><>>>><<><<<>><<<><<<>><<<<><<>>>><<<>><<<><<<>>><<<><<<<>>>><<>>>><<<>><<<<>>><<><<<<>>>><<<<>>>><<>><<><<>>><<>>>><<>>><<>>><<<>>>><<>>><<><<>>><<<>><<<<>>><<>>><<<>>><<<>>><>>>><<<>>>><<<<>>>><>>>><<<>>>><<<>>>><>>>><>>>><<<><<>><><>><<>><><<<>>>><><>>>><><<<><>>><<<>>><<<>>><<<<>><<<<><<<>>><<>><<<<>>><<<>><<>>>><<><<<<>>><>><<<>>>><<>><<<<>>><<<<>>><>>>><<>" <> ...} 108 + ``` 109 + 110 + ```elixir 111 + well = [0, 0, 0, 0, 0, 0, 0] 112 + ``` 113 + 114 + <!-- livebook:{"output":true} --> 115 + 116 + ``` 117 + [0, 0, 0, 0, 0, 0, 0] 118 + ``` 119 + 120 + ```elixir 121 + defmodule Tetris do 122 + def fit(well, n, :dash) when n in 0..3 do 123 + max = 124 + well 125 + |> Enum.drop(n) 126 + |> Enum.take(4) 127 + |> Enum.max() 128 + 129 + well 130 + |> List.replace_at(n, max + 1) 131 + |> List.replace_at(n + 1, max + 1) 132 + |> List.replace_at(n + 2, max + 1) 133 + |> List.replace_at(n + 3, max + 1) 134 + end 135 + 136 + def fit(well, n, :plus) when n in 0..4 do 137 + bottom = 138 + well 139 + |> Enum.drop(n) 140 + |> Enum.take(3) 141 + |> case do 142 + [a, b, c] when b < a and b < c -> max(a, b) - 1 143 + [_, b, _] -> b 144 + end 145 + 146 + well 147 + |> List.replace_at(n, bottom + 2) 148 + |> List.replace_at(n + 1, bottom + 3) 149 + |> List.replace_at(n + 2, bottom + 2) 150 + end 151 + 152 + def fit(well, n, :l), do: well 153 + 154 + def fit(well, n, :i), do: well 155 + 156 + def fit(well, n, :o), do: well 157 + end 158 + ``` 159 + 160 + <!-- livebook:{"output":true} --> 161 + 162 + ``` 163 + warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) 164 + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:32: Tetris.fit/3 165 + 166 + warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) 167 + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:34: Tetris.fit/3 168 + 169 + warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) 170 + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:36: Tetris.fit/3 171 + 172 + ``` 173 + 174 + <!-- livebook:{"output":true} --> 175 + 176 + ``` 177 + {:module, Tetris, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:fit, 3}} 178 + ``` 179 + 180 + ```elixir 181 + Tetris.fit([2, 1, 2, 0, 0, 0, 0], 0, :plus) 182 + ``` 183 + 184 + <!-- livebook:{"output":true} --> 185 + 186 + ``` 187 + [3, 4, 3, 0, 0, 0, 0] 188 + ```
+266
2022/day18.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 18 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + <!-- livebook:{"output":true} --> 12 + 13 + ``` 14 + :ok 15 + ``` 16 + 17 + ## Section 18 + 19 + <!-- livebook:{"attrs":{"day":"18","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 + 21 + ```elixir 22 + {:ok, puzzle_input} = 23 + KinoAOC.download_puzzle("2022", "18", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 24 + ``` 25 + 26 + <!-- livebook:{"output":true} --> 27 + 28 + ``` 29 + {:ok, 30 + "9,2,13\n12,12,4\n3,8,14\n9,3,4\n15,5,7\n9,5,4\n7,3,10\n12,8,2\n8,12,16\n12,16,12\n5,15,8\n16,7,12\n4,5,6\n11,7,2\n10,14,16\n9,3,15\n6,7,3\n14,10,15\n7,12,3\n13,8,3\n9,1,12\n7,15,5\n8,6,16\n17,9,12\n3,13,6\n7,2,10\n9,14,3\n16,12,6\n13,4,15\n17,14,11\n14,4,5\n15,4,14\n3,4,9\n13,12,17\n15,11,3\n12,14,3\n12,5,4\n16,5,12\n14,16,6\n4,3,11\n9,16,13\n10,6,3\n17,9,7\n5,5,14\n14,13,15\n16,12,8\n7,11,2\n14,9,4\n12,11,15\n13,7,4\n4,15,13\n9,13,2\n7,16,9\n17,13,6\n11,0,11\n15,4,11\n4,12,8\n13,3,13\n5,12,17\n16,14,9\n6,5,4\n9,17,8\n6,10,2\n3,10,7\n1,9,7\n5,14,12\n7,12,5\n3,5,10\n5,15,14\n6,3,11\n15,13,13\n7,4,5\n11,7,4\n11,16,12\n2,11,8\n7,15,4\n9,5,17\n12,14,4\n14,4,6\n7,8,2\n11,3,7\n15,13,7\n12,11,2\n11,6,16\n18,10,10\n4,12,5\n11,10,2\n7,17,9\n3,14,9\n7,17,5\n10,8,17\n10,1,11\n11,11,1\n16,8,14\n2,7,10\n7,9,17\n12,12,2\n11,17,11\n15,10,16\n9,1,8\n1,10,12\n6,2,11\n17,11,8\n9,2,11\n13,5,4\n2,9,11\n4,5,9\n8,3,5\n3,14,11\n3,13,12\n10,8,16\n12,14,16\n15,12,13\n5,3,12\n16,9,12\n1,10,10\n17,6,10\n10,18,8\n8,13,17\n13,7,2\n3,12,13\n2,12,5\n6,9,16\n3,6,9\n6,16,6\n0,9,9\n6,17,10\n15,10,14\n2,8,12\n13,3,8\n11,12,17\n9,17,11\n4,6,8\n15,11,2\n4,6,15\n11,4,12\n11,8,1\n7,1,10\n12,11,3\n18,11,12\n8,16,12\n1,9,11\n16,14,14\n15,8,5\n15,5,5\n6,10,17\n13,4,16\n8,12,2\n10,5,15\n4,11,16\n4,10,4\n12,10,3\n10,5,2\n5,15,7\n14,15,7\n16,10,5\n6,3,3\n12,17,10\n4,7,14\n6,4,12\n13,5,11\n7,15,6\n1,8,9\n4,11,15\n14,4,4\n2,13,8\n5,4,5\n4,13,13\n4,14,8\n17,12,11\n7,16,15\n16,13,11\n11,3,12\n17,9,8\n11,6,15\n11,15,16\n6,17,9\n17,6,8\n13,15,15\n10,17,8\n3,5,5\n3,9,14\n17,10,13\n16,9,13\n13,8,16\n12,5,3\n12,15,15\n5,10,14\n16,15,11\n7,2,9\n9,16,12\n2,14,9\n14,17,8\n13,16,8\n7,3,5\n5,3,10\n11,5,16\n17,10,10\n6,7,16\n1,12,10\n6,14,2\n7,2,12\n12,17,9\n17,6,12\n2,13,13\n8,4,3\n16,8,13\n3,15,7\n16,5,13\n16,13,12\n16,12,5\n16,5,9\n4,13,8\n9,13,17\n13,10,15\n4,6,4\n10,11,17\n13,14,5\n9,14,14\n11,2,7\n12,10,2\n12,18,10\n12,6,16\n17,11,6\n8,14,16\n10,15,3\n3,6,5\n7,10,17\n15,5,12\n16,11,14\n8,12,18\n15,13,9\n6,8,3\n15,12,2\n14,13,6\n15,4,10\n11,1,8\n10,1,6\n5,7,16\n9,7,2\n13,3,6\n8,2,7\n14,14,5\n9,3,13\n6,3,8\n8,5,4\n7,4,4\n10,14,15\n10,16,5\n16,11,10\n3,8,11\n4,13,15\n8,13,5\n10,4,5\n15,14,14\n13,12,16\n11,14,3\n11,17,8\n6,5,2\n15,15,13\n5,5,5\n14,9,2\n5,5,9\n3,7,13\n2,15,9\n15,15,7\n7,17,8\n11,8,2\n16,5,7\n9,16,7\n11,4,4\n7,5,15\n10,12,1\n7,4,14\n9,16,6\n15,10,9\n14,7,16\n7,15,15\n15,11,5\n8,4,14\n13,14,10\n10,12,2\n11,15,14\n13,13,3\n4,13,4\n8,8,17\n9,4,3\n13,5,3\n2,10,8\n6,16,9\n4,8,14\n7,2,11\n14,1,10\n17,8,7\n14,9,13\n14,6,6\n5,6,16\n4,13,10\n8,13,16\n16,9,15\n5,8,3\n18,9,10\n13,14,15\n14,4,13\n17,12,10\n17,7,7\n10,17,6\n16,10,14\n6,11,2\n16,10,10\n12,8,16\n12,13,18\n12,2,8\n17,8,9\n12,6,4\n13,17,10\n17,6,6\n15,8,15\n7,17,13\n4,15,11\n10,12,17\n2,7,11\n17,13,10\n5,12,4\n11,3,13\n5,11,4\n14,3,10\n11,4,14\n10,1,13\n5,6,6\n2,10,12\n5,8,15\n13,7,3\n12,7,4\n15,14,7\n5,7,13\n8,6,3\n9,6,16\n16,5,11\n15,13,15\n9,14,17\n15,14,13\n14,5,6\n2,7,6\n13,15,5\n4,11,5\n8,4,6\n14,14,15\n17,5,10\n5,9,3\n11,5,4\n5,9,13\n16,8,15\n11,11,17\n10,3,4\n14,5,16\n6,9,15\n9,14,16\n9,5,5\n5,15,13\n9,11,3\n7,6,4\n12,13,3\n2,13,7\n10,13,17\n10,17,10\n13,3,9\n14,4,8\n18,8,8\n4,12,7\n6,17,12\n9,9,1\n16,8,12\n12,3,6\n6,5,14\n4,14,12\n15,11,13\n5,4,15\n4,15,12\n5,14,5\n10,4,16\n12,6,2\n15,13,4\n8,15,4\n14,5,14\n16,10,12\n6,17,11\n17,15,10\n16,13,10\n16,12,14\n10,14,3\n11,12,1\n4,10,14\n10,2,15\n16,13,14\n6,14,5\n2,9,7\n12,9,2\n8,18,11\n13,12,2\n7,9,3\n8,16,15\n12,3,15\n9,16,11\n16,9,7\n6,15,7\n12,2,13\n5,12,16\n6,12,17\n12,1,10\n11,13,14\n9,8,18\n15,10,17\n7,13,16\n11,2,11\n10,11,2\n13,16,14\n8,15,14\n8,4,13\n7,7,2\n13,10,1\n7,3,12\n12,2,10\n10,17,11\n3,13,9\n5,10,13\n10,10,16\n6,14,6\n7,6,2\n13,12,4\n15,3,13\n4,3,12\n7,10,18\n4,14,7\n15,9,4\n7,16,4\n11,3,6\n5,11,2\n2,9,13\n14,7,4\n14,15,10\n4,8,4\n7,6,16\n15,12,14\n17,7,10\n13,15,4\n16,4,8\n13,3,5\n6,16,8\n3,6,12\n6,16,7\n15,9,15\n4,6,10\n12,12,16\n2,8,10\n3,13,11\n8,5,6\n14,4,12\n10,9,18\n9,6,2\n6,9,3\n12,14,15\n10,5,12\n17,7,12\n7,11,17\n14,12,15\n18,9,8\n10,5,16\n14,9,16\n4,5,11\n5,13,8\n3,4,6\n2,6,11\n6,15,15\n9,5,2\n11,15,15\n7,16,13\n2,9,12\n1,9,10\n9,7,16\n9,11,17\n16,11,6\n14,16,8\n9,3,12\n8,14,4\n17,8,10\n17,5,9\n4,11,12\n3,5,13\n7,15,14\n11,8,17\n13,2,9\n10,17,12\n8,5,2\n16,16,12\n10,6,16\n16,6,7\n9,10,1\n9,16,15\n7,11,18\n4,9,16\n8,2,11\n7,16,11\n8,7,2\n7,9,2\n2,11,5\n6,3,7\n10,7,17\n6,5,16\n4,4,8\n11,9,4\n5,13,13\n14,6,14\n2,8,7\n14,5,5\n13,14,3\n15,14,8\n9,5,3\n16,4,11\n3,7,15\n7,16,12\n14,14,14\n4,9,5\n4,4,10\n2,14,12\n15,2,9\n9,15,4\n16,13,6\n7,7,3\n4,11,6\n1,12,9\n12,10,17\n5,12,14\n16,12,12\n6,6,5\n15,11,11\n11,4,5\n11,13,5\n18,13,9\n17,6,13\n12,4,12\n5,16,9\n10,9,17\n3,14" <> ...} 31 + ``` 32 + 33 + ```elixir 34 + cubes = 35 + puzzle_input 36 + |> String.split("\n", trim: true) 37 + |> Enum.map(fn line -> 38 + line 39 + |> String.split(",") 40 + |> Enum.map(&String.to_integer/1) 41 + |> List.to_tuple() 42 + end) 43 + |> MapSet.new() 44 + ``` 45 + 46 + <!-- livebook:{"output":true} --> 47 + 48 + ``` 49 + MapSet.new([ 50 + {12, 9, 18}, 51 + {11, 4, 5}, 52 + {2, 10, 6}, 53 + {12, 2, 8}, 54 + {14, 15, 15}, 55 + {5, 14, 12}, 56 + {10, 6, 18}, 57 + {6, 4, 6}, 58 + {11, 4, 3}, 59 + {6, 14, 3}, 60 + {4, 8, 4}, 61 + {17, 7, 9}, 62 + {7, 12, 16}, 63 + {14, 13, 3}, 64 + {12, 3, 16}, 65 + {13, 6, 2}, 66 + {5, 6, 5}, 67 + {17, 10, 11}, 68 + {4, 16, 9}, 69 + {17, 9, 9}, 70 + {6, 2, 10}, 71 + {13, 17, 13}, 72 + {12, 13, 3}, 73 + {3, 13, 7}, 74 + {13, 7, 4}, 75 + {17, 12, 7}, 76 + {7, 3, 13}, 77 + {12, 15, 15}, 78 + {15, 6, 4}, 79 + {17, 10, 8}, 80 + {9, 14, 13}, 81 + {3, 9, 4}, 82 + {14, 13, 9}, 83 + {15, 13, 4}, 84 + {13, 4, 15}, 85 + {7, 7, 15}, 86 + {6, 14, 8}, 87 + {11, 2, 16}, 88 + {7, 2, 8}, 89 + {3, 14, 13}, 90 + {4, 5, 6}, 91 + {3, 9, 14}, 92 + {4, 16, 12}, 93 + {14, 12, 12}, 94 + {14, 5, 15}, 95 + {17, 9, 12}, 96 + {15, 10, 15}, 97 + {8, 17, ...}, 98 + {2, ...}, 99 + {...}, 100 + ... 101 + ]) 102 + ``` 103 + 104 + ## Task 1 105 + 106 + ```elixir 107 + sides = 108 + for {x, y, z} <- cubes, 109 + {place, {dx, dy, dz}} <- [ 110 + x: {-1, 0, 0}, 111 + y: {0, -1, 0}, 112 + z: {0, 0, -1}, 113 + x: {0, 0, 0}, 114 + y: {0, 0, 0}, 115 + z: {0, 0, 0} 116 + ], 117 + reduce: MapSet.new() do 118 + set -> 119 + side = {place, {x + dx, y + dy, z + dz}} 120 + 121 + if side in set do 122 + MapSet.delete(set, side) 123 + else 124 + MapSet.put(set, side) 125 + end 126 + end 127 + 128 + MapSet.size(sides) 129 + ``` 130 + 131 + <!-- livebook:{"output":true} --> 132 + 133 + ``` 134 + 3636 135 + ``` 136 + 137 + ## Task 2 138 + 139 + ```elixir 140 + max = 141 + Enum.reduce(cubes, {0, 0, 0}, fn {x, y, z}, {mx, my, mz} -> 142 + {max(x, mx), max(y, my), max(z, mz)} 143 + end) 144 + ``` 145 + 146 + <!-- livebook:{"output":true} --> 147 + 148 + ``` 149 + {19, 19, 19} 150 + ``` 151 + 152 + ```elixir 153 + defmodule Cave do 154 + def bfs([], _sides, outer, _visited), do: outer 155 + 156 + def bfs([{x, y, z} = p | queue], sides, outer, visited) do 157 + {min, max} = Enum.min_max([x, y, z]) 158 + 159 + if p in visited or max > 25 or min < -5 do 160 + bfs(queue, sides, outer, visited) 161 + else 162 + visited = MapSet.put(visited, p) 163 + 164 + {outer, xs1} = check(:x, p, {x + 1, y, z}, sides, outer, visited) 165 + {outer, xs2} = check(:x, {x - 1, y, z}, {x - 1, y, z}, sides, outer, visited) 166 + {outer, ys1} = check(:y, p, {x, y + 1, z}, sides, outer, visited) 167 + {outer, ys2} = check(:y, {x, y - 1, z}, {x, y - 1, z}, sides, outer, visited) 168 + {outer, zs1} = check(:z, p, {x, y, z + 1}, sides, outer, visited) 169 + {outer, zs2} = check(:z, {x, y, z - 1}, {x, y, z - 1}, sides, outer, visited) 170 + 171 + bfs(queue ++ xs1 ++ xs2 ++ ys1 ++ ys2 ++ zs1 ++ zs2, sides, outer, visited) 172 + end 173 + end 174 + 175 + defp check(axis, curr, next, sides, outer, visited) do 176 + cond do 177 + {axis, curr} in sides -> 178 + {MapSet.put(outer, {axis, curr}), []} 179 + 180 + next in visited -> 181 + {outer, []} 182 + 183 + true -> 184 + {outer, [next]} 185 + end 186 + end 187 + end 188 + ``` 189 + 190 + <!-- livebook:{"output":true} --> 191 + 192 + ``` 193 + {:module, Cave, <<70, 79, 82, 49, 0, 0, 14, ...>>, {:check, 6}} 194 + ``` 195 + 196 + ```elixir 197 + outer = Cave.bfs([{-5, -5, -5}], sides, MapSet.new(), MapSet.new()) 198 + ``` 199 + 200 + <!-- livebook:{"output":true} --> 201 + 202 + ``` 203 + MapSet.new([ 204 + x: {10, 19, 11}, 205 + z: {15, 16, 12}, 206 + z: {2, 16, 10}, 207 + z: {5, 13, 2}, 208 + y: {4, 3, 15}, 209 + x: {0, 13, 10}, 210 + x: {17, 12, 6}, 211 + z: {10, 11, 0}, 212 + z: {10, 5, 17}, 213 + z: {4, 7, 2}, 214 + x: {15, 16, 9}, 215 + x: {2, 7, 4}, 216 + z: {2, 8, 5}, 217 + y: {16, 13, 5}, 218 + x: {2, 6, 14}, 219 + x: {18, 12, 11}, 220 + y: {13, 17, 7}, 221 + z: {3, 9, 14}, 222 + y: {11, 3, 16}, 223 + x: {4, 10, 17}, 224 + y: {11, 2, 15}, 225 + z: {13, 4, 3}, 226 + x: {10, 17, 5}, 227 + y: {3, 12, 4}, 228 + y: {11, 18, 10}, 229 + z: {5, 17, 8}, 230 + y: {15, 16, 6}, 231 + y: {3, 3, 7}, 232 + z: {7, 1, 5}, 233 + x: {14, 2, 9}, 234 + y: {18, 5, 8}, 235 + x: {10, 1, 13}, 236 + x: {9, 16, 3}, 237 + x: {2, 15, 8}, 238 + y: {7, 4, 2}, 239 + x: {17, 6, 12}, 240 + x: {0, 9, 7}, 241 + x: {12, 8, 1}, 242 + x: {0, 11, 10}, 243 + z: {10, 16, 3}, 244 + x: {16, 5, 6}, 245 + z: {5, 10, 1}, 246 + z: {7, 4, 15}, 247 + z: {12, 11, 18}, 248 + y: {11, 17, 12}, 249 + z: {3, 5, 4}, 250 + z: {6, 1, 9}, 251 + x: {16, 8, ...}, 252 + z: {14, ...}, 253 + z: {...}, 254 + ... 255 + ]) 256 + ``` 257 + 258 + ```elixir 259 + MapSet.size(outer) 260 + ``` 261 + 262 + <!-- livebook:{"output":true} --> 263 + 264 + ``` 265 + 2102 266 + ```
+230
2022/day19.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 19 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + <!-- livebook:{"output":true} --> 12 + 13 + ``` 14 + :ok 15 + ``` 16 + 17 + ## Section 18 + 19 + <!-- livebook:{"attrs":{"day":"19","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 + 21 + ```elixir 22 + {:ok, puzzle_input} = 23 + KinoAOC.download_puzzle("2022", "19", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 24 + ``` 25 + 26 + <!-- livebook:{"output":true} --> 27 + 28 + ``` 29 + {:ok, 30 + "Blueprint 1: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 15 clay. Each geode robot costs 2 ore and 8 obsidian.\nBlueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 17 clay. Each geode robot costs 3 ore and 10 obsidian.\nBlueprint 3: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 14 obsidian.\nBlueprint 4: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 4 ore and 15 obsidian.\nBlueprint 5: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 6: Each ore robot costs 2 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 2 ore and 7 obsidian.\nBlueprint 7: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 9 clay. Each geode robot costs 3 ore and 7 obsidian.\nBlueprint 8: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 8 obsidian.\nBlueprint 9: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 4 ore and 18 obsidian.\nBlueprint 10: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 19 obsidian.\nBlueprint 11: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 3 ore and 10 obsidian.\nBlueprint 12: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 11 clay. Each geode robot costs 2 ore and 16 obsidian.\nBlueprint 13: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 16 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 14: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 13 obsidian.\nBlueprint 15: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 2 ore and 20 obsidian.\nBlueprint 16: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 14 clay. Each geode robot costs 4 ore and 10 obsidian.\nBlueprint 17: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 17 clay. Each geode robot costs 3 ore and 16 obsidian.\nBlueprint 18: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 20 clay. Each geode robot costs 2 ore and 17 obsidian.\nBlueprint 19: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 4 ore and 12 obsidian.\nBlueprint 20: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian.\nBlueprint 21: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 4 ore and 12 obsidian.\nBlueprint 22: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 13 clay. Each geode robot costs 3 ore and 19 obsidian.\nBlueprint 23: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 3 ore and 8 obsidian.\nBlueprint 24: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 13 clay. Each geode robot costs 2 ore and 9 obsidian.\nBlueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 15 obsidian.\nBlueprint 26: Each ore robot costs 4 ore. Each clay robot costs " <> ...} 31 + ``` 32 + 33 + ```elixir 34 + puzzle_input = """ 35 + Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. 36 + Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian. 37 + """ 38 + ``` 39 + 40 + <!-- livebook:{"output":true} --> 41 + 42 + ``` 43 + "Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.\nBlueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian.\n" 44 + ``` 45 + 46 + ```elixir 47 + regex = 48 + ~r/ore robot.*(?<ore_ore>\d+) ore.*clay robot.*(?<clay_ore>\d+) ore.*obsidian robot.*(?<obsidian_ore>\d+) ore and (?<obsidian_clay>\d+) clay.*geode robot.*(?<geode_ore>\d+) ore and (?<geode_obsidian>\d+) obsidian/ 49 + 50 + plans = 51 + puzzle_input 52 + |> String.split("\n", trim: true) 53 + |> Kino.render() 54 + |> Enum.map(fn line -> 55 + blueprint = 56 + Regex.named_captures(regex, line) 57 + |> Map.new(fn {k, v} -> 58 + {String.to_atom(k), String.to_integer(v)} 59 + end) 60 + 61 + %{ 62 + ore: %{ore: blueprint.ore_ore}, 63 + clay: %{ore: blueprint.clay_ore}, 64 + obsidian: %{ore: blueprint.obsidian_ore, clay: blueprint.obsidian_clay}, 65 + geode: %{ore: blueprint.geode_ore, obsidian: blueprint.geode_obsidian}, 66 + max: %{ 67 + ore: 68 + Enum.max([ 69 + blueprint.ore_ore, 70 + blueprint.clay_ore, 71 + blueprint.obsidian_ore, 72 + blueprint.geode_ore 73 + ]), 74 + clay: blueprint.obsidian_clay, 75 + obsidian: blueprint.geode_obsidian 76 + } 77 + } 78 + end) 79 + ``` 80 + 81 + <!-- livebook:{"output":true} --> 82 + 83 + ``` 84 + ["Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian.", 85 + "Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian."] 86 + ``` 87 + 88 + <!-- livebook:{"output":true} --> 89 + 90 + ``` 91 + [ 92 + %{ 93 + clay: %{ore: 2}, 94 + geode: %{obsidian: 7, ore: 2}, 95 + max: %{clay: 14, obsidian: 7, ore: 4}, 96 + obsidian: %{clay: 14, ore: 3}, 97 + ore: %{ore: 4} 98 + }, 99 + %{ 100 + clay: %{ore: 3}, 101 + geode: %{obsidian: 12, ore: 3}, 102 + max: %{clay: 8, obsidian: 12, ore: 3}, 103 + obsidian: %{clay: 8, ore: 3}, 104 + ore: %{ore: 2} 105 + } 106 + ] 107 + ``` 108 + 109 + ```elixir 110 + defmodule Blueprint do 111 + def produce(plan, time, machines) do 112 + produce(plan, time, machines, %{ore: 0, clay: 0, obsidian: 0, geode: 0}) 113 + end 114 + 115 + def produce(_plan, 0, machines, stash) do 116 + %{machines: machines, stash: stash} 117 + end 118 + 119 + def produce(plan, time_left, machines, stash) do 120 + do_shopping(plan, stash) 121 + |> Enum.filter(fn {k, _} -> (machines[k] || 0) < plan.max[k] end) 122 + |> Enum.flat_map(fn {machine, new_stash} -> 123 + # if machine in [:obsidian, :geode], do: IO.inspect(new_stash) 124 + [ 125 + produce( 126 + plan, 127 + time_left - 1, 128 + add_machine(machine, machines), 129 + update_stash(machines, new_stash) 130 + ) 131 + ] 132 + end) 133 + # |> tap(fn list -> 134 + # Enum.filter(list, & &1.obsidian > 0) 135 + # |> Enum.map(&IO.inspect/1) 136 + # end) 137 + |> Enum.max_by(& &1.stash.geode) 138 + end 139 + 140 + defp add_machine(nil, machines), do: machines 141 + defp add_machine(name, machines), do: Map.update(machines, name, 1, &(&1 + 1)) 142 + 143 + defp update_stash(machines, stash) do 144 + Enum.reduce(machines, stash, fn {k, v}, acc -> 145 + Map.update(acc, k, v, &(&1 + v)) 146 + end) 147 + end 148 + 149 + def do_shopping(plan, stash) 150 + when stash.ore >= plan.geode.ore and stash.obsidian >= plan.geode.obsidian, 151 + do: [{:geode, buy(plan.geode, stash)}] 152 + 153 + def do_shopping(plan, stash) 154 + when stash.ore >= plan.obsidian.ore and stash.clay >= plan.obsidian.clay, 155 + do: [{:obsidian, buy(plan.obsidian, stash)}, {nil, stash}] 156 + 157 + def do_shopping(plan, stash) do 158 + [ 159 + {nil, stash} 160 + | Enum.flat_map([:ore, :clay], fn k -> 161 + if stash.ore >= plan[k].ore do 162 + [{k, %{stash | ore: stash.ore - plan[k].ore}}] 163 + else 164 + [] 165 + end 166 + end) 167 + ] 168 + end 169 + 170 + defp buy(price, stash) do 171 + Map.merge(stash, price, fn _k, v1, v2 -> v1 - v2 end) 172 + end 173 + end 174 + ``` 175 + 176 + <!-- livebook:{"output":true} --> 177 + 178 + ``` 179 + {:module, Blueprint, <<70, 79, 82, 49, 0, 0, 22, ...>>, {:buy, 2}} 180 + ``` 181 + 182 + ```elixir 183 + plan = hd(plans) |> Kino.inspect() 184 + stash = %{clay: 35, geode: 0, obsidian: 0, ore: 4} 185 + 186 + Blueprint.do_shopping(plan, stash) 187 + ``` 188 + 189 + <!-- livebook:{"output":true} --> 190 + 191 + ``` 192 + %{ 193 + clay: %{ore: 2}, 194 + geode: %{obsidian: 7, ore: 2}, 195 + max: %{clay: 14, obsidian: 7, ore: 4}, 196 + obsidian: %{clay: 14, ore: 3}, 197 + ore: %{ore: 4} 198 + } 199 + ``` 200 + 201 + <!-- livebook:{"output":true} --> 202 + 203 + ``` 204 + [ 205 + obsidian: %{clay: 21, geode: 0, obsidian: 0, ore: 1}, 206 + nil: %{clay: 35, geode: 0, obsidian: 0, ore: 4} 207 + ] 208 + ``` 209 + 210 + ```elixir 211 + plans 212 + # |> Enum.drop(1) 213 + |> Enum.take(1) 214 + |> Kino.inspect() 215 + |> Enum.map(fn plan -> Blueprint.produce(plan, 24, %{ore: 1}) end) 216 + ``` 217 + 218 + <!-- livebook:{"output":true} --> 219 + 220 + ``` 221 + [ 222 + %{ 223 + clay: %{ore: 2}, 224 + geode: %{obsidian: 7, ore: 2}, 225 + max: %{clay: 14, obsidian: 7, ore: 4}, 226 + obsidian: %{clay: 14, ore: 3}, 227 + ore: %{ore: 4} 228 + } 229 + ] 230 + ```
+15
2022/day20.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 20 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + ## Section 12 + 13 + ```elixir 14 + 15 + ```
+78 -1
2022/day21.livemd
··· 11 11 <!-- livebook:{"output":true} --> 12 12 13 13 ``` 14 + * Getting kino_aoc (https://github.com/ljgago/kino_aoc) 15 + remote: Enumerating objects: 78, done. 16 + remote: Counting objects: 100% (78/78), done. 17 + remote: Compressing objects: 100% (50/50), done. 18 + remote: Total 78 (delta 25), reused 67 (delta 18), pack-reused 0 19 + origin/HEAD set to main 20 + Resolving Hex dependencies... 21 + Dependency resolution completed: 22 + New: 23 + castore 0.1.20 24 + finch 0.14.0 25 + hpax 0.1.2 26 + jason 1.4.0 27 + kino 0.8.0 28 + mime 2.0.3 29 + mint 1.4.2 30 + nimble_options 0.5.2 31 + nimble_pool 0.2.6 32 + req 0.3.4 33 + table 0.1.2 34 + telemetry 1.2.0 35 + * Getting kino (Hex package) 36 + * Getting req (Hex package) 37 + * Getting finch (Hex package) 38 + * Getting jason (Hex package) 39 + * Getting mime (Hex package) 40 + * Getting castore (Hex package) 41 + * Getting mint (Hex package) 42 + * Getting nimble_options (Hex package) 43 + * Getting nimble_pool (Hex package) 44 + * Getting telemetry (Hex package) 45 + * Getting hpax (Hex package) 46 + * Getting table (Hex package) 47 + ==> table 48 + Compiling 5 files (.ex) 49 + Generated table app 50 + ==> mime 51 + Compiling 1 file (.ex) 52 + Generated mime app 53 + ==> nimble_options 54 + Compiling 3 files (.ex) 55 + Generated nimble_options app 56 + ==> kino 57 + Compiling 37 files (.ex) 58 + Generated kino app 59 + ===> Analyzing applications... 60 + ===> Compiling telemetry 61 + ==> jason 62 + Compiling 10 files (.ex) 63 + Generated jason app 64 + ==> hpax 65 + Compiling 4 files (.ex) 66 + Generated hpax app 67 + ==> nimble_pool 68 + Compiling 2 files (.ex) 69 + Generated nimble_pool app 70 + ==> castore 71 + Compiling 1 file (.ex) 72 + Generated castore app 73 + ==> mint 74 + Compiling 1 file (.erl) 75 + Compiling 19 files (.ex) 76 + Generated mint app 77 + ==> finch 78 + Compiling 13 files (.ex) 79 + Generated finch app 80 + ==> req 81 + Compiling 5 files (.ex) 82 + Generated req app 83 + ==> kino_aoc 84 + Compiling 3 files (.ex) 85 + Generated kino_aoc app 86 + ``` 87 + 88 + <!-- livebook:{"output":true} --> 89 + 90 + ``` 14 91 :ok 15 92 ``` 16 93 17 94 ## Section 18 95 19 - <!-- livebook:{"attrs":{"day":"21","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 96 + <!-- livebook:{"attrs":{"day":"21","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 20 97 21 98 ```elixir 22 99 {:ok, puzzle_input} =
+15
2022/day22.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 22 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + ## Section 12 + 13 + ```elixir 14 + 15 + ```
+15
2022/day23.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 23 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + ## Section 12 + 13 + ```elixir 14 + 15 + ```
+15
2022/day24.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 24 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + ## Section 12 + 13 + ```elixir 14 + 15 + ```
+15
2022/day25.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 25 4 + 5 + ```elixir 6 + Mix.install([ 7 + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} 8 + ]) 9 + ``` 10 + 11 + ## Section 12 + 13 + ```elixir 14 + 15 + ```