this repo has no description
1<!-- 2 vim:ft=markdown --!> 3 livebook:{"persist_outputs":true} 4--> 5 6<!-- livebook:{"persist_outputs":true} --> 7 8# Advent of Code 2021 9 10## Setup 11 12```elixir 13Mix.install([ 14 {:nx, github: "elixir-nx/nx", sparse: "nx"}, 15 {:kino, github: "livebook-dev/kino"} 16]) 17``` 18 19```output 20:ok 21``` 22 23## Day 1 24 25### Load input 26 27```elixir 28stream = 29 File.stream!("day1.txt") 30 |> Stream.map(&String.to_integer(String.trim(&1))) 31``` 32 33```output 34#Stream<[ 35 enum: %File.Stream{ 36 line_or_bytes: :line, 37 modes: [:raw, :read_ahead, :binary], 38 path: "day1.txt", 39 raw: true 40 }, 41 funs: [#Function<47.58486609/1 in Stream.map/2>] 42]> 43``` 44 45### Task 1 46 47<!-- livebook:{"break_markdown":true} --> 48 49Compute count of consecutive increases 50 51```elixir 52stream 53|> Stream.chunk_every(2, 1, :discard) 54|> Enum.count(fn [a, b] -> a < b end) 55``` 56 57```output 581688 59``` 60 61### Task 2 62 63<!-- livebook:{"break_markdown":true} --> 64 65Compute count of consecutive increases of sums of trigrams. 66 67However we can notice, that if we have list like: 68 69$$ 70[a, b, c, d] 71$$ 72 73Then when we want to compare consecutive trigrams then we compare: 74 75$$ 76a + b + c < b + c + d \\ 77a < d 78$$ 79 80So we can traverse each 4 elements and then just compare first and last one 81instead of summing and then traversing it again. 82 83```elixir 84stream 85|> Stream.chunk_every(4, 1, :discard) 86|> Enum.count(fn [a, _, _, b] -> a < b end) 87``` 88 89```output 901728 91``` 92 93## Day 2 94 95### Load input 96 97We do parsing there, as it will help us with the latter tasks. Pattern matching 98is the simplest approach there, as input is in form of: 99 100``` 101forward 10 102up 20 103down 30 104``` 105 106We need to `trim/1` input to make sure that the last newline will not interrupt 107`String.to_integer/1` calls. 108 109```elixir 110stream = 111 File.stream!("day2.txt") 112 |> Stream.map(fn input -> 113 case String.trim(input) do 114 "forward " <> n -> {:forward, String.to_integer(n)} 115 "up " <> n -> {:up, String.to_integer(n)} 116 "down " <> n -> {:down, String.to_integer(n)} 117 end 118 end) 119``` 120 121```output 122#Stream<[ 123 enum: %File.Stream{ 124 line_or_bytes: :line, 125 modes: [:raw, :read_ahead, :binary], 126 path: "day2.txt", 127 raw: true 128 }, 129 funs: [#Function<47.58486609/1 in Stream.map/2>] 130]> 131``` 132 133### Task 1 134 135```elixir 136{h, d} = 137 stream 138 |> Enum.reduce({0, 0}, fn 139 {:forward, n}, {h, d} -> {h + n, d} 140 {:up, n}, {h, d} -> {h, d - n} 141 {:down, n}, {h, d} -> {h, d + n} 142 end) 143 144h * d 145``` 146 147```output 1481499229 149``` 150 151### Task 2 152 153```elixir 154{h, d, _} = 155 stream 156 |> Enum.reduce({0, 0, 0}, fn 157 {:forward, n}, {h, d, a} -> {h + n, d + a * n, a} 158 {:up, n}, {h, d, a} -> {h, d, a - n} 159 {:down, n}, {h, d, a} -> {h, d, a + n} 160 end) 161 162h * d 163``` 164 165```output 1661340836560 167``` 168 169## Day 3 170 171### Input 172 173```elixir 174stream = 175 File.stream!("day3.txt") 176 |> Enum.map(&String.trim/1) 177 |> Enum.map(&String.to_charlist/1) 178 179defmodule Day3 do 180 def count(list) do 181 Enum.reduce(list, List.duplicate(0, 12), fn input, acc -> 182 for {value, counter} <- Enum.zip(input, acc) do 183 case value do 184 ?1 -> counter + 1 185 ?0 -> counter 186 end 187 end 188 end) 189 end 190end 191``` 192 193```output 194{:module, Day3, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:count, 1}} 195``` 196 197### Task 1 198 199```elixir 200half = div(length(stream), 2) 201 202{a, b} = 203 stream 204 |> Day3.count() 205 |> Enum.reduce({0, 0}, fn elem, {a, b} -> 206 if elem > half do 207 {a * 2 + 1, b * 2} 208 else 209 {a * 2, b * 2 + 1} 210 end 211 end) 212 213a * b 214``` 215 216```output 2173847100 218``` 219 220### Task 2 221 222```elixir 223defmodule Day3.Task2 do 224 def reduce(list, cb), do: reduce(list, 0, cb) 225 226 defp reduce([elem], _, _), do: elem 227 228 defp reduce(list, at, cb) do 229 counts = Day3.count(list) 230 231 half = div(length(list), 2) 232 count = Enum.at(counts, at) 233 234 bit = 235 cond do 236 count == half and cb.(count + 1, half) -> ?1 237 count != half and cb.(count, half) -> ?1 238 true -> ?0 239 end 240 241 reduce(Enum.filter(list, &(Enum.at(&1, at) == bit)), at + 1, cb) 242 end 243end 244 245co2 = List.to_integer(Day3.Task2.reduce(stream, &</2), 2) 246o2 = List.to_integer(Day3.Task2.reduce(stream, &>/2), 2) 247 248co2 * o2 249``` 250 251```output 2524105235 253``` 254 255## Day 4 256 257### Input 258 259This time it is a little bit more convoluted, as there are 2 parts of the input. 260Fortunately we can easily disect the parts via pattern matching. 261 262Technically the conversion to the numbers is not needed, but it does no harm 263and provides additional layer of safety against some whitespace characters left there 264and here. 265 266The `Day4.win/2` function is manually unrolled, as it is easier to write than some 267random jumping in the list. 268 269<!-- livebook:{"disable_formatting":true} --> 270 271```elixir 272[numbers | bingos] = 273 File.read!("day4.txt") 274 |> String.split("\n\n", trim: true) 275 276numbers = 277 numbers 278 |> String.trim() 279 |> String.split(",") 280 |> Enum.map(&String.to_integer/1) 281 282bingos = 283 bingos 284 |> Enum.map(fn bingo -> 285 bingo 286 |> String.split(~r/\s+/, trim: true) 287 |> Enum.map(&String.to_integer/1) 288 end) 289 290defmodule Day4 do 291 def win( 292 [ 293 a1, a2, a3, a4, a5, 294 b1, b2, b3, b4, b5, 295 c1, c2, c3, c4, c5, 296 d1, d2, d3, d4, d5, 297 e1, e2, e3, e4, e5 298 ], 299 nums 300 ) do 301 # Rows 302 all_in([a1, a2, a3, a4, a5], nums) or 303 all_in([b1, b3, b3, b4, b5], nums) or 304 all_in([c1, c2, c3, c4, c5], nums) or 305 all_in([d1, d2, d3, d4, d5], nums) or 306 all_in([e1, e2, e3, e4, e5], nums) or 307 # Columns 308 all_in([a1, b1, c1, d1, e1], nums) or 309 all_in([a2, b2, c2, d2, e2], nums) or 310 all_in([a3, b3, c3, d3, e3], nums) or 311 all_in([a4, b4, c4, d4, e4], nums) or 312 all_in([a5, b5, c5, d5, e5], nums) 313 end 314 315 def not_matched(bingo, nums) do 316 Enum.reject(bingo, &(&1 in nums)) 317 end 318 319 defp all_in(list, nums) do 320 Enum.all?(list, &(&1 in nums)) 321 end 322end 323``` 324 325```output 326{:module, Day4, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:all_in, 2}} 327``` 328 329### Task 1 330 331We simply traverse the `numbers` list aggregating the numbers (order doesn't really matter, 332here we aggregate them in reverse order to speedup the code). When we have enough numbers 333that any of the `bingos` is winning one, then we halt the reduction and return computed 334result. 335 336```elixir 337numbers 338|> Enum.reduce_while([], fn elem, acc -> 339 matches = [elem | acc] 340 341 case Enum.find(bingos, &Day4.win(&1, matches)) do 342 nil -> {:cont, matches} 343 bingo -> {:halt, Enum.sum(Day4.not_matched(bingo, matches)) * elem} 344 end 345end) 346``` 347 348```output 34934506 350``` 351 352### Task 2 353 354```elixir 355numbers 356|> Enum.reduce_while({bingos, []}, fn elem, {bingos, acc} -> 357 matches = [elem | acc] 358 359 case bingos do 360 [bingo] -> 361 if Day4.win(bingo, matches) do 362 {:halt, Enum.sum(Day4.not_matched(bingo, matches)) * elem} 363 else 364 {:cont, {bingos, matches}} 365 end 366 367 _ -> 368 {:cont, {Enum.reject(bingos, &Day4.win(&1, matches)), matches}} 369 end 370end) 371``` 372 373```output 3747686 375``` 376 377## Day 5 378 379```elixir 380defmodule Day5 do 381 defmodule Point do 382 defstruct [:x, :y] 383 384 def parse(input) do 385 [x, y] = String.split(input, ",") 386 387 %__MODULE__{x: String.to_integer(x), y: String.to_integer(y)} 388 end 389 end 390 391 defmodule Line do 392 defstruct [:start, :finish] 393 394 def new(a, b) do 395 {start, finish} = 396 cond do 397 a.x < b.x -> {a, b} 398 a.y < b.y -> {a, b} 399 true -> {b, a} 400 end 401 402 %__MODULE__{start: start, finish: finish} 403 end 404 405 def horizontal?(a), do: a.start.y == a.finish.y 406 def vertical?(a), do: a.start.x == a.finish.x 407 408 def points(a) do 409 case {sign(a.finish.x - a.start.x), sign(a.finish.y - a.start.y)} do 410 {0, dy} -> for y <- a.start.y..a.finish.y//dy, do: {a.start.x, y} 411 {dx, 0} -> for x <- a.start.x..a.finish.x//dx, do: {x, a.start.y} 412 {dx, dy} -> Enum.zip(a.start.x..a.finish.x//dx, a.start.y..a.finish.y//dy) 413 end 414 end 415 416 def orientation(a) do 417 cond do 418 horizontal?(a) -> :horizontal 419 vertical?(a) -> :vertical 420 true -> :diagonal 421 end 422 end 423 424 defp sign(0), do: 0 425 defp sign(x) when x < 0, do: -1 426 defp sign(x) when x > 0, do: 1 427 end 428end 429 430lines = 431 File.stream!("day5.txt") 432 |> Stream.map(&String.trim/1) 433 |> Stream.map(fn input -> 434 [a, b] = String.split(input, " -> ") 435 436 pa = Day5.Point.parse(a) 437 pb = Day5.Point.parse(b) 438 439 Day5.Line.new(pa, pb) 440 end) 441``` 442 443```output 444#Stream<[ 445 enum: %File.Stream{ 446 line_or_bytes: :line, 447 modes: [:raw, :read_ahead, :binary], 448 path: "day5.txt", 449 raw: true 450 }, 451 funs: [#Function<47.58486609/1 in Stream.map/2>, #Function<47.58486609/1 in Stream.map/2>] 452]> 453``` 454 455### Task 1 456 457```elixir 458lines 459|> Stream.filter(&(Day5.Line.orientation(&1) != :diagonal)) 460|> Stream.flat_map(&Day5.Line.points/1) 461|> Enum.frequencies() 462|> Enum.count(fn {_k, v} -> v > 1 end) 463``` 464 465```output 4665197 467``` 468 469### Task 2 470 471```elixir 472lines 473|> Stream.flat_map(&Day5.Line.points/1) 474|> Enum.frequencies() 475|> Enum.count(fn {_k, v} -> v > 1 end) 476``` 477 478```output 47918605 480``` 481 482## Day 6 483 484```elixir 485initial = for i <- 0..8, into: %{}, do: {i, 0} 486 487counts = 488 File.read!("day6.txt") 489 |> String.trim() 490 |> String.split(",") 491 |> Enum.map(&String.to_integer/1) 492 |> Enum.frequencies() 493 |> Map.merge(initial, fn _, a, _ -> a end) 494 495defmodule Day6 do 496 def next(%{0 => next} = population) do 497 1..8 498 |> Map.new(&{&1 - 1, population[&1]}) 499 |> Map.merge(%{6 => next, 8 => next}, fn _, v1, v2 -> v1 + v2 end) 500 end 501end 502``` 503 504```output 505{:module, Day6, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:next, 1}} 506``` 507 508### Task 1 509 510```elixir 5111..80 512|> Enum.reduce(counts, fn _, acc -> Day6.next(acc) end) 513|> Map.values() 514|> Enum.sum() 515``` 516 517```output 518343441 519``` 520 521### Task 2 522 523```elixir 5241..256 525|> Enum.reduce(counts, fn _, acc -> Day6.next(acc) end) 526|> Map.values() 527|> Enum.sum() 528``` 529 530```output 5311569108373832 532``` 533 534## Day 7 535 536```elixir 537input = 538 File.read!("day7.txt") 539 |> String.trim() 540 |> String.split(",") 541 |> Enum.map(&String.to_integer/1) 542``` 543 544```output 545[1101, 1, 29, 67, 1102, 0, 1, 65, 1008, 65, 35, 66, 1005, 66, 28, 1, 67, 65, 20, 4, 0, 1001, 65, 1, 546 65, 1106, 0, 8, 99, 35, 67, 101, 99, 105, 32, 110, 39, 101, 115, 116, 32, 112, 97, 115, 32, 117, 547 110, 101, 32, 105, ...] 548``` 549 550### Task 1 551 552```elixir 553median = Enum.at(Enum.sort(input), div(length(input), 2)) 554 555input 556|> Enum.map(&abs(&1 - median)) 557|> Enum.sum() 558``` 559 560```output 561336721 562``` 563 564### Task 2 565 566```elixir 567arith_sum = fn n -> div(n * n + n, 2) end 568 569max = Enum.max(input) 570 571mean = Enum.sum(input) / length(input) 572 573[floor(mean), ceil(mean)] 574|> Enum.map(fn n -> 575 input 576 |> Enum.map(&arith_sum.(abs(&1 - n))) 577 |> Enum.sum() 578end) 579|> Enum.min() 580``` 581 582```output 58391638945 584``` 585 586## Day 8 587 588```elixir 589input = 590 File.stream!("day8.txt") 591 |> Stream.map(fn line -> 592 line 593 |> String.split(" | ") 594 |> Enum.map(fn part -> 595 part 596 |> String.trim() 597 |> String.split(" ") 598 |> Enum.map(fn disp -> 599 # Sort characters in each entry to simplify later work 600 disp 601 |> String.to_charlist() 602 |> Enum.sort() 603 |> List.to_string() 604 end) 605 end) 606 |> List.to_tuple() 607 end) 608``` 609 610```output 611#Stream<[ 612 enum: %File.Stream{ 613 line_or_bytes: :line, 614 modes: [:raw, :read_ahead, :binary], 615 path: "day8.txt", 616 raw: true 617 }, 618 funs: [#Function<47.58486609/1 in Stream.map/2>] 619]> 620``` 621 622### Task 1 623 624We simply need to count all occurences of the values that have 2, 3, 4, or 7 highlighted 625segments. 626 627```elixir 628input 629|> Enum.map(fn {_, output} -> 630 Enum.count(output, &(byte_size(&1) in [2, 3, 4, 7])) 631end) 632|> Enum.sum() 633``` 634 635```output 636390 637``` 638 639### Task 2 640 641```elixir 642defmodule Day8.Task2 do 643 defp a --- b, do: MapSet.difference(a, b) 644 645 defp a +++ b, do: MapSet.union(a, b) 646 647 defp a <~> b, do: MapSet.intersection(a, b) 648 649 # 1. 7. 4. 2|3|5. 2|3|5. 2|3|5. 6|9|0. 6|9|0. 6|9|0. 8. 650 def deduce([cf, acf, bcdf, acdeg, acdfg, abdfg, abdefg, abcdfg, abcefg, abcdefg]) do 651 eg = abcdefg --- (acf +++ bcdf) 652 bd = bcdf --- cf 653 adg = acdeg <~> acdfg <~> abdfg 654 abfg = abdefg <~> abcdfg <~> abcefg 655 a = acf --- cf 656 b = abfg <~> bd 657 f = abfg <~> cf 658 g = adg <~> eg 659 d = adg <~> bd 660 c = cf --- f 661 e = eg --- g 662 663 [a, b, c, d, e, f, g] = 664 [a, b, c, d, e, f, g] 665 |> Enum.map(&extract/1) 666 667 [ 668 # 0 669 [a, b, c, e, f, g], 670 # 1 671 [c, f], 672 # 2 673 [a, c, d, e, g], 674 # 3 675 [a, c, d, f, g], 676 # 4 677 [b, c, d, f], 678 # 5 679 [a, b, d, f, g], 680 # 6 681 [a, b, d, e, f, g], 682 # 7 683 [a, c, f], 684 # 8 685 [a, b, c, d, e, f, g], 686 # 9 687 [a, b, c, d, f, g] 688 ] 689 |> Enum.map(&List.to_string(Enum.sort(&1))) 690 |> Enum.with_index() 691 |> Map.new() 692 end 693 694 defp extract(a) do 695 # Just additional sanity check 696 [v] = MapSet.to_list(a) 697 698 v 699 end 700 701 def decode(matches, output) do 702 output 703 |> Enum.map(&matches[&1]) 704 |> Integer.undigits() 705 end 706end 707 708input 709|> Enum.map(fn {input, output} -> 710 input 711 |> Enum.sort_by(&byte_size/1) 712 |> Enum.map(&MapSet.new(String.to_charlist(&1))) 713 |> Day8.Task2.deduce() 714 |> Day8.Task2.decode(output) 715end) 716|> Enum.sum() 717``` 718 719```output 7201011785 721``` 722 723## Day 9 724 725```elixir 726input = 727 File.read!("day9.txt") 728 |> String.split("\n", trim: true) 729 |> Enum.map(&String.to_charlist(String.trim(&1))) 730 |> Nx.tensor(names: [:y, :x]) 731 |> Nx.subtract(?0) 732 |> Nx.add(1) 733 734{width, height} = shape = Nx.shape(input) 735``` 736 737```output 738{100, 100} 739``` 740 741### Task 1 742 743```elixir 744minima = fn padded, size, axis -> 745 shifted = Nx.slice_axis(padded, 0, size, axis) 746 x1 = Nx.less(input, shifted) 747 748 shifted = Nx.slice_axis(padded, 2, size, axis) 749 x2 = Nx.less(input, shifted) 750 751 Nx.logical_and(x1, x2) 752end 753 754padded = Nx.pad(input, 99, [{0, 0, 0}, {1, 1, 0}]) 755 756x = minima.(padded, width, :x) 757 758padded = Nx.pad(input, 99, [{1, 1, 0}, {0, 0, 0}]) 759 760y = minima.(padded, height, :y) 761 762minimas = Nx.logical_and(x, y) 763 764input 765|> Nx.multiply(minimas) 766|> Nx.sum() 767|> Nx.to_number() 768``` 769 770```output 771452 772``` 773 774### Task 2 775 776```elixir 777input 778|> Nx.equal(10) 779|> Nx.logical_not() 780|> Nx.select(Nx.iota(shape), 9999) 781|> Nx.to_flat_list() 782|> Enum.reject(&(&1 == 9999)) 783|> Enum.map(fn point -> {div(point, width), rem(point, width)} end) 784|> Enum.reduce([], fn {y, x} = point, basins -> 785 basin_left = Enum.find_index(basins, &({y, x - 1} in &1)) 786 basin_up = Enum.find_index(basins, &({y - 1, x} in &1)) 787 788 case {basin_left, basin_up} do 789 {nil, nil} -> 790 [MapSet.new([point]) | basins] 791 792 {idx, nil} -> 793 List.update_at(basins, idx, &MapSet.put(&1, point)) 794 795 {nil, idx} -> 796 List.update_at(basins, idx, &MapSet.put(&1, point)) 797 798 {idx, idx} -> 799 List.update_at(basins, idx, &MapSet.put(&1, point)) 800 801 {idx1, idx2} -> 802 {old, basins} = List.pop_at(basins, max(idx1, idx2)) 803 804 List.update_at(basins, min(idx1, idx2), &(&1 |> MapSet.union(old) |> MapSet.put(point))) 805 end 806end) 807|> Enum.map(&MapSet.size/1) 808|> Enum.sort(:desc) 809|> Enum.take(3) 810|> Enum.reduce(&*/2) 811``` 812 813```output 8141263735 815``` 816 817## Day 10 818 819```elixir 820input = 821 File.stream!("day10.txt") 822 |> Stream.map(&String.trim/1) 823 824defmodule Day10 do 825 @parens %{?( => ?), ?[ => ?], ?< => ?>, ?{ => ?}} 826 827 def parse(input), do: parse(input, []) 828 829 defp parse(<<c>> <> rest, stack) when c in '([{<', do: parse(rest, [@parens[c] | stack]) 830 defp parse(<<c>> <> rest, [c | stack]), do: parse(rest, stack) 831 defp parse(<<>>, []), do: :ok 832 defp parse(<<>>, rest), do: {:incomplete, rest} 833 defp parse(<<c>> <> _, _), do: {:unexpected, [c]} 834end 835``` 836 837```output 838{:module, Day10, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:parse, 2}} 839``` 840 841### Task 1 842 843```elixir 844points = %{ 845 ?) => 3, 846 ?] => 57, 847 ?} => 1197, 848 ?> => 25137 849} 850 851input 852|> Enum.map(&Day10.parse/1) 853|> Enum.map(fn 854 {:unexpected, [c]} -> points[c] 855 _ -> 0 856end) 857|> Enum.sum() 858``` 859 860```output 861288291 862``` 863 864### Task 2 865 866```elixir 867points = %{ 868 ?) => 1, 869 ?] => 2, 870 ?} => 3, 871 ?> => 4 872} 873 874median = fn list -> 875 sorted = Enum.sort(list) 876 middle = div(length(list), 2) 877 878 Enum.at(sorted, middle) 879end 880 881input 882|> Enum.map(&Day10.parse/1) 883|> Enum.flat_map(fn 884 {:incomplete, rest} -> 885 [ 886 Enum.reduce(rest, 0, fn c, acc -> 887 acc * 5 + points[c] 888 end) 889 ] 890 891 _ -> 892 [] 893end) 894|> median.() 895``` 896 897```output 898820045242 899``` 900 901## Day 11 902 903```elixir 904input = 905 File.read!("day11.txt") 906 |> String.split("\n") 907 |> Enum.map(&String.trim/1) 908 |> Enum.map(fn line -> 909 for <<c <- line>>, do: c - ?0 910 end) 911 |> Enum.with_index() 912 |> Enum.flat_map(fn {row, y} -> 913 for {v, x} <- Enum.with_index(row), do: {{x, y}, v} 914 end) 915 |> Map.new() 916 917defmodule Day11 do 918 def step(map) do 919 updated = Map.new(map, fn {k, v} -> {k, v + 1} end) 920 921 lightup(updated, 0) 922 end 923 924 @diffs for dx <- -1..1, dy <- -1..1, dx != 0 or dy != 0, do: {dx, dy} 925 926 def lightup(map, n) do 927 map 928 |> Enum.reduce({map, 0}, fn 929 {_, v}, acc when v < 10 -> 930 acc 931 932 {{x, y} = k, _}, {map, count} -> 933 new_map = 934 @diffs 935 |> Enum.reduce(map, fn {dx, dy}, acc -> 936 point = {x + dx, y + dy} 937 938 case Map.fetch(acc, point) do 939 {:ok, value} when value != 0 -> %{acc | point => value + 1} 940 _ -> acc 941 end 942 end) 943 |> Map.put(k, 0) 944 945 {new_map, count + 1} 946 end) 947 |> case do 948 {map, 0} -> {map, n} 949 {map, m} -> lightup(map, n + m) 950 end 951 end 952end 953``` 954 955```output 956{:module, Day11, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:lightup, 2}} 957``` 958 959### Task 1 960 961```elixir 962draw = fn map -> 963 for x <- 0..9 do 964 IO.puts(for y <- 0..9, do: ?0 + map[{x, y}]) 965 end 966 967 IO.puts("") 968end 969 9701..100 971|> Enum.reduce({input, 0}, fn _, {map, n} -> 972 {new_map, m} = Day11.step(map) 973 {new_map, n + m} 974end) 975|> elem(1) 976``` 977 978```output 9791688 980``` 981 982### Task 2 983 984```elixir 985Stream.unfold(1, &{&1, &1 + 1}) 986|> Enum.reduce_while(input, fn idx, map -> 987 case Day11.step(map) do 988 {_, 100} -> {:halt, idx} 989 {next, _} -> {:cont, next} 990 end 991end) 992``` 993 994```output 995403 996``` 997 998## Day 12 999 1000```elixir 1001input = 1002 File.read!("day12.txt") 1003 |> String.split("\n") 1004 |> Enum.map(&String.split(&1, "-")) 1005 1006graph = 1007 Enum.reduce(input, %{}, fn [a, b], acc -> 1008 acc 1009 |> Map.update(a, [b], &[b | &1]) 1010 |> Map.update(b, [a], &[a | &1]) 1011 end) 1012 1013defmodule Day12 do 1014 def dfs(graph, start, finish), do: dfs(graph, start, finish, [start]) 1015 1016 defp dfs(_graph, vertex, vertex, _visited), do: 1 1017 1018 defp dfs(graph, vertex, finish, visited) do 1019 (graph[vertex] -- visited) 1020 |> Enum.reduce(0, fn vertex, acc -> 1021 visited = if small?(vertex), do: [vertex | visited], else: visited 1022 1023 acc + dfs(graph, vertex, finish, visited) 1024 end) 1025 end 1026 1027 def dfs2(graph, start, finish), do: dfs2(graph, start, finish, %{start => :inf}) 1028 1029 defp dfs2(_graph, vertex, vertex, _visited), do: 1 1030 1031 defp dfs2(graph, vertex, finish, visited) do 1032 (graph[vertex] -- keys(visited)) 1033 |> Enum.reduce(0, fn vertex, acc -> 1034 visited = if small?(vertex), do: Map.update(visited, vertex, 1, &(&1 + 1)), else: visited 1035 1036 acc + dfs2(graph, vertex, finish, visited) 1037 end) 1038 end 1039 1040 defp keys(map) do 1041 if Enum.any?(map, fn {_, v} -> v == 2 end) do 1042 # there is already some vertex visited twice 1043 Map.keys(map) 1044 else 1045 for {k, v} <- map, v > 1, do: k 1046 end 1047 end 1048 1049 defp small?(<<c>> <> _), do: c in ?a..?z 1050end 1051``` 1052 1053```output 1054{:module, Day12, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:small?, 1}} 1055``` 1056 1057### Task 1 1058 1059```elixir 1060Day12.dfs(graph, "start", "end") 1061``` 1062 1063```output 10644167 1065``` 1066 1067### Task 2 1068 1069```elixir 1070Day12.dfs2(graph, "start", "end") 1071``` 1072 1073```output 107498441 1075``` 1076 1077## Day 13 1078 1079```elixir 1080[input, folds] = 1081 File.read!("day13.txt") 1082 |> String.trim() 1083 |> String.split("\n\n") 1084 1085input = 1086 input 1087 |> String.split("\n") 1088 |> Enum.map(fn line -> 1089 [x, y] = String.split(line, ",") 1090 1091 {String.to_integer(x), String.to_integer(y)} 1092 end) 1093 |> MapSet.new() 1094 1095folds = 1096 folds 1097 |> String.split("\n") 1098 |> Enum.map(fn 1099 "fold along " <> <<c>> <> "=" <> rest -> 1100 {String.to_atom(<<c>>), String.to_integer(rest)} 1101 end) 1102 1103defmodule Day13 do 1104 def fold({orientation, pos}, set) do 1105 Enum.reduce(set, MapSet.new(), fn point, acc -> 1106 new_point = folded_coords(orientation, pos, point) 1107 1108 MapSet.put(acc, new_point) 1109 end) 1110 end 1111 1112 defp folded_coords(:x, col, {x, y}) when x > col, do: {abs(2 * col - x), y} 1113 defp folded_coords(:y, row, {x, y}) when y > row, do: {x, abs(2 * row - y)} 1114 defp folded_coords(_, _, point), do: point 1115 1116 def draw(set) do 1117 set 1118 |> Enum.group_by(&elem(&1, 1)) 1119 |> Enum.sort() 1120 |> Enum.map(fn {_, points} -> 1121 points 1122 |> Enum.map(&elem(&1, 0)) 1123 |> Enum.sort() 1124 |> Enum.chunk_every(2, 1) 1125 |> Enum.map(fn 1126 [a, b] -> b - a 1127 _ -> 0 1128 end) 1129 |> Enum.map(&String.pad_trailing("█", &1, " ")) 1130 end) 1131 |> Enum.join("\n") 1132 end 1133end 1134``` 1135 1136```output 1137{:module, Day13, <<70, 79, 82, 49, 0, 0, 13, ...>>, {:draw, 1}} 1138``` 1139 1140### Task 1 1141 1142```elixir 1143Day13.fold(hd(folds), input) |> MapSet.size() 1144``` 1145 1146```output 1147802 1148``` 1149 1150### Task 2 1151 1152```elixir 1153Enum.reduce(folds, input, &Day13.fold/2) 1154|> Day13.draw() 1155|> IO.puts() 1156``` 1157 1158```output 1159███ █ █ █ █ ████ ████ ██ █ █ ███ 1160█ █ █ █ █ █ █ █ █ █ █ █ █ █ 1161█ █ ██ ████ ███ █ █ █ █ ███ 1162███ █ █ █ █ █ █ █ ██ █ █ █ █ 1163█ █ █ █ █ █ █ █ █ █ █ █ █ █ 1164█ █ █ █ █ █ █ ████ ███ ██ ███ 1165``` 1166 1167```output 1168:ok 1169``` 1170 1171## Day 14 1172 1173```elixir 1174[polymer_raw, subs] = 1175 File.read!("day14.txt") 1176 |> String.split("\n\n") 1177 1178<<first, _::binary>> = polymer_raw 1179 1180polymer = 1181 {first, 1182 polymer_raw 1183 |> String.to_charlist() 1184 |> Enum.chunk_every(2, 1, :discard) 1185 |> Enum.frequencies()} 1186 1187subs = 1188 subs 1189 |> String.trim() 1190 |> String.split(["\n", " -> "]) 1191 |> Enum.chunk_every(2) 1192 |> Map.new(fn [pair, <<new>>] -> {String.to_charlist(pair), new} end) 1193 1194defmodule Day14 do 1195 def expand({hd, polymer}, subs) do 1196 new = 1197 polymer 1198 |> Enum.reduce(%{}, fn {[a, b] = pair, count}, acc -> 1199 s = Map.fetch!(subs, pair) 1200 1201 acc 1202 |> Map.update([a, s], count, &(&1 + count)) 1203 |> Map.update([s, b], count, &(&1 + count)) 1204 end) 1205 1206 {hd, new} 1207 end 1208 1209 def expand_naive(polymer, subs) do 1210 polymer 1211 |> to_charlist() 1212 |> Enum.chunk_every(2, 1, :discard) 1213 |> Enum.flat_map(fn [a, b] = pair -> 1214 [a, subs[pair], b] 1215 end) 1216 |> List.to_string() 1217 end 1218 1219 def frequencies({hd, polymer}) do 1220 polymer 1221 |> Enum.reduce(%{hd => 1}, fn {[_, b], count}, acc -> 1222 Map.update(acc, b, count, &(&1 + count)) 1223 end) 1224 end 1225end 1226``` 1227 1228```output 1229{:module, Day14, <<70, 79, 82, 49, 0, 0, 13, ...>>, {:frequencies, 1}} 1230``` 1231 1232### Task 1 1233 1234```elixir 1235{{_, min}, {_, max}} = 1236 1..10 1237 |> Enum.reduce(polymer, fn _, acc -> 1238 Day14.expand(acc, subs) 1239 end) 1240 |> Day14.frequencies() 1241 |> Enum.min_max_by(&elem(&1, 1)) 1242 1243# 2768 1244max - min 1245``` 1246 1247```output 12482768 1249``` 1250 1251### Task 2 1252 1253```elixir 1254{{_, min}, {_, max}} = 1255 1..40 1256 |> Enum.reduce(polymer, fn _, acc -> 1257 Day14.expand(acc, subs) 1258 end) 1259 |> Day14.frequencies() 1260 |> Enum.min_max_by(&elem(&1, 1)) 1261 1262max - min 1263``` 1264 1265```output 12662914365137499 1267``` 1268 1269## Day 15 1270 1271```elixir 1272input = 1273 File.read!("day15.txt") 1274 |> String.trim() 1275 |> String.split("\n") 1276 |> Enum.map(&String.to_charlist/1) 1277 |> Enum.with_index() 1278 |> Enum.flat_map(fn {row, y} -> 1279 row 1280 |> Enum.with_index() 1281 |> Enum.map(fn {v, x} -> {{x, y}, v - ?0} end) 1282 end) 1283 |> Map.new() 1284 1285{width, height} = Enum.max(Map.keys(input)) 1286``` 1287 1288```output 1289{99, 99} 1290``` 1291 1292### Task 1 1293 1294```elixir 1295shortest_paths = 1296 for y <- height..0//-1, 1297 x <- width..0//-1, 1298 reduce: %{} do 1299 acc -> 1300 right = acc[{x + 1, y}] 1301 bottom = acc[{x, y + 1}] 1302 1303 value = 1304 case {right, bottom} do 1305 {nil, nil} -> input[{x, y}] 1306 _ -> input[{x, y}] + min(right, bottom) 1307 end 1308 1309 Map.put(acc, {x, y}, value) 1310 end 1311 1312shortest_paths[{0, 0}] - input[{0, 0}] 1313``` 1314 1315```output 1316429 1317``` 1318 1319### Task 2 1320 1321```elixir 1322defmodule Day15.Task2 do 1323 def expand_grid(board) do 1324 {width, height} = Enum.max(Map.keys(board)) 1325 1326 board 1327 |> Enum.flat_map(fn {{x, y}, v} -> 1328 for rx <- 0..4, ry <- 0..4 do 1329 {{x + (width + 1) * rx, y + (height + 1) * ry}, rem(v - 1 + rx + ry, 9) + 1} 1330 end 1331 end) 1332 |> Map.new() 1333 end 1334 1335 def find_path(board, start, finish) do 1336 dists = :gb_sets.singleton({0, start}) 1337 1338 find_path(board, finish, dists, MapSet.new()) 1339 end 1340 1341 @surround for dx <- -1..1, dy <- -1..1, abs(dx) != abs(dy), do: {dx, dy} 1342 1343 def find_path(board, finish, dists, visited) do 1344 {{dist, {x, y} = curr}, dists} = :gb_sets.take_smallest(dists) 1345 1346 if curr == finish do 1347 dist 1348 else 1349 visited = MapSet.put(visited, curr) 1350 1351 dists = 1352 for {dx, dy} <- @surround, 1353 next = {x + dx, y + dy}, 1354 next not in visited, 1355 is_map_key(board, next), 1356 alt = dist + board[next], 1357 reduce: dists do 1358 acc -> 1359 :gb_sets.add_element({alt, next}, acc) 1360 end 1361 1362 find_path(board, finish, dists, visited) 1363 end 1364 end 1365end 1366``` 1367 1368```output 1369{:module, Day15.Task2, <<70, 79, 82, 49, 0, 0, 16, ...>>, {:find_path, 4}} 1370``` 1371 1372```elixir 1373input 1374|> Day15.Task2.expand_grid() 1375|> Day15.Task2.find_path({0, 0}, {499, 499}) 1376``` 1377 1378```output 13792844 1380``` 1381 1382## Day 16 1383 1384```elixir 1385defmodule Day16 do 1386 defmodule Packet do 1387 defstruct [:version, :type, :value] 1388 end 1389 1390 def decode(<<version::3, 4::3, rest::bitstring>>) do 1391 {value, rest} = literal(rest, 0) 1392 1393 {%Packet{type: 4, version: version, value: value}, rest} 1394 end 1395 1396 def decode(<<version::3, type::3, 0::1, length::15, rest::bitstring>>) do 1397 <<subpackets::bitstring-size(length), rest::bitstring>> = rest 1398 1399 {%Packet{type: type, version: version, value: decode_all(subpackets)}, rest} 1400 end 1401 1402 def decode(<<version::3, type::3, 1::1, length::11, rest::bitstring>>) do 1403 {value, rest} = Enum.map_reduce(1..length, rest, fn _, acc -> decode(acc) end) 1404 1405 {%Packet{type: type, version: version, value: value}, rest} 1406 end 1407 1408 def decode_all(input) do 1409 case decode(input) do 1410 {packet, <<>>} -> [packet] 1411 {packet, rest} -> [packet | decode_all(rest)] 1412 end 1413 end 1414 1415 defp literal(<<1::1, bits::4, rest::bitstring>>, acc) do 1416 literal(rest, acc * 0x10 + bits) 1417 end 1418 1419 defp literal(<<0::1, bits::4, rest::bitstring>>, acc) do 1420 {acc * 0x10 + bits, rest} 1421 end 1422end 1423 1424input = 1425 File.read!("day16.txt") 1426 |> String.trim() 1427 |> Base.decode16!() 1428 |> Day16.decode() 1429 |> elem(0) 1430``` 1431 1432```output 1433%Day16.Packet{ 1434 type: 0, 1435 value: [ 1436 %Day16.Packet{ 1437 type: 1, 1438 value: [ 1439 %Day16.Packet{type: 4, value: 20, version: 6}, 1440 %Day16.Packet{ 1441 type: 6, 1442 value: [ 1443 %Day16.Packet{type: 4, value: 14747, version: 1}, 1444 %Day16.Packet{type: 4, value: 14747, version: 6} 1445 ], 1446 version: 2 1447 } 1448 ], 1449 version: 1 1450 }, 1451 %Day16.Packet{ 1452 type: 3, 1453 value: [ 1454 %Day16.Packet{type: 4, value: 15, version: 5}, 1455 %Day16.Packet{type: 4, value: 10, version: 6} 1456 ], 1457 version: 7 1458 }, 1459 %Day16.Packet{ 1460 type: 1, 1461 value: [ 1462 %Day16.Packet{ 1463 type: 7, 1464 value: [ 1465 %Day16.Packet{type: 4, value: 2184, version: 1}, 1466 %Day16.Packet{type: 4, value: 130250, version: 6} 1467 ], 1468 version: 6 1469 }, 1470 %Day16.Packet{type: 4, value: 5442981, version: 4} 1471 ], 1472 version: 6 1473 }, 1474 %Day16.Packet{type: 4, value: 8281083, version: 0}, 1475 %Day16.Packet{ 1476 type: 2, 1477 value: [ 1478 %Day16.Packet{type: 4, value: 102, version: 5}, 1479 %Day16.Packet{type: 4, value: 647125, version: 7} 1480 ], 1481 version: 1 1482 }, 1483 %Day16.Packet{ 1484 type: 1, 1485 value: [ 1486 %Day16.Packet{type: 4, value: 178, version: 1}, 1487 %Day16.Packet{type: 4, value: 176, version: 6} 1488 ], 1489 version: 0 1490 }, 1491 %Day16.Packet{ 1492 type: 1, 1493 value: [ 1494 %Day16.Packet{ 1495 type: 6, 1496 value: [ 1497 %Day16.Packet{ 1498 type: 0, 1499 value: [ 1500 %Day16.Packet{type: 4, value: 13, version: 1}, 1501 %Day16.Packet{type: 4, value: 8, version: 4}, 1502 %Day16.Packet{type: 4, value: 4, version: 3} 1503 ], 1504 version: 2 1505 }, 1506 %Day16.Packet{ 1507 type: 0, 1508 value: [ 1509 %Day16.Packet{type: 4, value: 7, version: 7}, 1510 %Day16.Packet{type: 4, value: 11, version: 3}, 1511 %Day16.Packet{type: 4, value: 14, version: 2} 1512 ], 1513 version: 4 1514 } 1515 ], 1516 version: 7 1517 }, 1518 %Day16.Packet{type: 4, value: 2724, version: 0} 1519 ], 1520 version: 1 1521 }, 1522 %Day16.Packet{type: 4, value: 9, version: 4}, 1523 %Day16.Packet{ 1524 type: 1, 1525 value: [ 1526 %Day16.Packet{ 1527 type: 5, 1528 value: [ 1529 %Day16.Packet{type: 4, value: 7240238, version: 2}, 1530 %Day16.Packet{type: 4, value: 233, version: 7} 1531 ], 1532 version: 1 1533 }, 1534 %Day16.Packet{type: 4, value: 37, version: 6} 1535 ], 1536 version: 4 1537 }, 1538 %Day16.Packet{type: 2, value: [%Day16.Packet{type: 4, value: 2, version: 5}], version: 5}, 1539 %Day16.Packet{type: 4, value: 53749, version: 4}, 1540 %Day16.Packet{type: 4, value: 11, version: 3}, 1541 %Day16.Packet{ 1542 type: 1, 1543 value: [ 1544 %Day16.Packet{type: 4, value: 382979, version: 4}, 1545 %Day16.Packet{ 1546 type: 5, 1547 value: [ 1548 %Day16.Packet{ 1549 type: 0, 1550 value: [ 1551 %Day16.Packet{type: 4, value: 15, version: 1}, 1552 %Day16.Packet{type: 4, value: 10, version: 0}, 1553 %Day16.Packet{type: 4, value: 2, version: 6} 1554 ], 1555 version: 5 1556 }, 1557 %Day16.Packet{ 1558 type: 0, 1559 value: [ 1560 %Day16.Packet{type: 4, value: 4, version: 7}, 1561 %Day16.Packet{type: 4, value: 7, version: 4}, 1562 %Day16.Packet{type: 4, value: 2, version: 5} 1563 ], 1564 version: 1 1565 } 1566 ], 1567 version: 6 1568 } 1569 ], 1570 version: 2 1571 }, 1572 %Day16.Packet{type: 4, value: 21251, version: 1}, 1573 %Day16.Packet{ 1574 type: 1, 1575 value: [ 1576 %Day16.Packet{type: 4, value: 163, version: 6}, 1577 %Day16.Packet{ 1578 type: 5, 1579 value: [ 1580 %Day16.Packet{type: 4, value: 59, version: 3}, 1581 %Day16.Packet{type: 4, value: 836848134220, version: 1} 1582 ], 1583 version: 6 1584 } 1585 ], 1586 version: 2 1587 }, 1588 %Day16.Packet{ 1589 type: 2, 1590 value: [ 1591 %Day16.Packet{ 1592 type: 0, 1593 value: [ 1594 %Day16.Packet{ 1595 type: 0, 1596 value: [ 1597 %Day16.Packet{ 1598 type: 2, 1599 value: [ 1600 %Day16.Packet{ 1601 type: 2, 1602 value: [ 1603 %Day16.Packet{ 1604 type: 0, 1605 value: [ 1606 %Day16.Packet{ 1607 type: 3, 1608 value: [ 1609 %Day16.Packet{ 1610 type: 2, 1611 value: [ 1612 %Day16.Packet{ 1613 type: 2, 1614 value: [ 1615 %Day16.Packet{ 1616 type: 3, 1617 value: [%Day16.Packet{type: 0, value: [...], ...}], 1618 version: 0 1619 } 1620 ], 1621 version: 1 1622 } 1623 ], 1624 version: 1 1625 } 1626 ], 1627 version: 7 1628 } 1629 ], 1630 version: 0 1631 } 1632 ], 1633 version: 6 1634 } 1635 ], 1636 version: 2 1637 } 1638 ], 1639 version: 2 1640 } 1641 ], 1642 version: 6 1643 } 1644 ], 1645 version: 7 1646 }, 1647 %Day16.Packet{type: 1, value: [%Day16.Packet{type: 4, value: 44, version: 4}], version: 7}, 1648 %Day16.Packet{ 1649 type: 1, 1650 value: [ 1651 %Day16.Packet{type: 4, value: 255, version: 2}, 1652 %Day16.Packet{type: 4, value: 91, version: 5}, 1653 %Day16.Packet{type: 4, value: 176, version: 5}, 1654 %Day16.Packet{type: 4, value: 23, version: 1} 1655 ], 1656 version: 7 1657 }, 1658 %Day16.Packet{ 1659 type: 3, 1660 value: [ 1661 %Day16.Packet{type: 4, value: 11520, version: 4}, 1662 %Day16.Packet{type: 4, value: 6069, version: 0}, 1663 %Day16.Packet{type: 4, value: 1089149511401, version: 4}, 1664 %Day16.Packet{type: 4, value: 158, version: 2}, 1665 %Day16.Packet{type: 4, value: 620605, version: 0} 1666 ], 1667 version: 2 1668 }, 1669 %Day16.Packet{ 1670 type: 0, 1671 value: [ 1672 %Day16.Packet{type: 4, value: 62788, version: 7}, 1673 %Day16.Packet{type: 4, value: 9410622, version: 2}, 1674 %Day16.Packet{type: 4, value: 15912821, version: 4} 1675 ], 1676 version: 4 1677 }, 1678 %Day16.Packet{ 1679 type: 1, 1680 value: [ 1681 %Day16.Packet{type: 4, value: 22416, version: 5}, 1682 %Day16.Packet{ 1683 type: 5, 1684 value: [ 1685 %Day16.Packet{type: 4, value: 246, version: 1}, 1686 %Day16.Packet{type: 4, value: 246, version: 4} 1687 ], 1688 version: 2 1689 } 1690 ], 1691 version: 0 1692 }, 1693 %Day16.Packet{type: 3, value: [%Day16.Packet{type: 4, value: 13008601, version: 5}], version: 0}, 1694 %Day16.Packet{ 1695 type: 0, 1696 value: [ 1697 %Day16.Packet{ 1698 type: 1, 1699 value: [ 1700 %Day16.Packet{type: 4, value: 3, version: 4}, 1701 %Day16.Packet{type: 4, value: 14, version: 1}, 1702 %Day16.Packet{type: 4, value: 5, version: 0} 1703 ], 1704 version: 5 1705 }, 1706 %Day16.Packet{ 1707 type: 1, 1708 value: [ 1709 %Day16.Packet{type: 4, value: 2, version: 1}, 1710 %Day16.Packet{type: 4, value: 14, version: 1}, 1711 %Day16.Packet{type: 4, value: 10, version: 1} 1712 ], 1713 version: 6 1714 }, 1715 %Day16.Packet{ 1716 type: 1, 1717 value: [ 1718 %Day16.Packet{type: 4, value: 8, version: 3}, 1719 %Day16.Packet{type: 4, value: 6, version: 6}, 1720 %Day16.Packet{type: 4, value: 11, version: 0} 1721 ], 1722 version: 1 1723 } 1724 ], 1725 version: 5 1726 }, 1727 %Day16.Packet{ 1728 type: 1, 1729 value: [ 1730 %Day16.Packet{type: 4, value: 32940592237, version: 2}, 1731 %Day16.Packet{ 1732 type: 5, 1733 value: [ 1734 %Day16.Packet{type: 4, value: 100, version: 1}, 1735 %Day16.Packet{type: 4, value: 1393232728, version: 2} 1736 ], 1737 version: 2 1738 } 1739 ], 1740 version: 0 1741 }, 1742 %Day16.Packet{type: 4, value: 89, version: 3}, 1743 %Day16.Packet{ 1744 type: 2, 1745 value: [ 1746 %Day16.Packet{type: 4, value: 204, version: 6}, 1747 %Day16.Packet{type: 4, value: 260321821, version: 2}, 1748 %Day16.Packet{type: 4, value: 225241983, version: 6} 1749 ], 1750 version: 0 1751 }, 1752 %Day16.Packet{ 1753 type: 0, 1754 value: [ 1755 %Day16.Packet{type: 4, value: 960899, version: 3}, 1756 %Day16.Packet{type: 4, value: 58997, version: 5}, 1757 %Day16.Packet{type: 4, value: 54940, version: 6}, 1758 %Day16.Packet{type: 4, value: 10974, version: 2}, 1759 %Day16.Packet{type: 4, value: 882043, version: 2} 1760 ], 1761 version: 0 1762 }, 1763 %Day16.Packet{ 1764 type: 1, 1765 value: [ 1766 %Day16.Packet{ 1767 type: 6, 1768 value: [ 1769 %Day16.Packet{type: 4, value: 35633017255, version: 4}, 1770 %Day16.Packet{type: 4, value: 35633017255, version: 2} 1771 ], 1772 version: 3 1773 }, 1774 %Day16.Packet{type: 4, value: 1359, version: 6} 1775 ], 1776 version: 6 1777 }, 1778 %Day16.Packet{ 1779 type: 1, 1780 value: [ 1781 %Day16.Packet{type: 4, value: 92, version: 4}, 1782 %Day16.Packet{type: 4, value: 38, version: 3}, 1783 %Day16.Packet{type: 4, value: 160, version: 5}, 1784 %Day16.Packet{type: 4, value: 111, version: 1}, 1785 %Day16.Packet{type: 4, value: 64, version: 4} 1786 ], 1787 version: 4 1788 }, 1789 %Day16.Packet{ 1790 type: 0, 1791 value: [ 1792 %Day16.Packet{type: 4, value: 2541, version: 3}, 1793 %Day16.Packet{type: 4, value: 263947, version: 6}, 1794 %Day16.Packet{type: 4, value: 7686705, version: 5}, 1795 %Day16.Packet{type: 4, value: 31, version: 4} 1796 ], 1797 version: 2 1798 }, 1799 %Day16.Packet{ 1800 type: 1, 1801 value: [ 1802 %Day16.Packet{ 1803 type: 6, 1804 value: [ 1805 %Day16.Packet{type: 4, value: 3193865, version: 1}, 1806 %Day16.Packet{type: 4, value: 20223, version: 7} 1807 ], 1808 version: 2 1809 }, 1810 %Day16.Packet{type: 4, value: 9328522, version: 5} 1811 ], 1812 version: 0 1813 }, 1814 %Day16.Packet{ 1815 type: 2, 1816 value: [ 1817 %Day16.Packet{type: 4, value: 5, version: 4}, 1818 %Day16.Packet{type: 4, value: 7, version: 3}, 1819 %Day16.Packet{type: 4, value: 179420284, version: 4}, 1820 %Day16.Packet{type: 4, value: 19890, version: 1}, 1821 %Day16.Packet{type: 4, value: 2655, version: 0} 1822 ], 1823 version: 7 1824 }, 1825 %Day16.Packet{ 1826 type: 1, 1827 value: [ 1828 %Day16.Packet{type: 4, value: 862089, version: 1}, 1829 %Day16.Packet{ 1830 type: 6, 1831 value: [ 1832 %Day16.Packet{type: 4, value: 248, version: 3}, 1833 %Day16.Packet{type: 4, value: 3286, version: 5} 1834 ], 1835 version: 3 1836 } 1837 ], 1838 version: 3 1839 }, 1840 %Day16.Packet{ 1841 type: 1, 1842 value: [ 1843 %Day16.Packet{type: 4, value: 93, version: 6}, 1844 %Day16.Packet{ 1845 type: 5, 1846 value: [ 1847 %Day16.Packet{type: 4, value: 4269, version: 6}, 1848 %Day16.Packet{type: 4, value: 240, version: 3} 1849 ], 1850 version: 4 1851 } 1852 ], 1853 version: 5 1854 }, 1855 %Day16.Packet{ 1856 type: 3, 1857 value: [ 1858 %Day16.Packet{type: 4, value: 2938, version: 6}, 1859 %Day16.Packet{type: 4, value: 3, version: 6}, 1860 %Day16.Packet{type: 4, value: 211, version: 7} 1861 ], 1862 version: 3 1863 }, 1864 %Day16.Packet{ 1865 type: 1, 1866 value: [ 1867 %Day16.Packet{ 1868 type: 7, 1869 value: [ 1870 %Day16.Packet{type: 4, value: 159, version: 0}, 1871 %Day16.Packet{type: 4, value: 159, version: 5} 1872 ], 1873 version: 0 1874 }, 1875 %Day16.Packet{type: 4, value: 28, version: 1} 1876 ], 1877 version: 4 1878 }, 1879 %Day16.Packet{type: 4, value: 84, version: 4}, 1880 %Day16.Packet{ 1881 type: 1, 1882 value: [ 1883 %Day16.Packet{type: 4, value: 235, version: 4}, 1884 %Day16.Packet{ 1885 type: 6, 1886 value: [ 1887 %Day16.Packet{type: 0, value: [%Day16.Packet{...}, ...], version: 4}, 1888 %Day16.Packet{type: 0, value: [...], ...} 1889 ], 1890 version: 3 1891 } 1892 ], 1893 version: 6 1894 }, 1895 %Day16.Packet{type: 4, value: 1425, version: 4}, 1896 %Day16.Packet{ 1897 type: 1, 1898 value: [ 1899 %Day16.Packet{ 1900 type: 7, 1901 value: [%Day16.Packet{type: 0, value: [...], ...}, %Day16.Packet{type: 0, ...}], 1902 version: 5 1903 }, 1904 %Day16.Packet{type: 4, value: 13, version: 2} 1905 ], 1906 version: 2 1907 }, 1908 %Day16.Packet{type: 0, value: [%Day16.Packet{type: 4, value: 3121, version: 6}], version: 5}, 1909 %Day16.Packet{ 1910 type: 1, 1911 value: [ 1912 %Day16.Packet{type: 4, value: 51, version: 2}, 1913 %Day16.Packet{type: 4, value: 61, ...}, 1914 %Day16.Packet{type: 4, ...} 1915 ], 1916 version: 4 1917 }, 1918 %Day16.Packet{ 1919 type: 1, 1920 value: [%Day16.Packet{type: 4, value: 1393, ...}, %Day16.Packet{type: 5, ...}], 1921 version: 3 1922 }, 1923 %Day16.Packet{type: 1, value: [%Day16.Packet{type: 7, ...}, %Day16.Packet{...}], version: 3}, 1924 %Day16.Packet{type: 1, value: [%Day16.Packet{...}, ...], version: 7}, 1925 %Day16.Packet{type: 3, value: [...], ...}, 1926 %Day16.Packet{type: 2, ...}, 1927 %Day16.Packet{...}, 1928 ... 1929 ], 1930 version: 3 1931} 1932``` 1933 1934### Task 1 1935 1936```elixir 1937defmodule Day16.Task1 do 1938 alias Day16.Packet 1939 1940 def sum(%Packet{type: 4, version: version}), do: version 1941 1942 def sum(%Packet{version: version, value: value}) do 1943 Enum.reduce(value, version, &(sum(&1) + &2)) 1944 end 1945end 1946 1947Day16.Task1.sum(input) 1948``` 1949 1950```output 1951949 1952``` 1953 1954### Task 2 1955 1956```elixir 1957defmodule Day16.Task2 do 1958 alias Day16.Packet 1959 1960 def evaluate(%Packet{type: 0} = packet), do: reduce(packet, 0, &+/2) 1961 def evaluate(%Packet{type: 1} = packet), do: reduce(packet, 1, &*/2) 1962 def evaluate(%Packet{type: 2} = packet), do: reduce(packet, :inf, &min/2) 1963 def evaluate(%Packet{type: 3} = packet), do: reduce(packet, 0, &max/2) 1964 1965 def evaluate(%Packet{type: 4, value: value}), do: value 1966 1967 def evaluate(%Packet{type: 5} = packet), do: compare(packet, &>/2) 1968 def evaluate(%Packet{type: 6} = packet), do: compare(packet, &</2) 1969 def evaluate(%Packet{type: 7} = packet), do: compare(packet, &==/2) 1970 1971 defp reduce(%Packet{value: value}, initial, op) do 1972 Enum.reduce(value, initial, &op.(evaluate(&1), &2)) 1973 end 1974 1975 defp compare(%Packet{value: [a, b]}, op) do 1976 if op.(evaluate(a), evaluate(b)), do: 1, else: 0 1977 end 1978end 1979 1980Day16.Task2.evaluate(input) 1981``` 1982 1983```output 19841114600142730 1985```