Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 4: Giant Squid

day4/solution.livemd

Day 4: Giant Squid

Part 1

[drawn_nums_raw | raw_boards] =
  """
  7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1

  22 13 17 11  0
   8  2 23  4 24
  21  9 14 16  7
   6 10  3 18  5
   1 12 20 15 19

   3 15  0  2 22
   9 18 13 17  5
  19  8  7 25 23
  20 11 10 24  4
  14 21 16 12  6

  14 21 17 24  4
  10 16 15  9 19
  18  8 23 26 20
  22 11 13  6  5
   2  0 12  3  7
  """
  |> String.split("\n\n")

boards =
  raw_boards
  |> Enum.map(fn e ->
    String.split(e, ["\n", " "], trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Enum.chunk_every(5)
  end)

drawn_nums = drawn_nums_raw |> String.split(",") |> Enum.map(&String.to_integer/1)
[7, 4, 9, 5, 11, 17, 23, 2, 0, 14, 21, 24, 10, 16, 13, 6, 15, 25, 12, 22, 18, 20, 8, 19, 3, 26, 1]
defmodule Part1 do
  def transpose(board), do: board |> List.zip() |> Enum.map(&Tuple.to_list/1)

  def draw_num_and_mark(boards, drawn_number) do
    boards
    |> Enum.map(fn board ->
      board |> Enum.map(fn row -> Enum.map(row, &if(&1 == drawn_number, do: "x", else: &1)) end)
    end)
  end

  def winning?(board) do
    winning_row = board |> Enum.any?(fn row -> Enum.all?(row, &(&1 == "x")) end)
    winning_col = transpose(board) |> Enum.any?(fn row -> Enum.all?(row, &(&1 == "x")) end)

    winning_row || winning_col
  end

  def find_first_winning_board(_, [], _, _), do: raise("No winning boards")

  def find_first_winning_board(boards, [drawn_number | other_nums], nil, _) do
    new_boards = draw_num_and_mark(boards, drawn_number)

    find_first_winning_board(
      new_boards,
      other_nums,
      Enum.find(new_boards, &winning?/1),
      drawn_number
    )
  end

  def find_first_winning_board(_, _, winning_board, last_drawn), do: {winning_board, last_drawn}

  def find_last_winning_board(_, [], _, _), do: raise("No winning boards")

  def find_last_winning_board([board | []], nums, _),
    do: find_first_winning_board([board], nums, nil, nil)

  def find_last_winning_board(boards, [drawn_number | other_nums], _) do
    draw_num_and_mark(boards, drawn_number)
    |> Enum.filter(fn board -> !winning?(board) end)
    |> find_last_winning_board(other_nums, drawn_number)
  end
end

{winning_board, last_drawn} = Part1.find_first_winning_board(boards, drawn_nums, nil, nil)

board_sum =
  winning_board
  |> Enum.reduce(0, fn r, a ->
    a + (r |> Enum.filter(&(&1 != "x")) |> Enum.sum())
  end)

IO.inspect(board_sum * last_drawn, label: "Part 1 result")
Part 1 result: 4512
4512
[drawn_nums_raw | raw_boards] =
  """
  93,35,66,15,6,51,49,67,16,77,80,8,1,57,99,92,14,9,13,23,33,11,43,50,60,96,40,25,22,39,56,18,2,7,34,68,26,90,75,41,4,95,71,30,42,5,46,55,27,98,79,12,65,73,29,28,17,48,81,32,59,63,85,91,52,21,38,31,61,83,97,62,44,70,19,69,36,47,74,58,78,24,72,0,10,88,37,87,3,45,82,76,54,84,20,94,86,53,64,89

  14 33 79 61 44
  85 60 38 13 48
  51 34 11 19  7
  21 30 73  6 76
  41  4 65 18 91

   3 82 68 26 93
  61 90 29 69 92
  60 94 99  6 83
  77 80  2 58 55
  59 65 95 38 62

  41  9 73 71 74
  66 24 45  5 55
  97 82 53 63 16
  12 19 88 87 27
  31  8 75 98 83

  63 24 86 90 45
  41 92 42 83 77
  64 28 54 94 10
  15 93 57 29 50
  23 39 37 48 38

   1 31  7  0 54
   9 59 79 19 96
  51 14 77 38 45
  30 76 42 65 91
  72 60 37 43 71

  22 81 40 97 27
  83 28 41  1 76
  69 68 64 57 78
  59 38 63 89 29
   8 58 18 66 72

  39 32 21 94 37
  20  1 66 82 52
  10 56 40 13 62
  59 96 44 75 50
  41 83  6 90 28

  90 33  1 57 34
  14 86 93 92 68
  54 37 95 11 77
  88 13 62 72 48
  96 65 67 85 80

  47 48 82 96 85
  78 91 42 38 11
  79 94 49 24 27
  56 92 72 45 73
  75  0 70  4 68

  48 51 94 17 58
  37 88 56 66 16
  27 97 14 45 83
  53 39  6  5 68
  47 57 28 31 11

  35 66 19 68 73
  41 49 10 80 48
  39 50 79 23 59
  15 45 40 17 75
  88 86 71  8  0

  58 48 41 22 11
  97 59 17 71 44
   6 24 49 84 42
  89 27 23 82  9
  60 86 90 65 34

  11 58  2 98 26
  90 52 60 14 12
  69 63 56 36 30
   3 44 19  5 85
  95 84 31 51 79

  39 62 64 29 24
  56  9  0 18  3
  22 74 77 47 98
  55 93 79  4 33
  78 53 11 26 75

  38 82  8 25 55
  74  1 21 30 46
  12  4 62 45 52
  24 39  0 92 15
  19 54 51 57 88

  16 28 48 19 43
  58 96 67 22 61
   8  9 74  5 81
  78 59 49 71 15
  82 46 42 32 70

  73 89 80 92 42
   4 60 99 75 39
   5 50 64 98 91
  49 11  9 51 85
  27 97 54 93 14

  70 41 37 53 62
   0 57 48 39 61
  10 85 59 74 76
   2  7  1  4 81
  26 78 60 80 72

   8 50 43 73 80
  74 86 64 95 30
  45 69 71 65 55
  52 66 36 62 60
  25 53 63 46  5

   5 57 15 82 46
  23 96 72 29 43
  98 91 42 51 99
  70 25 64 45 16
   4 40 48 97 11

  37 93 48 23 99
  98  8 21 78 36
  52 73  5 55 11
  63 42 88 38 94
   1 80 71 68 15

  51 34 66 87 17
  20 54 74 14 55
  84 64 96 31  2
  62 43 76  5 45
  98 71 50 56 82

  13 59 67 25 94
  41 89 27 60  2
  77 31 48 63 62
  24 49 32 76 87
  70 85 51 52 66

  31 22 23 36 47
  45 55 61 89 72
  62 81 35 79  8
  24 82 38 91 76
  74  5 29 94 58

   2 41  6 13 34
  86 46 44 38 56
  28 19 50  1 12
  96 23 33 91 64
   7 89 59  9 70

  81 69 97 10 87
  83 56  7 53 96
  93 42 68 29 62
  78 66  2 55 60
   4  5 15 98 99

  80 40 93 94 25
  95 99 55 31 12
  29 90 43 52 38
  51 64 92 37 77
  21  4 85 20 17

  44 73 69 38 95
  11 47 19 83 91
  96 92 22 31 21
  70 62 88 25 82
  18 40 98 34 94

   6 14 86 29 99
   8  5 15 38 90
  44 43 51 77 80
  78 32 75 83  3
  53 13 71 66 52

  55  3 93 75 54
  58 57 60 15 70
  67 51 81 96 74
   6 35 29 32 44
  38 56  5 50 88

  38 46 11 16 33
  83  6 88 93 43
  42 56 77  9 85
  76 69 49 58 22
  15 14  4 54 23

  27 84 97 50 46
  98 14 60 87 72
  20 38 74 13 32
  18 96 92 21 99
  93 43 86 16 66

  53 12 29 78 41
  13 70 71  4 97
  44  1 37 84 49
  17  0 22 72 63
  61 66 60 32 68

  92 44 20 56 69
  73 22 18 31 48
  71 93 83 16 49
  81 89 79 38 30
  80 24 26 86 62

  82 58 76 20  5
  56 34 84 80 38
  12 49  8 52 91
  41 62  1 77 48
  23 83 51 81  2

  77  5 96 13 52
  61 85 46 54 48
  56 80 20 83 69
  39 42 28 87 16
  59 40 45 58 62

  35 87 52 85  9
  18 55 71 63 58
  86 28 20  5 68
  26 76 93 66 44
  53  2 95  6 60

  19 53 33 59 27
  58 95 74 26  9
  98 25 49 92 44
  76 20 41 66 88
  47 50 57 24 28

  54 63 31 74 72
  91 19  3 23 14
  85 44 66 55 33
  18 17 86  7 78
  42 22 15 99 93

  33 31 15 40 44
  41 86 18 94 66
  19 69 91 76 95
  99 11 70 42 56
  68 82 90 12 83

  79 21 74 63 22
  99 76 27 17 34
  91 52 14  2 26
  13 93 81 35 75
  48 62  0 39  6

  61  3 96 95 10
   4 39 22 29 49
   5  7 15 54 83
   2 33 65 62 14
   8 73 24 47 87

  24 75 54 90  5
  59 26 52 37 23
  11 36 42 47 93
  44 88 45 21 96
   6 58 73 60 86

  57  2 67 75 90
  87 51 80 35 24
  98 36 79  5 21
   6 78  0 94 25
  16  3 81 41 45

  63 84 58 52  9
  38 57 87 20 40
   5 68 14 98 29
  71 88 21 80 61
   3 43 31 48 26

   2 92 45 28 18
  89 20 90 42 99
  40 52 87 63 91
  13 31 59 24 29
  70 79 34 82 15

  95 82 62  2 53
  63 19 10 42 16
  69 28 22 92 56
  11  3 17 76 71
  58 70 27  6 93

  83 43 99 11 58
   9 79  4 76  6
  18 49 56 36 72
  31 91  8 34 78
   7 96 66 98 95

  87 31 90 33 53
  70 39 50 73  3
  89 17 64 97 65
  11 85 42 57  6
  88 44 26 47 54

  37 90 50 65 25
  68 15 87 33  0
  24 63 30 98 57
  13  7 93 22 34
  55 75 70 14 16

  48 77 51 15 33
  84 52 22 73 67
  25 47 34 95 89
   3 45 42 17 93
  56 53 68 72  8

  60 44 46 84 70
  34 94 76 79 98
  36 37 59 90 22
  23 39  2 48 15
  81  4  7  3 21

  60 58 26 10 66
  53 18 38 80 24
  93 56 11 27 21
  51 86 94 64 52
  65 57 28 98 69

  32 45 64 94 68
  66 67 53 50 16
  37 60 10 33 70
  76 87 69 78 88
  71 99 63 38 25

  54 14 31 45 40
  27 17 91 78 96
  70 84 11 98 75
   6 94 72 88 18
  65  9 56 33 92

  40 33 82 38 85
  98 91 44 26 57
  73 34 32 25 46
  58  8 16 42 95
  20  1 67 54 90

  34 88 27 63 73
  92 70  5 21 15
   1 82 74  9 23
  33 66 78 85 30
   3 75 53 37 72

  22 11 43  8 69
  57 30 72 26 58
  45 55 23 88 21
  53  0 19 31 65
  62 66 46 39 15

  57 71 75 51 44
  49 96 10 53 47
  77 93 28 91 74
  70 41 79 89 97
  26 45 59 56 80

  28 69 48 13 43
  10 75 80 58 40
   1 92 82 94 33
  47 74 60 53 18
  51 11 77  9 55

  50  3 89 47 34
  26 15 68 79 45
  94 90 19 59 73
  62 29 46 74 44
  91  5 39 10 14

  11 49 87 19  2
   9 33 71 57 66
  82 46 83 64 55
  52 76 67 15 73
  88 39 34 85 61

  34 82 64 97 39
  53 30 71 22 85
  73 86 88 93 44
  56 25 52 87  4
  67  7 31  2 83

   9  6 54 84 46
   4 75 65 63  1
  81 66 72 71 43
  17 61 51 48 35
  14 56 70 50 13

   0 48 33 27 35
   7 20  9 97 46
   8 13 52 11 24
  40 56 50 64 75
  32 92 36 54  5

  19 49 78 92 20
  97 87 80 64  9
  26 34 67 21 91
  63 85 68 88 28
  18 93 41 31 79

  97 13  9 26 58
   1 19 76 31 51
  95 65 37 48 88
  92 72 98 10 43
  69 28 29  5 62

  81 86 83 31 43
  37 95 51 42 17
  54  3 99 23 40
  15 72 16  4 78
  49 48 76 38 52

  66 97 55  6 62
  38 95 58  7 96
  61 93 45 41 50
  13 51 92  2 52
  15  8 36 37 17

  27 60 58 69 16
   0 92 24 25 61
  65 28 52 20 99
  87 12  3 21 31
  48 67 63 70 11

  51 32 36 37 62
  33 38 46  6 63
  88 97 67 72 84
  54 23  3 81 94
  59 50 40 11 21

  30 22 59 53 35
  46 88 12  9 78
  95 31 39 10 67
  86 73 42 43  1
  93 21 16 51 28

  61 98 77 62 41
  42 93 58 66 89
  64 14 18 67 76
  21 17 43 79 44
  47  0 20 95 97

  47 75 70  8 26
  82 98 13 61 96
  94 74 17 78 30
  15 85 46 31 11
  99 28 39 51 92

   8 54 19  9 30
  63 90 99  7 50
  14 45 74 65 82
  10 76 85 21 20
  80 48 94  6 93

  32 13 76 35  2
  57 51 25 43 85
  89 87 26 15 95
  24 67 33 34 14
  23 47 39 64 71

  83 82 79 50 23
  77 60 67  8 32
  55 38 33 26 37
  17 36 69 44 43
  49  9 52 70 39

  94 79 82 74 99
   7 90  6 76  3
   0 91 81 11 17
   2 28 29 22 78
  33  1 23 16 86

  53 18 72 38  1
  75 70 19 10 99
  34 60 30 61 95
  80 78 51 83 22
  25 23 11  6 44

   8 17 15 21  6
  46 79 77 11 23
  25 14 59 42 95
  50 16 90 49  2
  81 56 51 96 76

  37 27 62  8 35
  67 81 84 47 53
  32 13 80 15 66
  95 94 59 38 97
  64 26 63 75 78

  23 71 88 61 20
  35 32 59 10 67
  17 36 38 89 75
  74  8 30 57 39
  97 58 55 70 15

  82 37 71 56 15
  92 66 10  1 14
  26 60 70 50 89
  97 58 83  3 61
  41  6 35 88 13

  16  7 54  9 31
  47 91 50 17 51
   6 38 24 14 69
  48  3  0 77  5
  43 86 70 80 40

  39 94 95 47 98
  46 41 45 38 48
  18 73 56 99 76
  74 75 26 30 16
  42 11 85 86 51

  39 68 42 79 14
  48 90 75  4 41
  34 76 63 49 83
  64 86 92 98 65
  40 15 54 20  1

  17  4 47 37  8
  19 15 36  6 60
  23  5 24 87 55
  51 12 94 18 90
  81  3 86 39 88

  58 46 25 13 81
  72 17 64 28 51
  91  1 55 57 49
  20 39 11  5 52
  60 22 24 15 53

  40 50 55 39  6
  79 38 44 52 81
  83 36 11 42 88
  48  4 32  8 71
  34 65 51  2 46

  21 47 96 94 19
  31 38 55 64 24
  36 57 32  9 34
  43 61 11 41 56
  58  2  4 28 59

  47 14 83 62 76
  18 61 22 80 54
  24 87 49 13 40
  44 82 34 78 10
  94 55 29 95 71

  68 54 76  1 39
  46  4 50 82 85
  75 26 43 58 98
  29 47 49 81 12
  14 19 57 11 41

  65 38  2  0 57
  23 19  4 79 70
  88  8 73 25 34
  15 28 77 24 39
  31 97 11 62 37

  29 26 19 14 40
  12 88 22 42 96
  95 63 78 21 53
  35 50  9 39 43
  10 46 24 87 13

   4 94 52 42 67
  71 33 15 75 80
  45 49 61 64 58
  35 37 62 55 30
  87 79 31 96 41

  75 61 94  3 52
  59 13 35 53 54
  85 81 79 96 57
  36 38 40 28 93
  70 95 39 43  5

  33 79 74 21 32
   0 18 43  5 28
  82 63 66 56 27
  42 76 61 98 73
  83  9  2 96 23

  96 47 61 45 89
  40 77 15 55 25
  23 39 10 18 91
  31 70  1 30 75
  67 94 37  4 51

   3  5 10 80 89
  60 17 42 55 92
  38 32 52  0 56
  96 61 79 34 90
  43  2 98  4 27

  74 95 14 35 49
  67 66 57 76 88
  89 71 68 69 48
  20 70  3  0 12
  13 21 15 51 24
  """
  |> String.split("\n\n")

boards =
  raw_boards
  |> Enum.map(fn e ->
    String.split(e, ["\n", " "], trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Enum.chunk_every(5)
  end)

drawn_nums = drawn_nums_raw |> String.split(",") |> Enum.map(&String.to_integer/1)
[93, 35, 66, 15, 6, 51, 49, 67, 16, 77, 80, 8, 1, 57, 99, 92, 14, 9, 13, 23, 33, 11, 43, 50, 60, 96,
 40, 25, 22, 39, 56, 18, 2, 7, 34, 68, 26, 90, 75, 41, 4, 95, 71, 30, 42, 5, 46, 55, 27, 98, ...]
{winning_board, last_drawn} = Part1.find_first_winning_board(boards, drawn_nums, nil, nil)

board_sum =
  winning_board
  |> Enum.reduce(0, fn r, a ->
    a + (r |> Enum.filter(&(&1 != "x")) |> Enum.sum())
  end)

IO.inspect(board_sum * last_drawn, label: "Part 1 result")
Part 1 result: 27027
27027

Part 2

{last_winning_board, last_drawn_last_board} =
  Part1.find_last_winning_board(boards, drawn_nums, nil)
  |> IO.inspect(label: "last winning board, and drawn number")

last_board_sum =
  last_winning_board
  |> Enum.reduce(0, fn r, a ->
    a + (r |> Enum.filter(&(&1 != "x")) |> Enum.sum())
  end)

IO.inspect(last_board_sum * last_drawn_last_board, label: "Part 2 result")
last winning board, and drawn number: {[
   ["x", "x", "x", "x", "x"],
   [20, 54, "x", "x", "x"],
   [84, 64, "x", "x", "x"],
   ["x", "x", 76, "x", 45],
   ["x", "x", "x", "x", 82]
 ], 87}
Part 2 result: 36975
36975