diff --git a/2022/day01.livemd b/2022/day01.livemd index 792e3f6..8864e91 100644 --- a/2022/day01.livemd +++ b/2022/day01.livemd @@ -4,19 +4,13 @@ ```elixir Mix.install([ - {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} + {:kino_aoc, ">= 0.0.0"} ]) ``` - - -``` -:ok -``` - ## Setup - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day06.livemd b/2022/day06.livemd index b588af2..894b094 100644 --- a/2022/day06.livemd +++ b/2022/day06.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day07.livemd b/2022/day07.livemd index f7c3bc1..1efa25c 100644 --- a/2022/day07.livemd +++ b/2022/day07.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day08.livemd b/2022/day08.livemd index ad7a65b..ddbabd7 100644 --- a/2022/day08.livemd +++ b/2022/day08.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day09.livemd b/2022/day09.livemd index 9f02c35..9682b63 100644 --- a/2022/day09.livemd +++ b/2022/day09.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Setup - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day10.livemd b/2022/day10.livemd index 6dcb08f..1647dc9 100644 --- a/2022/day10.livemd +++ b/2022/day10.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day11.livemd b/2022/day11.livemd index 9776f5b..333a8b8 100644 --- a/2022/day11.livemd +++ b/2022/day11.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day12.livemd b/2022/day12.livemd index ed39697..d58ae1a 100644 --- a/2022/day12.livemd +++ b/2022/day12.livemd @@ -17,7 +17,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day13.livemd b/2022/day13.livemd index 06d7d40..c592398 100644 --- a/2022/day13.livemd +++ b/2022/day13.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day14.livemd b/2022/day14.livemd index 76254cd..f11b048 100644 --- a/2022/day14.livemd +++ b/2022/day14.livemd @@ -10,6 +10,17 @@ Mix.install( ], consolidate_protocols: false ) + +# defimpl Kino.Render, for: Vix.Vips.Image do +# alias Vix.Vips.Image, as: VImg + +# def to_livebook(image) do +# format = "png" + +# {:ok, image_bin} = VImg.write_to_buffer(image, ".#{format}") +# Kino.Output.image(image_bin, "image/#{format}") +# end +# end ``` @@ -20,7 +31,7 @@ Mix.install( ## Setup - + ```elixir {:ok, puzzle_input} = @@ -36,17 +47,17 @@ Mix.install( ```elixir defmodule Cave do - defstruct map: MapSet.new(), occupied: MapSet.new(), width: nil, height: 0, start: {500, 0} + defstruct map: %{}, width: nil, height: 0, start: {500, 0} def parse(input, start \\ {500, 0}) do map = input |> String.split("\n", trim: true) |> Enum.map(&Cave.parse_line/1) - |> Enum.reduce(&MapSet.union/2) + |> Enum.reduce(&Map.merge/2) {width, height} = - for {x, y} <- map, + for {{x, y}, _} <- map, reduce: {nil, nil} do {nil, nil} -> {x..x, y} @@ -55,21 +66,7 @@ defmodule Cave do {min(min_x, x)..max(max_x, x), max(max_y, y)} end - %__MODULE__{map: map, occupied: map, start: start, width: width, height: height} - end - - def add_line(%__MODULE__{} = cave, line) do - {width, height} = - Enum.reduce(line, {cave.width, cave.height}, fn {x, y}, {x0..x1, h} -> - {min(x, x0)..max(x, x1), max(y, h)} - end) - - struct(cave, - width: width, - height: height, - map: MapSet.union(cave.map, line), - occupied: MapSet.union(cave.occupied, line) - ) + %__MODULE__{map: map, start: start, width: width, height: height} end def parse_point(str) do @@ -91,30 +88,28 @@ defmodule Cave do [{x1, y}, {x2, y}] -> for x <- x1..x2, do: {x, y} end) - |> MapSet.new() + |> Map.new(&{&1, :rock}) points end def drop_sand(%__MODULE__{} = cave), do: drop_sand(cave, cave.start) - def drop_sand(%__MODULE__{height: h, width: x0..x1} = cave, {sx, sy}) - when sx not in x0..x1 or sy >= h, - do: {:fall_out, cave} + def drop_sand(%__MODULE__{height: h} = cave, {_, sy} = p) + when sy >= h, + do: {p, struct(cave, map: Map.put(cave.map, p, :sand))} - def drop_sand(%__MODULE__{} = cave, {sx, sy}) do + def drop_sand(%__MODULE__{map: map} = cave, {sx, sy} = p) do cond do - {sx, sy + 1} not in cave.occupied -> drop_sand(cave, {sx, sy + 1}) - {sx - 1, sy + 1} not in cave.occupied -> drop_sand(cave, {sx - 1, sy + 1}) - {sx + 1, sy + 1} not in cave.occupied -> drop_sand(cave, {sx + 1, sy + 1}) - true -> {{sx, sy}, struct(cave, occupied: MapSet.put(cave.occupied, {sx, sy}))} + not Map.has_key?(map, {sx, sy + 1}) -> drop_sand(cave, {sx, sy + 1}) + not Map.has_key?(map, {sx - 1, sy + 1}) -> drop_sand(cave, {sx - 1, sy + 1}) + not Map.has_key?(map, {sx + 1, sy + 1}) -> drop_sand(cave, {sx + 1, sy + 1}) + true -> {p, struct(cave, map: Map.put(cave.map, p, :sand))} end end -end -defimpl Kino.Render, for: Cave do - def to_livebook(%@for{} = cave) do - x0..x1 = cave.width + def to_image(%__MODULE__{} = cave) do + {{{x0, _}, _}, {{x1, _}, _}} = Enum.min_max_by(cave.map, fn {{x, _}, _} -> x end) {sx, sy} = cave.start image = Image.new!(x1 - x0 + 3, cave.height + 3) @@ -122,23 +117,28 @@ defimpl Kino.Render, for: Cave do Image.mutate(image, fn im -> Image.Draw.point(im, sx - x0 + 1, sy + 1, color: :red) - for {x, y} <- cave.occupied do - Image.Draw.point(im, x - x0 + 1, y + 1, color: :tan) - end - - for {x, y} <- cave.map do - Image.Draw.point(im, x - x0 + 1, y + 1, color: :white) - end + cave.map + |> Enum.sort() + |> Enum.each(fn {{x, y}, type} -> + case type do + :rock -> Image.Draw.point(im, x - x0 + 1, y + 1, color: :white) + :sand -> Image.Draw.point(im, x - x0 + 1, y + 1, color: :tan) + end + end) :ok end) - buf = - image - |> Image.resize!(4, interpolate: :nearest) - |> Image.write!(:memory, suffix: ".png") + image + end +end - Kino.Output.image(buf, "image/png") +defimpl Kino.Render, for: Cave do + def to_livebook(%@for{} = cave) do + cave + |> @for.to_image() + |> Image.resize!(4, interpolate: :nearest) + |> Kino.Render.to_livebook() end end ``` @@ -146,19 +146,38 @@ end ``` -{:module, Kino.Render.Cave, <<70, 79, 82, 49, 0, 0, 16, ...>>, {:to_livebook, 1}} +{:module, Kino.Render.Cave, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:to_livebook, 1}} ``` ```elixir cave = Cave.parse(puzzle_input) + +floor = cave.height + 1 + +cave = struct(cave, height: floor) ``` ## Task 1 ```elixir -Stream.unfold(cave, &Cave.drop_sand/1) -|> Enum.take_while(&(&1 != :fall_out)) -|> length() +frame = Kino.Frame.new() |> Kino.render() + +image = Cave.to_image(cave) + +cave +|> Stream.unfold(fn cave -> + {_, new_cave} = ret = Cave.drop_sand(cave) + + {ret, new_cave} +end) +|> Enum.reduce_while(0, fn {{_x, y}, cave}, acc -> + if y < cave.height do + {:cont, acc + 1} + else + Kino.Frame.render(frame, Image.resize!(Cave.to_image(cave), 4, interpolate: :nearest)) + {:halt, acc} + end +end) ``` @@ -170,20 +189,37 @@ Stream.unfold(cave, &Cave.drop_sand/1) ## Task 2 ```elixir -floor_y = cave.height + 2 +{grains, pyramid} = + Stream.unfold(cave, fn cave -> + {_, new_cave} = ret = Cave.drop_sand(cave) + + {ret, new_cave} + end) + |> Enum.reduce_while(0, fn {p, cave}, acc -> + if p != {500, 0} do + {:cont, acc + 1} + else + {:halt, {acc + 1, cave}} + end + end) -floor = for x <- 0..(cave.width.last * 2), into: MapSet.new(), do: {x, floor_y} +grains +``` -cave = Cave.add_line(cave, floor) + -Stream.unfold(cave, &Cave.drop_sand/1) -|> Enum.take_while(&(&1 != cave.start)) -|> length() -|> then(&(&1 + 1)) +``` +26686 +``` + +```elixir +Kino.render(pyramid) + +:ok ``` ``` -26686 +:ok ``` diff --git a/2022/day15.livemd b/2022/day15.livemd index 5177e44..88c360b 100644 --- a/2022/day15.livemd +++ b/2022/day15.livemd @@ -16,7 +16,7 @@ Mix.install([ ## Section - + ```elixir {:ok, puzzle_input} = @@ -108,6 +108,13 @@ defmodule RangeSet do a end + def continuous?(%__MODULE__{ranges: []}), do: true + def continuous?(%__MODULE__{ranges: [_]}), do: true + def continuous?(%__MODULE__{ranges: _}), do: false + + def gaps(%__MODULE__{ranges: []} = set), do: set + def gaps(%__MODULE__{ranges: [_]}), do: %__MODULE__{ranges: []} + def gaps(%__MODULE__{ranges: ranges}) do gaps = ranges @@ -199,7 +206,7 @@ end ``` -{:module, RangeSet, <<70, 79, 82, 49, 0, 0, 37, ...>>, {:squash, 1}} +{:module, RangeSet, <<70, 79, 82, 49, 0, 0, 39, ...>>, {:squash, 1}} ``` ```elixir @@ -272,12 +279,19 @@ beacons_at_line = circles |> Beacons.covered_at_line(a_y) +|> IO.inspect() |> RangeSet.remove(beacons_at_line) |> RangeSet.length() ``` +``` +%RangeSet{ranges: [-101830..5006266]} +``` + + + ``` 5108096 ``` @@ -293,18 +307,24 @@ range = 4_000_000..0//-1 |> Enum.find_value(fn y -> covered = Beacons.covered_at_line(circles, y) - gaps = RangeSet.gaps(covered) - - if not RangeSet.empty?(gaps) do + if not RangeSet.continuous?(covered) do + gaps = RangeSet.gaps(covered) {y, RangeSet.to_list(gaps)} end end) + |> Kino.render() x * 4_000_000 + y ``` +``` +{2650264, [2638485]} +``` + + + ``` 10553942650264 ``` diff --git a/2022/day16.livemd b/2022/day16.livemd new file mode 100644 index 0000000..827d88c --- /dev/null +++ b/2022/day16.livemd @@ -0,0 +1,985 @@ + + +# Day 16 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}, + {:libgraph, github: "hauleth/libgraph", ref: "perf/bellman-ford-implementation"} +]) +``` + + + +``` +:ok +``` + +## Setup + + + +```elixir +{:ok, puzzle_input} = + KinoAOC.download_puzzle("2022", "16", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) +``` + + + +``` +{:ok, + "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"} +``` + +```elixir +# puzzle_input = """ +# Valve AA has flow rate=0; tunnels lead to valves DD, II, BB +# Valve BB has flow rate=13; tunnels lead to valves CC, AA +# Valve CC has flow rate=2; tunnels lead to valves DD, BB +# Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE +# Valve EE has flow rate=3; tunnels lead to valves FF, DD +# Valve FF has flow rate=0; tunnels lead to valves EE, GG +# Valve GG has flow rate=0; tunnels lead to valves FF, HH +# Valve HH has flow rate=22; tunnel leads to valve GG +# Valve II has flow rate=0; tunnels lead to valves AA, JJ +# Valve JJ has flow rate=21; tunnel leads to valve II +# """ +``` + + + +``` +nil +``` + +```elixir +{{start, _}, valves} = + valves = + puzzle_input + |> String.split("\n", trim: true) + |> Kino.render() + |> Enum.map(fn line -> + %{ + "name" => name, + "rate" => rate, + "routes" => routes + } = + Regex.named_captures( + ~r/Valve (?..).*rate=(?\d+);.*valves? (?.*)$/, + line + ) + + {name, %{rate: String.to_integer(rate), routes: String.split(routes, ~r/,\s*/, trim: true)}} + end) + |> then(&{hd(&1), Map.new(&1)}) +``` + + + +``` +["Valve QJ has flow rate=11; tunnels lead to valves HB, GL", + "Valve VZ has flow rate=10; tunnel leads to valve NE", + "Valve TX has flow rate=19; tunnels lead to valves MG, OQ, HM", + "Valve ZI has flow rate=5; tunnels lead to valves BY, ON, RU, LF, JR", + "Valve IH has flow rate=0; tunnels lead to valves YB, QS", + "Valve QS has flow rate=22; tunnel leads to valve IH", + "Valve QB has flow rate=0; tunnels lead to valves QX, ES", + "Valve NX has flow rate=0; tunnels lead to valves UH, OP", + "Valve PJ has flow rate=0; tunnels lead to valves OC, UH", + "Valve OR has flow rate=6; tunnels lead to valves QH, BH, HB, JD", + "Valve OC has flow rate=7; tunnels lead to valves IZ, JR, TA, ZH, PJ", + "Valve UC has flow rate=0; tunnels lead to valves AA, BY", + "Valve QX has flow rate=0; tunnels lead to valves AA, QB", + "Valve IZ has flow rate=0; tunnels lead to valves OC, SX", + "Valve AG has flow rate=13; tunnels lead to valves NW, GL, SM", + "Valve ON has flow rate=0; tunnels lead to valves MO, ZI", + "Valve XT has flow rate=18; tunnels lead to valves QZ, PG", + "Valve AX has flow rate=0; tunnels lead to valves UH, MO", + "Valve JD has flow rate=0; tunnels lead to valves OR, SM", + "Valve HM has flow rate=0; tunnels lead to valves TX, QH", + "Valve LF has flow rate=0; tunnels lead to valves ZI, UH", + "Valve QH has flow rate=0; tunnels lead to valves OR, HM", + "Valve RT has flow rate=21; tunnel leads to valve PG", + "Valve NE has flow rate=0; tunnels lead to valves VZ, TA", + "Valve OQ has flow rate=0; tunnels lead to valves TX, GE", + "Valve AA has flow rate=0; tunnels lead to valves QZ, UC, OP, QX, EH", + "Valve UH has flow rate=17; tunnels lead to valves PJ, NX, AX, LF", + "Valve GE has flow rate=0; tunnels lead to valves YB, OQ", + "Valve EH has flow rate=0; tunnels lead to valves AA, MO", + "Valve MG has flow rate=0; tunnels lead to valves TX, NW", + "Valve YB has flow rate=20; tunnels lead to valves IH, GE, XG", + "Valve MO has flow rate=15; tunnels lead to valves EH, ON, AX, ZH, CB", + "Valve JR has flow rate=0; tunnels lead to valves ZI, OC", + "Valve GL has flow rate=0; tunnels lead to valves AG, QJ", + "Valve SM has flow rate=0; tunnels lead to valves JD, AG", + "Valve HB has flow rate=0; tunnels lead to valves OR, QJ", + "Valve TA has flow rate=0; tunnels lead to valves OC, NE", + "Valve PG has flow rate=0; tunnels lead to valves RT, XT", + "Valve XG has flow rate=0; tunnels lead to valves CB, YB", + "Valve ES has flow rate=9; tunnels lead to valves QB, FL", + "Valve BH has flow rate=0; tunnels lead to valves RU, OR", + "Valve FL has flow rate=0; tunnels lead to valves SX, ES", + "Valve CB has flow rate=0; tunnels lead to valves MO, XG", + "Valve QZ has flow rate=0; tunnels lead to valves AA, XT", + "Valve BY has flow rate=0; tunnels lead to valves UC, ZI", + "Valve ZH has flow rate=0; tunnels lead to valves MO, OC", + "Valve OP has flow rate=0; tunnels lead to valves NX, AA", + "Valve NW has flow rate=0; tunnels lead to valves MG, AG", + "Valve RU has flow rate=0; tunnels lead to valves ZI, BH", + "Valve SX has flow rate=16; tunnels lead to valves IZ, FL"] +``` + + + +``` +{{"QJ", %{rate: 11, routes: ["HB", "GL"]}}, + %{ + "CB" => %{rate: 0, routes: ["MO", "XG"]}, + "EH" => %{rate: 0, routes: ["AA", "MO"]}, + "YB" => %{rate: 20, routes: ["IH", "GE", "XG"]}, + "ON" => %{rate: 0, routes: ["MO", "ZI"]}, + "ES" => %{rate: 9, routes: ["QB", "FL"]}, + "XG" => %{rate: 0, routes: ["CB", "YB"]}, + "TX" => %{rate: 19, routes: ["MG", "OQ", "HM"]}, + "RT" => %{rate: 21, routes: ["PG"]}, + "GL" => %{rate: 0, routes: ["AG", "QJ"]}, + "XT" => %{rate: 18, routes: ["QZ", "PG"]}, + "BY" => %{rate: 0, routes: ["UC", "ZI"]}, + "QJ" => %{rate: 11, routes: ["HB", "GL"]}, + "QB" => %{rate: 0, routes: ["QX", "ES"]}, + "QH" => %{rate: 0, routes: ["OR", "HM"]}, + "SX" => %{rate: 16, routes: ["IZ", "FL"]}, + "ZI" => %{rate: 5, routes: ["BY", "ON", "RU", "LF", "JR"]}, + "OC" => %{rate: 7, routes: ["IZ", "JR", "TA", "ZH", "PJ"]}, + "NW" => %{rate: 0, routes: ["MG", "AG"]}, + "UH" => %{rate: 17, routes: ["PJ", "NX", "AX", "LF"]}, + "VZ" => %{rate: 10, routes: ["NE"]}, + "MO" => %{rate: 15, routes: ["EH", "ON", "AX", "ZH", "CB"]}, + "ZH" => %{rate: 0, routes: ["MO", "OC"]}, + "RU" => %{rate: 0, routes: ["ZI", "BH"]}, + "FL" => %{rate: 0, routes: ["SX", "ES"]}, + "SM" => %{rate: 0, routes: ["JD", "AG"]}, + "AA" => %{rate: 0, routes: ["QZ", "UC", "OP", "QX", "EH"]}, + "JR" => %{rate: 0, routes: ["ZI", "OC"]}, + "QS" => %{rate: 22, routes: ["IH"]}, + "AG" => %{rate: 13, routes: ["NW", "GL", "SM"]}, + "JD" => %{rate: 0, routes: ["OR", "SM"]}, + "QZ" => %{rate: 0, routes: ["AA", "XT"]}, + "MG" => %{rate: 0, routes: ["TX", "NW"]}, + "UC" => %{rate: 0, routes: ["AA", "BY"]}, + "AX" => %{rate: 0, routes: ["UH", "MO"]}, + "HM" => %{rate: 0, routes: ["TX", "QH"]}, + "LF" => %{rate: 0, routes: ["ZI", "UH"]}, + "BH" => %{rate: 0, routes: ["RU", "OR"]}, + "OR" => %{rate: 6, routes: ["QH", "BH", "HB", "JD"]}, + "GE" => %{rate: 0, routes: ["YB", "OQ"]}, + "QX" => %{rate: 0, routes: ["AA", "QB"]}, + "IZ" => %{rate: 0, routes: ["OC", "SX"]}, + "PG" => %{rate: 0, routes: ["RT", "XT"]}, + "NX" => %{rate: 0, routes: ["UH", "OP"]}, + "OP" => %{rate: 0, routes: ["NX", "AA"]}, + "TA" => %{rate: 0, routes: ["OC", ...]}, + "IH" => %{rate: 0, routes: [...]}, + "HB" => %{rate: 0, ...}, + "PJ" => %{...}, + ... + }} +``` + +```elixir +graph = Graph.new(type: :directed) + +edges = + Enum.flat_map(valves, fn {a, %{routes: routes}} -> + for b <- routes, p <- [{a, b, weight: 1}, {b, a, weight: 1}], do: p + end) + +graph = + Graph.add_edges(graph, edges) + |> Kino.render() + +paths = + for v <- Graph.vertices(graph), into: %{} do + routes = + graph + |> Graph.bellman_ford(v) + |> Enum.filter(fn {k, _} -> valves[k].rate > 0 and k != v end) + |> Map.new() + + {v, routes} + end +``` + + + +``` +#Graph "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"]> +``` + + + +``` +%{ + "CB" => %{ + "AG" => 8, + "ES" => 6, + "MO" => 1, + "OC" => 3, + "OR" => 6, + "QJ" => 8, + "QS" => 4, + "RT" => 7, + "SX" => 5, + "TX" => 5, + "UH" => 3, + "VZ" => 6, + "XT" => 5, + "YB" => 2, + "ZI" => 3 + }, + "EH" => %{ + "AG" => 9, + "ES" => 4, + "MO" => 1, + "OC" => 3, + "OR" => 6, + "QJ" => 8, + "QS" => 6, + "RT" => 5, + "SX" => 5, + "TX" => 7, + "UH" => 3, + "VZ" => 6, + "XT" => 3, + "YB" => 4, + "ZI" => 3 + }, + "YB" => %{ + "AG" => 6, + "ES" => 8, + "MO" => 3, + "OC" => 5, + "OR" => 6, + "QJ" => 8, + "QS" => 2, + "RT" => 9, + "SX" => 7, + "TX" => 3, + "UH" => 5, + "VZ" => 8, + "XT" => 7, + "ZI" => 5 + }, + "ON" => %{ + "AG" => 7, + "ES" => 6, + "MO" => 1, + "OC" => 3, + "OR" => 4, + "QJ" => 6, + "QS" => 6, + "RT" => 7, + "SX" => 5, + "TX" => 7, + "UH" => 3, + "VZ" => 6, + "XT" => 5, + "YB" => 4, + "ZI" => 1 + }, + "ES" => %{ + "AG" => 12, + "MO" => 5, + "OC" => 4, + "OR" => 9, + "QJ" => 11, + "QS" => 10, + "RT" => 7, + "SX" => 2, + "TX" => 11, + "UH" => 6, + "VZ" => 7, + "XT" => 5, + "YB" => 8, + "ZI" => 6 + }, + "XG" => %{ + "AG" => 7, + "ES" => 7, + "MO" => 2, + "OC" => 4, + "OR" => 7, + "QJ" => 9, + "QS" => 3, + "RT" => 8, + "SX" => 6, + "TX" => 4, + "UH" => 4, + "VZ" => 7, + "XT" => 6, + "YB" => 1, + "ZI" => 4 + }, + "TX" => %{ + "AG" => 3, + "ES" => 11, + "MO" => 6, + "OC" => 8, + "OR" => 3, + "QJ" => 5, + "QS" => 5, + "RT" => 12, + "SX" => 10, + "UH" => 8, + "VZ" => 11, + "XT" => 10, + "YB" => 3, + "ZI" => 6 + }, + "RT" => %{ + "AG" => 13, + "ES" => 7, + "MO" => 6, + "OC" => 8, + "OR" => 10, + "QJ" => 12, + "QS" => 11, + "SX" => 9, + "TX" => 12, + "UH" => 7, + "VZ" => 11, + "XT" => 2, + "YB" => 9, + "ZI" => 7 + }, + "GL" => %{ + "AG" => 1, + "ES" => 12, + "MO" => 8, + "OC" => 8, + "OR" => 3, + "QJ" => 1, + "QS" => 9, + "RT" => 13, + "SX" => 10, + "TX" => 4, + "UH" => 8, + "VZ" => 11, + "XT" => 11, + "YB" => 7, + "ZI" => 6 + }, + "XT" => %{ + "AG" => 11, + "ES" => 5, + "MO" => 4, + "OC" => 6, + "OR" => 8, + "QJ" => 10, + "QS" => 9, + "RT" => 2, + "SX" => 7, + "TX" => 10, + "UH" => 5, + "VZ" => 9, + "YB" => 7, + "ZI" => 5 + }, + "BY" => %{ + "AG" => 7, + "ES" => 5, + "MO" => 3, + "OC" => 3, + "OR" => 4, + "QJ" => 6, + "QS" => 8, + "RT" => 6, + "SX" => 5, + "TX" => 7, + "UH" => 3, + "VZ" => 6, + "XT" => 4, + "YB" => 6, + "ZI" => 1 + }, + "QJ" => %{ + "AG" => 2, + "ES" => 11, + "MO" => 7, + "OC" => 7, + "OR" => 2, + "QS" => 10, + "RT" => 12, + "SX" => 9, + "TX" => 5, + "UH" => 7, + "VZ" => 10, + "XT" => 10, + "YB" => 8, + "ZI" => 5 + }, + "QB" => %{ + "AG" => 11, + "ES" => 1, + "MO" => 4, + "OC" => 5, + "OR" => 8, + "QJ" => 10, + "QS" => 9, + "RT" => 6, + "SX" => 3, + "TX" => 10, + "UH" => 5, + "VZ" => 8, + "XT" => 4, + "YB" => 7, + "ZI" => 5 + }, + "QH" => %{ + "AG" => 4, + "ES" => 10, + "MO" => 6, + "OC" => 6, + "OR" => 1, + "QJ" => 3, + "QS" => 7, + "RT" => 11, + "SX" => 8, + "TX" => 2, + "UH" => 6, + "VZ" => 9, + "XT" => 9, + "YB" => 5, + "ZI" => 4 + }, + "SX" => %{ + "AG" => 10, + "ES" => 2, + "MO" => 4, + "OC" => 2, + "OR" => 7, + "QJ" => 9, + "QS" => 9, + "RT" => 9, + "TX" => 10, + "UH" => 4, + "VZ" => 5, + "XT" => 7, + "YB" => 7, + "ZI" => 4 + }, + "ZI" => %{ + "AG" => 6, + "ES" => 6, + "MO" => 2, + "OC" => 2, + "OR" => 3, + "QJ" => 5, + "QS" => 7, + "RT" => 7, + "SX" => 4, + "TX" => 6, + "UH" => 2, + "VZ" => 5, + "XT" => 5, + "YB" => 5 + }, + "OC" => %{ + "AG" => 8, + "ES" => 4, + "MO" => 2, + "OR" => 5, + "QJ" => 7, + "QS" => 7, + "RT" => 8, + "SX" => 2, + "TX" => 8, + "UH" => 2, + "VZ" => 3, + "XT" => 6, + "YB" => 5, + "ZI" => 2 + }, + "NW" => %{ + "AG" => 1, + "ES" => 13, + "MO" => 8, + "OC" => 9, + "OR" => 4, + "QJ" => 3, + "QS" => 7, + "RT" => 14, + "SX" => 11, + "TX" => 2, + "UH" => 9, + "VZ" => 12, + "XT" => 12, + "YB" => 5, + "ZI" => 7 + }, + "UH" => %{ + "AG" => 8, + "ES" => 6, + "MO" => 2, + "OC" => 2, + "OR" => 5, + "QJ" => 7, + "QS" => 7, + "RT" => 7, + "SX" => 4, + "TX" => 8, + "VZ" => 5, + "XT" => 5, + "YB" => 5, + "ZI" => 2 + }, + "VZ" => %{ + "AG" => 11, + "ES" => 7, + "MO" => 5, + "OC" => 3, + "OR" => 8, + "QJ" => 10, + "QS" => 10, + "RT" => 11, + "SX" => 5, + "TX" => 11, + "UH" => 5, + "XT" => 9, + "YB" => 8, + "ZI" => 5 + }, + "MO" => %{ + "AG" => 8, + "ES" => 5, + "OC" => 2, + "OR" => 5, + "QJ" => 7, + "QS" => 5, + "RT" => 6, + "SX" => 4, + "TX" => 6, + "UH" => 2, + "VZ" => 5, + "XT" => 4, + "YB" => 3, + "ZI" => 2 + }, + "ZH" => %{ + "AG" => 9, + "ES" => 5, + "MO" => 1, + "OC" => 1, + "OR" => 6, + "QJ" => 8, + "QS" => 6, + "RT" => 7, + "SX" => 3, + "TX" => 7, + "UH" => 3, + "VZ" => 4, + "XT" => 5, + "YB" => 4, + "ZI" => 3 + }, + "RU" => %{ + "AG" => 5, + "ES" => 7, + "MO" => 3, + "OC" => 3, + "OR" => 2, + "QJ" => 4, + "QS" => 8, + "RT" => 8, + "SX" => 5, + "TX" => 5, + "UH" => 3, + "VZ" => 6, + "XT" => 6, + "YB" => 6, + "ZI" => 1 + }, + "FL" => %{ + "AG" => 11, + "ES" => 1, + "MO" => 5, + "OC" => 3, + "OR" => 8, + "QJ" => 10, + "QS" => 10, + "RT" => 8, + "SX" => 1, + "TX" => 11, + "UH" => 5, + "VZ" => 6, + "XT" => 6, + "YB" => 8, + "ZI" => 5 + }, + "SM" => %{ + "AG" => 1, + "ES" => 11, + "MO" => 7, + "OC" => 7, + "OR" => 2, + "QJ" => 3, + "QS" => 9, + "RT" => 12, + "SX" => 9, + "TX" => 4, + "UH" => 7, + "VZ" => 10, + "XT" => 10, + "YB" => 7, + "ZI" => 5 + }, + "AA" => %{ + "AG" => 9, + "ES" => 3, + "MO" => 2, + "OC" => 4, + "OR" => 6, + "QJ" => 8, + "QS" => 7, + "RT" => 4, + "SX" => 5, + "TX" => 8, + "UH" => 3, + "VZ" => 7, + "XT" => 2, + "YB" => 5, + "ZI" => 3 + }, + "JR" => %{ + "AG" => 7, + "ES" => 5, + "MO" => 3, + "OC" => 1, + "OR" => 4, + "QJ" => 6, + "QS" => 8, + "RT" => 8, + "SX" => 3, + "TX" => 7, + "UH" => 3, + "VZ" => 4, + "XT" => 6, + "YB" => 6, + "ZI" => 1 + }, + "QS" => %{ + "AG" => 8, + "ES" => 10, + "MO" => 5, + "OC" => 7, + "OR" => 8, + "QJ" => 10, + "RT" => 11, + "SX" => 9, + "TX" => 5, + "UH" => 7, + "VZ" => 10, + "XT" => 9, + "YB" => 2, + "ZI" => 7 + }, + "AG" => %{ + "ES" => 12, + "MO" => 8, + "OC" => 8, + "OR" => 3, + "QJ" => 2, + "QS" => 8, + "RT" => 13, + "SX" => 10, + "TX" => 3, + "UH" => 8, + "VZ" => 11, + "XT" => 11, + "YB" => 6, + "ZI" => 6 + }, + "JD" => %{ + "AG" => 2, + "ES" => 10, + "MO" => 6, + "OC" => 6, + "OR" => 1, + "QJ" => 3, + "QS" => 9, + "RT" => 11, + "SX" => 8, + "TX" => 4, + "UH" => 6, + "VZ" => 9, + "XT" => 9, + "YB" => 7, + "ZI" => 4 + }, + "QZ" => %{ + "AG" => 10, + "ES" => 4, + "MO" => 3, + "OC" => 5, + "OR" => 7, + "QJ" => 9, + "QS" => 8, + "RT" => 3, + "SX" => 6, + "TX" => 9, + "UH" => 4, + "VZ" => 8, + "XT" => 1, + "YB" => 6, + "ZI" => 4 + }, + "MG" => %{ + "AG" => 2, + "ES" => 12, + "MO" => 7, + "OC" => 9, + "OR" => 4, + "QJ" => 4, + "QS" => 6, + "RT" => 13, + "SX" => 11, + "TX" => 1, + "UH" => 9, + "VZ" => 12, + "XT" => 11, + "YB" => 4, + "ZI" => 7 + }, + "UC" => %{ + "AG" => 8, + "ES" => 4, + "MO" => 3, + "OC" => 4, + "OR" => 5, + "QJ" => 7, + "QS" => 8, + "RT" => 5, + "SX" => 6, + "TX" => 8, + "UH" => 4, + "VZ" => 7, + "XT" => 3, + "YB" => 6, + "ZI" => 2 + }, + "AX" => %{ + "AG" => 9, + "ES" => 6, + "MO" => 1, + "OC" => 3, + "OR" => 6, + "QJ" => 8, + "QS" => 6, + "RT" => 7, + "SX" => 5, + "TX" => 7, + "UH" => 1, + "VZ" => 6, + "XT" => 5, + "YB" => 4, + "ZI" => 3 + }, + "HM" => %{ + "AG" => 4, + "ES" => 11, + "MO" => 7, + "OC" => 7, + "OR" => 2, + "QJ" => 4, + "QS" => 6, + "RT" => 12, + "SX" => 9, + "TX" => 1, + "UH" => 7, + "VZ" => 10, + "XT" => 10, + "YB" => 4, + "ZI" => 5 + }, + "LF" => %{ + "AG" => 7, + "ES" => 7, + "MO" => 3, + "OC" => 3, + "OR" => 4, + "QJ" => 6, + "QS" => 8, + "RT" => 8, + "SX" => 5, + "TX" => 7, + "UH" => 1, + "VZ" => 6, + "XT" => 6, + "YB" => 6, + ... + }, + "BH" => %{ + "AG" => 4, + "ES" => 8, + "MO" => 4, + "OC" => 4, + "OR" => 1, + "QJ" => 3, + "QS" => 9, + "RT" => 9, + "SX" => 6, + "TX" => 4, + "UH" => 4, + "VZ" => 7, + "XT" => 7, + ... + }, + "OR" => %{ + "AG" => 3, + "ES" => 9, + "MO" => 5, + "OC" => 5, + "QJ" => 2, + "QS" => 8, + "RT" => 10, + "SX" => 7, + "TX" => 3, + "UH" => 5, + "VZ" => 8, + "XT" => 8, + ... + }, + "GE" => %{ + "AG" => 5, + "ES" => 9, + "MO" => 4, + "OC" => 6, + "OR" => 5, + "QJ" => 7, + "QS" => 3, + "RT" => 10, + "SX" => 8, + "TX" => 2, + "UH" => 6, + ... + }, + "QX" => %{ + "AG" => 10, + "ES" => 2, + "MO" => 3, + "OC" => 5, + "OR" => 7, + "QJ" => 9, + "QS" => 8, + "RT" => 5, + "SX" => 4, + "TX" => 9, + ... + }, + "IZ" => %{ + "AG" => 9, + "ES" => 3, + "MO" => 3, + "OC" => 1, + "OR" => 6, + "QJ" => 8, + "QS" => 8, + "RT" => 9, + "SX" => 1, + ... + }, + "PG" => %{ + "AG" => 12, + "ES" => 6, + "MO" => 5, + "OC" => 7, + "OR" => 9, + "QJ" => 11, + "QS" => 10, + "RT" => 1, + ... + }, + "NX" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 3, "OR" => 6, "QJ" => 8, "QS" => 8, ...}, + "OP" => %{"AG" => 10, "ES" => 4, "MO" => 3, "OC" => 4, "OR" => 7, "QJ" => 9, ...}, + "TA" => %{"AG" => 9, "ES" => 5, "MO" => 3, "OC" => 1, "OR" => 6, ...}, + "IH" => %{"AG" => 7, "ES" => 9, "MO" => 4, "OC" => 6, ...}, + "HB" => %{"AG" => 3, "ES" => 10, "MO" => 6, ...}, + "PJ" => %{"AG" => 9, "ES" => 5, ...}, + "OQ" => %{"AG" => 4, ...}, + "NE" => %{...} +} +``` + +## Task 1 + +```elixir +defmodule Alone do + def visit(current, valves, paths, left, opened) when left >= 0 do + {left, rate, opened} = + case valves[current].rate do + 0 -> {left, 0, opened} + other -> {left - 1, other, Map.put(opened, current, left - 1)} + end + + rate = rate * left + + paths[current] + |> Enum.map(fn + {next, weight} when weight + 1 < left and not is_map_key(opened, next) -> + {val, opened} = visit(next, valves, paths, left - weight, opened) + {val + rate, opened} + + _ -> + {rate, opened} + end) + |> Enum.max_by(&elem(&1, 0)) + end +end +``` + + + +``` +{:module, Valves, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:visit, 5}} +``` + +```elixir +{t, v} = Alone.visit("AA", valves, paths, 30, %{}) +``` + + + +``` +{1820, %{"AG" => 6, "MO" => 23, "QJ" => 3, "QS" => 16, "TX" => 10, "UH" => 26, "YB" => 19}} +``` + +## Task 2 + +```elixir +defmodule Alone do + def visit(current, valves, paths, left, opened) when left >= 0 do + {left, rate, opened} = + case valves[current].rate do + 0 -> {left, 0, opened} + other -> {left - 1, other, Map.put(opened, current, left - 1)} + end + + rate = rate * left + + paths[current] + |> Enum.map(fn + {next, weight} when weight + 1 < left and not is_map_key(opened, next) -> + {val, opened} = visit(next, valves, paths, left - weight, opened) + {val + rate, opened} + + _ -> + {rate, opened} + end) + |> Enum.max_by(&elem(&1, 0)) + end +end +``` diff --git a/2022/day17.livemd b/2022/day17.livemd new file mode 100644 index 0000000..6b6ff58 --- /dev/null +++ b/2022/day17.livemd @@ -0,0 +1,188 @@ + + +# Day 17 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + + + +``` +* Getting kino_aoc (https://github.com/ljgago/kino_aoc) +remote: Enumerating objects: 103, done. +remote: Counting objects: 100% (103/103), done. +remote: Compressing objects: 100% (68/68), done. +remote: Total 103 (delta 40), reused 84 (delta 25), pack-reused 0 +origin/HEAD set to main +Resolving Hex dependencies... +Resolution completed in 0.336s +New: + castore 1.0.3 + finch 0.16.0 + hpax 0.1.2 + jason 1.4.1 + kino 0.10.0 + mime 2.0.5 + mint 1.5.1 + nimble_options 1.0.2 + nimble_pool 1.0.0 + req 0.3.10 + table 0.1.2 + telemetry 1.2.1 +* Getting kino (Hex package) +* Getting req (Hex package) +* Getting finch (Hex package) +* Getting jason (Hex package) +* Getting mime (Hex package) +* Getting castore (Hex package) +* Getting mint (Hex package) +* Getting nimble_options (Hex package) +* Getting nimble_pool (Hex package) +* Getting telemetry (Hex package) +* Getting hpax (Hex package) +* Getting table (Hex package) +==> table +Compiling 5 files (.ex) +Generated table app +==> mime +Compiling 1 file (.ex) +Generated mime app +==> nimble_options +Compiling 3 files (.ex) +Generated nimble_options app +==> kino +Compiling 41 files (.ex) +Generated kino app +===> Analyzing applications... +===> Compiling telemetry +==> jason +Compiling 10 files (.ex) +Generated jason app +==> hpax +Compiling 4 files (.ex) +Generated hpax app +==> nimble_pool +Compiling 2 files (.ex) +Generated nimble_pool app +==> castore +Compiling 1 file (.ex) +Generated castore app +==> mint +Compiling 1 file (.erl) +Compiling 19 files (.ex) +Generated mint app +==> finch +Compiling 13 files (.ex) +Generated finch app +==> req +Compiling 5 files (.ex) +Generated req app +==> kino_aoc +Compiling 3 files (.ex) +Generated kino_aoc app +``` + + + +``` +:ok +``` + +## Section + + + +```elixir +{:ok, puzzle_input} = + KinoAOC.download_puzzle("2022", "17", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) +``` + + + +``` +{:ok, + ">><<<>><<<<>>><>><>>><<<>>>><>>><<><<<>>>><<<><<<><<><<<>>>><<><<>>><<<<>><<>><<<><<<<>><<<<><>>><<<<>>><<<>>>><<<>>>><<<<>>><<>>><<>>>><<<<>>>><<<<>><>>>><<<<>>><<>><>>><>>><<<<>>><<>>><>><<<>>>><<>>>><<<>>><<<>>>><<<<><<<><<>>><>><<<<>><>><<><<<<>>><<>>><<<>>>><<<<>>><<>>>><<<<>><>><<<><<>><<<>>>><<<>><<<<>>>><<<><<<<>>><<><>>><<>><<<>>><<<<>>><<>>>><<<>>><<<<>>><<>>>><<<<>><<>>>><<<>>>><<>>><<><<<>>><<<<>>>><<<<>>><<<>>>><<<<>><<<>>>><>>><><<>>><<<><<>>>><<<>>>><<><<<<>>>><<<><<>><<<<>>>><<>>><>>>><<<<>><<>>><<>>><<>><>><><<<<>>>><<<>><<>>><<><<<<>>>><<<<><<<<>>>><><<>>><><>>><<>>><>>><>>>><<>><><<>><>>><<>>>><<>>>><<<<><<<>>>><>><>>>><<<<><<<><<<>>>><<><<>><<<>>><<<<>>><<<<><<>>><<<>>>><<><<<<>><<<<>><<<><>><>>>><><<<>>><<<<><<<<>><>>><<<>><<<<><<<>>>><<<>>>><<<>><<>><<<<>><<<<>><>>>><<>>>><<<<>>><<>>>><<>>>><>><<<>>>><<<<>>><<<<><>>>><<><<<>><<<<>>>><<<<>><>>>><<<>>>><<<<>>>><<<<>>><<<<>><>>><<<<><>>>><<><>>>><>><<>>>><>>>><<>><<>>><<<>>>><<><<<>>>><<><<>><<<<>>><<<>>><<<<>><<<><<<>>><<><<>>>><<<>>><<>>><<<><<<<>>><>>>><<<>>><<<>>>><<><><<>>>><<>>>><<>>>><<>>><<>><<><<<>>><>>><<<<>>>><>>>><<<>><>><<<<>>><<<<>>><<>>><<<<><<<>>><>>>><<>><<<<>><<<<>><<<<><>><<<<>>>><<>>><>><<<>><<>><<<<>><<>>><<<<>>><<<<>>><<><<<>>><<><<<><<>>>><>><<><<<<><<>><<<>>>><><<<<><><><>>><<<>>><<>>><<<>>>><<><<>><<>><<<><<<<>>>><>>>><<>>>><<<>>>><<>>>><<<>><>><<<>>><<>>>><<><<>>>><<<><<<<>>><<<>>>><<<>>><<<><>>><<>>><<<>>>><<<>>>><<<>>>><<<>><>><<<>>><<<<>>>><><<<>>>><<>>>><><>>><<>>>><<>><<>>>><<<>><<<>>>><<>>>><<<<>><<<>><<<>><<>><<<>>><<><>>><<><<><>>>><<<>>>><<<<>><<>>>><<<<>><><<<>>><<<<>><<>>><<<>><<>><<>><>>>><<><<>>>><>>>><<><><<<><<<<>>>><<<<>><<><<><<>>>><>>><<<><<<<><<>><<<><<>><><<><<<>>>><>>>><<>>>><>><><><<<><<><<>>><<<<><<>><<<>>>><<><<<<>>>><<<<>><><<<<>><<>><>><<<<>>>><<>>>><<<<><<<>><<>>><<<>>><>>><<>>>><<<><<<<><<>>>><<<<>><<<>>>><<<>><<<<><<<>><<<<>><<<>>>><<>>>><><>>><>>><<<>>>><<>>><<<>><>>>><<<>>>><<<<><<<>>><<<<>><<>><<>><<<><<<<>>><><>><<<><<<>>><<<><<<<>>>><><<<<>><<>><>>><<<>>>><<>>><<<>><<<<>>><<<>><<>><<>><<<<><<>>><>><<>>><<><<<><<<>><<<<>>><>><><<<<>>>><<<><<<>><>><<>>>><<<>>>><<<><<<>>><<>>><><>><<<>><>>>><<<<>>>><<<<>>><<<<>>><<<<>><<<<><><<>><>><<>>><<>><<><<<<>>>><<<<>>>><<>>>><<<<>>>><<>>>><>>>><<>><<><<<><><>><<<><<<<>>>><<<<>><<<>>>><<<<>>>><>>>><><<<<>><>>><<<<><<>>>><>><<<<>><<<><<<>>>><<>><<>>><>>>><<><>>>><<<<><<><<<>>>><<<>>>><<><>><<<>><<<>><<<<><<>>><>><<>>><<>>><>>>><<<>>><<>><<><><<>>>><<<>>><<<>><<<>>><<<>>>><<>>><>>>><>>>><>>><<>>>><<<>><<<<>><<<<>><<>>>><><>>>><<>>>><<<><<<<><<>>>><<<<>><<<<>>>><><<<><>><<<<>>>><>>>><<<<>>>><<><>><<<<><<<>>><<<<>><>><>>>><<>>>><>>><>>>><>><<>>><<<><>><>>>><<<>><<<>><<<<><<<<>>><<<>>><<<>>>><>><>>><<<<>><<<><<>>><>>><<><>>>><<<>>>><<<<>>>><><<<>>><<<<>>><>><>>>><<<>><<>>>><>>><<<<>>>><<<>><<<>>>><<<<>><<<>>><<<<><<<<>>>><><<<>>><<<<>>>><<<<>><<>><<<>>><>>><>><<>>><<<>><><<><>><<>><>><<<><<<<>>><<<>><<<><<<>>>><<>>><<<<><<><<<>>><<<<>>><<>><>>><>>><<<><<>>>><<<>><<<<><<<>><<<<>><>><<>><>>>><>>>><<>>><<<<>>><><><><<<>>><<<>><<>>><<<<>>>><>><<<>>>><<>><<<<>><<>><>><<<>>>><>>><<<<>>><>><<>>><<<>><<<<>>>><<<>><<>><>><<<<>><<<><<<>><>><<<><<<>>>><<<<>>><<><<<<><<<<>>>><<<><>><<><>>><<<><<><<<<>>><<>>>><>><<<<>><<<<>>><<>>>><>>><<<>>><<<>>>><<>>><>>>><<<<><>><<>>>><<<>>><>>><>><<<>>>><<><<<>>>><<><<<<>>>><<<<>>>><><<<<>>>><<<>>>><<><<<>>>><<>><>><>>><<<<><<<>>>><<<<>>>><<<><<>>>><<<><>>>><<<<>>>><>>><<<>><<<<><<>>><<>>><<>>><>>><<<><><><<<>>>><<>>>><<<<><>>>><<<>><<>>>><<><<<<><<<<>><><<<<><<>>>><<<>><<<<>><<>><<><<>>>><<><<<><<<<><<<<>>><<<>>>><<<<>>><><<<>>><>>>><>>><<<<>>><<<>>><<<<><<<<><<>><><<<>>><>>><<><<><<>><<<<>>>><<<>><<<><<<<>>><<<<>>><<>><<<<>><>>>><>><<<><>>>><<<>>><<><<>><<<><<<>><<<<>><<<<>><<<<><>>>><<><<<>><<<><<<>><<<<><<>>>><<<>><<<><<<>>><<<><<<<>>>><<>>>><<<>><<<<>>><<><<<<>>>><<<<>>>><<>><<><<>>><<>>>><<>>><<>>><<<>>>><<>>><<><<>>><<<>><<<<>>><<>>><<<>>><<<>>><>>>><<<>>>><<<<>>>><>>>><<<>>>><<<>>>><>>>><>>>><<<><<>><><>><<>><><<<>>>><><>>>><><<<><>>><<<>>><<<>>><<<<>><<<<><<<>>><<>><<<<>>><<<>><<>>>><<><<<<>>><>><<<>>>><<>><<<<>>><<<<>>><>>>><<>" <> ...} +``` + +```elixir +well = [0, 0, 0, 0, 0, 0, 0] +``` + + + +``` +[0, 0, 0, 0, 0, 0, 0] +``` + +```elixir +defmodule Tetris do + def fit(well, n, :dash) when n in 0..3 do + max = + well + |> Enum.drop(n) + |> Enum.take(4) + |> Enum.max() + + well + |> List.replace_at(n, max + 1) + |> List.replace_at(n + 1, max + 1) + |> List.replace_at(n + 2, max + 1) + |> List.replace_at(n + 3, max + 1) + end + + def fit(well, n, :plus) when n in 0..4 do + bottom = + well + |> Enum.drop(n) + |> Enum.take(3) + |> case do + [a, b, c] when b < a and b < c -> max(a, b) - 1 + [_, b, _] -> b + end + + well + |> List.replace_at(n, bottom + 2) + |> List.replace_at(n + 1, bottom + 3) + |> List.replace_at(n + 2, bottom + 2) + end + + def fit(well, n, :l), do: well + + def fit(well, n, :i), do: well + + def fit(well, n, :o), do: well +end +``` + + + +``` +warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:32: Tetris.fit/3 + +warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:34: Tetris.fit/3 + +warning: variable "n" is unused (if the variable is not meant to be used, prefix it with an underscore) + 2022/day17.livemd#cell:yqwk3yzwldnf4hstvs2cj6qm5r3go5yp:36: Tetris.fit/3 + +``` + + + +``` +{:module, Tetris, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:fit, 3}} +``` + +```elixir +Tetris.fit([2, 1, 2, 0, 0, 0, 0], 0, :plus) +``` + + + +``` +[3, 4, 3, 0, 0, 0, 0] +``` diff --git a/2022/day18.livemd b/2022/day18.livemd new file mode 100644 index 0000000..9a96baf --- /dev/null +++ b/2022/day18.livemd @@ -0,0 +1,266 @@ + + +# Day 18 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + + + +``` +:ok +``` + +## Section + + + +```elixir +{:ok, puzzle_input} = + KinoAOC.download_puzzle("2022", "18", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) +``` + + + +``` +{:ok, + "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" <> ...} +``` + +```elixir +cubes = + puzzle_input + |> String.split("\n", trim: true) + |> Enum.map(fn line -> + line + |> String.split(",") + |> Enum.map(&String.to_integer/1) + |> List.to_tuple() + end) + |> MapSet.new() +``` + + + +``` +MapSet.new([ + {12, 9, 18}, + {11, 4, 5}, + {2, 10, 6}, + {12, 2, 8}, + {14, 15, 15}, + {5, 14, 12}, + {10, 6, 18}, + {6, 4, 6}, + {11, 4, 3}, + {6, 14, 3}, + {4, 8, 4}, + {17, 7, 9}, + {7, 12, 16}, + {14, 13, 3}, + {12, 3, 16}, + {13, 6, 2}, + {5, 6, 5}, + {17, 10, 11}, + {4, 16, 9}, + {17, 9, 9}, + {6, 2, 10}, + {13, 17, 13}, + {12, 13, 3}, + {3, 13, 7}, + {13, 7, 4}, + {17, 12, 7}, + {7, 3, 13}, + {12, 15, 15}, + {15, 6, 4}, + {17, 10, 8}, + {9, 14, 13}, + {3, 9, 4}, + {14, 13, 9}, + {15, 13, 4}, + {13, 4, 15}, + {7, 7, 15}, + {6, 14, 8}, + {11, 2, 16}, + {7, 2, 8}, + {3, 14, 13}, + {4, 5, 6}, + {3, 9, 14}, + {4, 16, 12}, + {14, 12, 12}, + {14, 5, 15}, + {17, 9, 12}, + {15, 10, 15}, + {8, 17, ...}, + {2, ...}, + {...}, + ... +]) +``` + +## Task 1 + +```elixir +sides = + for {x, y, z} <- cubes, + {place, {dx, dy, dz}} <- [ + x: {-1, 0, 0}, + y: {0, -1, 0}, + z: {0, 0, -1}, + x: {0, 0, 0}, + y: {0, 0, 0}, + z: {0, 0, 0} + ], + reduce: MapSet.new() do + set -> + side = {place, {x + dx, y + dy, z + dz}} + + if side in set do + MapSet.delete(set, side) + else + MapSet.put(set, side) + end + end + +MapSet.size(sides) +``` + + + +``` +3636 +``` + +## Task 2 + +```elixir +max = + Enum.reduce(cubes, {0, 0, 0}, fn {x, y, z}, {mx, my, mz} -> + {max(x, mx), max(y, my), max(z, mz)} + end) +``` + + + +``` +{19, 19, 19} +``` + +```elixir +defmodule Cave do + def bfs([], _sides, outer, _visited), do: outer + + def bfs([{x, y, z} = p | queue], sides, outer, visited) do + {min, max} = Enum.min_max([x, y, z]) + + if p in visited or max > 25 or min < -5 do + bfs(queue, sides, outer, visited) + else + visited = MapSet.put(visited, p) + + {outer, xs1} = check(:x, p, {x + 1, y, z}, sides, outer, visited) + {outer, xs2} = check(:x, {x - 1, y, z}, {x - 1, y, z}, sides, outer, visited) + {outer, ys1} = check(:y, p, {x, y + 1, z}, sides, outer, visited) + {outer, ys2} = check(:y, {x, y - 1, z}, {x, y - 1, z}, sides, outer, visited) + {outer, zs1} = check(:z, p, {x, y, z + 1}, sides, outer, visited) + {outer, zs2} = check(:z, {x, y, z - 1}, {x, y, z - 1}, sides, outer, visited) + + bfs(queue ++ xs1 ++ xs2 ++ ys1 ++ ys2 ++ zs1 ++ zs2, sides, outer, visited) + end + end + + defp check(axis, curr, next, sides, outer, visited) do + cond do + {axis, curr} in sides -> + {MapSet.put(outer, {axis, curr}), []} + + next in visited -> + {outer, []} + + true -> + {outer, [next]} + end + end +end +``` + + + +``` +{:module, Cave, <<70, 79, 82, 49, 0, 0, 14, ...>>, {:check, 6}} +``` + +```elixir +outer = Cave.bfs([{-5, -5, -5}], sides, MapSet.new(), MapSet.new()) +``` + + + +``` +MapSet.new([ + x: {10, 19, 11}, + z: {15, 16, 12}, + z: {2, 16, 10}, + z: {5, 13, 2}, + y: {4, 3, 15}, + x: {0, 13, 10}, + x: {17, 12, 6}, + z: {10, 11, 0}, + z: {10, 5, 17}, + z: {4, 7, 2}, + x: {15, 16, 9}, + x: {2, 7, 4}, + z: {2, 8, 5}, + y: {16, 13, 5}, + x: {2, 6, 14}, + x: {18, 12, 11}, + y: {13, 17, 7}, + z: {3, 9, 14}, + y: {11, 3, 16}, + x: {4, 10, 17}, + y: {11, 2, 15}, + z: {13, 4, 3}, + x: {10, 17, 5}, + y: {3, 12, 4}, + y: {11, 18, 10}, + z: {5, 17, 8}, + y: {15, 16, 6}, + y: {3, 3, 7}, + z: {7, 1, 5}, + x: {14, 2, 9}, + y: {18, 5, 8}, + x: {10, 1, 13}, + x: {9, 16, 3}, + x: {2, 15, 8}, + y: {7, 4, 2}, + x: {17, 6, 12}, + x: {0, 9, 7}, + x: {12, 8, 1}, + x: {0, 11, 10}, + z: {10, 16, 3}, + x: {16, 5, 6}, + z: {5, 10, 1}, + z: {7, 4, 15}, + z: {12, 11, 18}, + y: {11, 17, 12}, + z: {3, 5, 4}, + z: {6, 1, 9}, + x: {16, 8, ...}, + z: {14, ...}, + z: {...}, + ... +]) +``` + +```elixir +MapSet.size(outer) +``` + + + +``` +2102 +``` diff --git a/2022/day19.livemd b/2022/day19.livemd new file mode 100644 index 0000000..0b8bfbe --- /dev/null +++ b/2022/day19.livemd @@ -0,0 +1,230 @@ + + +# Day 19 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + + + +``` +:ok +``` + +## Section + + + +```elixir +{:ok, puzzle_input} = + KinoAOC.download_puzzle("2022", "19", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) +``` + + + +``` +{:ok, + "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 " <> ...} +``` + +```elixir +puzzle_input = """ +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. +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. +""" +``` + + + +``` +"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" +``` + +```elixir +regex = + ~r/ore robot.*(?\d+) ore.*clay robot.*(?\d+) ore.*obsidian robot.*(?\d+) ore and (?\d+) clay.*geode robot.*(?\d+) ore and (?\d+) obsidian/ + +plans = + puzzle_input + |> String.split("\n", trim: true) + |> Kino.render() + |> Enum.map(fn line -> + blueprint = + Regex.named_captures(regex, line) + |> Map.new(fn {k, v} -> + {String.to_atom(k), String.to_integer(v)} + end) + + %{ + ore: %{ore: blueprint.ore_ore}, + clay: %{ore: blueprint.clay_ore}, + obsidian: %{ore: blueprint.obsidian_ore, clay: blueprint.obsidian_clay}, + geode: %{ore: blueprint.geode_ore, obsidian: blueprint.geode_obsidian}, + max: %{ + ore: + Enum.max([ + blueprint.ore_ore, + blueprint.clay_ore, + blueprint.obsidian_ore, + blueprint.geode_ore + ]), + clay: blueprint.obsidian_clay, + obsidian: blueprint.geode_obsidian + } + } + end) +``` + + + +``` +["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.", + "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."] +``` + + + +``` +[ + %{ + clay: %{ore: 2}, + geode: %{obsidian: 7, ore: 2}, + max: %{clay: 14, obsidian: 7, ore: 4}, + obsidian: %{clay: 14, ore: 3}, + ore: %{ore: 4} + }, + %{ + clay: %{ore: 3}, + geode: %{obsidian: 12, ore: 3}, + max: %{clay: 8, obsidian: 12, ore: 3}, + obsidian: %{clay: 8, ore: 3}, + ore: %{ore: 2} + } +] +``` + +```elixir +defmodule Blueprint do + def produce(plan, time, machines) do + produce(plan, time, machines, %{ore: 0, clay: 0, obsidian: 0, geode: 0}) + end + + def produce(_plan, 0, machines, stash) do + %{machines: machines, stash: stash} + end + + def produce(plan, time_left, machines, stash) do + do_shopping(plan, stash) + |> Enum.filter(fn {k, _} -> (machines[k] || 0) < plan.max[k] end) + |> Enum.flat_map(fn {machine, new_stash} -> + # if machine in [:obsidian, :geode], do: IO.inspect(new_stash) + [ + produce( + plan, + time_left - 1, + add_machine(machine, machines), + update_stash(machines, new_stash) + ) + ] + end) + # |> tap(fn list -> + # Enum.filter(list, & &1.obsidian > 0) + # |> Enum.map(&IO.inspect/1) + # end) + |> Enum.max_by(& &1.stash.geode) + end + + defp add_machine(nil, machines), do: machines + defp add_machine(name, machines), do: Map.update(machines, name, 1, &(&1 + 1)) + + defp update_stash(machines, stash) do + Enum.reduce(machines, stash, fn {k, v}, acc -> + Map.update(acc, k, v, &(&1 + v)) + end) + end + + def do_shopping(plan, stash) + when stash.ore >= plan.geode.ore and stash.obsidian >= plan.geode.obsidian, + do: [{:geode, buy(plan.geode, stash)}] + + def do_shopping(plan, stash) + when stash.ore >= plan.obsidian.ore and stash.clay >= plan.obsidian.clay, + do: [{:obsidian, buy(plan.obsidian, stash)}, {nil, stash}] + + def do_shopping(plan, stash) do + [ + {nil, stash} + | Enum.flat_map([:ore, :clay], fn k -> + if stash.ore >= plan[k].ore do + [{k, %{stash | ore: stash.ore - plan[k].ore}}] + else + [] + end + end) + ] + end + + defp buy(price, stash) do + Map.merge(stash, price, fn _k, v1, v2 -> v1 - v2 end) + end +end +``` + + + +``` +{:module, Blueprint, <<70, 79, 82, 49, 0, 0, 22, ...>>, {:buy, 2}} +``` + +```elixir +plan = hd(plans) |> Kino.inspect() +stash = %{clay: 35, geode: 0, obsidian: 0, ore: 4} + +Blueprint.do_shopping(plan, stash) +``` + + + +``` +%{ + clay: %{ore: 2}, + geode: %{obsidian: 7, ore: 2}, + max: %{clay: 14, obsidian: 7, ore: 4}, + obsidian: %{clay: 14, ore: 3}, + ore: %{ore: 4} +} +``` + + + +``` +[ + obsidian: %{clay: 21, geode: 0, obsidian: 0, ore: 1}, + nil: %{clay: 35, geode: 0, obsidian: 0, ore: 4} +] +``` + +```elixir +plans +# |> Enum.drop(1) +|> Enum.take(1) +|> Kino.inspect() +|> Enum.map(fn plan -> Blueprint.produce(plan, 24, %{ore: 1}) end) +``` + + + +``` +[ + %{ + clay: %{ore: 2}, + geode: %{obsidian: 7, ore: 2}, + max: %{clay: 14, obsidian: 7, ore: 4}, + obsidian: %{clay: 14, ore: 3}, + ore: %{ore: 4} + } +] +``` diff --git a/2022/day20.livemd b/2022/day20.livemd new file mode 100644 index 0000000..99a0725 --- /dev/null +++ b/2022/day20.livemd @@ -0,0 +1,15 @@ + + +# Day 20 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + +## Section + +```elixir + +``` diff --git a/2022/day21.livemd b/2022/day21.livemd index 738fb0e..3fa4aa7 100644 --- a/2022/day21.livemd +++ b/2022/day21.livemd @@ -10,13 +10,90 @@ Mix.install([ +``` +* Getting kino_aoc (https://github.com/ljgago/kino_aoc) +remote: Enumerating objects: 78, done. +remote: Counting objects: 100% (78/78), done. +remote: Compressing objects: 100% (50/50), done. +remote: Total 78 (delta 25), reused 67 (delta 18), pack-reused 0 +origin/HEAD set to main +Resolving Hex dependencies... +Dependency resolution completed: +New: + castore 0.1.20 + finch 0.14.0 + hpax 0.1.2 + jason 1.4.0 + kino 0.8.0 + mime 2.0.3 + mint 1.4.2 + nimble_options 0.5.2 + nimble_pool 0.2.6 + req 0.3.4 + table 0.1.2 + telemetry 1.2.0 +* Getting kino (Hex package) +* Getting req (Hex package) +* Getting finch (Hex package) +* Getting jason (Hex package) +* Getting mime (Hex package) +* Getting castore (Hex package) +* Getting mint (Hex package) +* Getting nimble_options (Hex package) +* Getting nimble_pool (Hex package) +* Getting telemetry (Hex package) +* Getting hpax (Hex package) +* Getting table (Hex package) +==> table +Compiling 5 files (.ex) +Generated table app +==> mime +Compiling 1 file (.ex) +Generated mime app +==> nimble_options +Compiling 3 files (.ex) +Generated nimble_options app +==> kino +Compiling 37 files (.ex) +Generated kino app +===> Analyzing applications... +===> Compiling telemetry +==> jason +Compiling 10 files (.ex) +Generated jason app +==> hpax +Compiling 4 files (.ex) +Generated hpax app +==> nimble_pool +Compiling 2 files (.ex) +Generated nimble_pool app +==> castore +Compiling 1 file (.ex) +Generated castore app +==> mint +Compiling 1 file (.erl) +Compiling 19 files (.ex) +Generated mint app +==> finch +Compiling 13 files (.ex) +Generated finch app +==> req +Compiling 5 files (.ex) +Generated req app +==> kino_aoc +Compiling 3 files (.ex) +Generated kino_aoc app +``` + + + ``` :ok ``` ## Section - + ```elixir {:ok, puzzle_input} = diff --git a/2022/day22.livemd b/2022/day22.livemd new file mode 100644 index 0000000..7d21008 --- /dev/null +++ b/2022/day22.livemd @@ -0,0 +1,15 @@ + + +# Day 22 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + +## Section + +```elixir + +``` diff --git a/2022/day23.livemd b/2022/day23.livemd new file mode 100644 index 0000000..6f49445 --- /dev/null +++ b/2022/day23.livemd @@ -0,0 +1,15 @@ + + +# Day 23 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + +## Section + +```elixir + +``` diff --git a/2022/day24.livemd b/2022/day24.livemd new file mode 100644 index 0000000..2d6982a --- /dev/null +++ b/2022/day24.livemd @@ -0,0 +1,15 @@ + + +# Day 24 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + +## Section + +```elixir + +``` diff --git a/2022/day25.livemd b/2022/day25.livemd new file mode 100644 index 0000000..87201a4 --- /dev/null +++ b/2022/day25.livemd @@ -0,0 +1,15 @@ + + +# Day 25 + +```elixir +Mix.install([ + {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"} +]) +``` + +## Section + +```elixir + +```