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

Day 4

2021/day4.livemd

Day 4

Input

# Livebook Input (atleast the default one) doesn't support multiline
[winning_nums | boards] = IO.gets(:input) |> String.split(~r{\s}, trim: true)

winning_nums =
  winning_nums
  |> String.split(",")
  |> Enum.map(&String.to_integer/1)

boards =
  boards
  |> Enum.map(&String.to_integer/1)
  |> Enum.chunk_every(5)
  |> Enum.chunk_every(5)

Part 1

calculate_card = fn bingo_card, last_number ->
  List.flatten(bingo_card)
  |> Enum.reject(&(&1 == -1))
  |> Enum.sum()
  |> Kernel.*(last_number)
  |> IO.inspect()

  # exit after first find
  Kernel.exit(:ok)
end

# mark all matching numbers inside boards
mark_boards = fn boards, n ->
  List.flatten(boards)
  |> Enum.map(&if(&1 == n, do: -1, else: &1))
  # convert back to 5x5 boards
  |> Enum.chunk_every(5)
  |> Enum.chunk_every(5)
end

check_boards = fn boards, last_n ->
  Enum.each(boards, fn b ->
    for i <- 0..4 do
      # horizontal || vertical
      if Enum.sum(Enum.at(b, i)) == -5 || Enum.sum(Enum.map(b, &amp;Enum.at(&amp;1, i))) == -5 do
        calculate_card.(b, last_n)
      end
    end
  end)

  boards
end

Enum.reduce(winning_nums, boards, fn n, b -> mark_boards.(b, n) |> check_boards.(n) end)

Part 2

# So ugly I had to hide it