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

Day 4

day_4.livemd

Day 4

Setup

Mix.install([
  {:kino, "~> 0.4.1"}
])
input = Kino.Input.textarea("Input")
input =
  input
  |> Kino.Input.read()
  |> String.split("\n\n", trim: true)

# Split up the bingo callouts
callouts = input |> Enum.at(0) |> String.split(",", trim: true) |> Enum.map(&String.to_integer/1)
# Build the boards into a concat array of x, y axis
boards =
  input
  |> Enum.drop(1)
  |> Enum.map(
    &(&1
      |> String.split("\n", trim: true)
      |> Enum.map(fn x ->
        String.split(x, " ", trim: true)
        |> Enum.map(fn y -> String.to_integer(y) end)
      end))
  )
  |> Enum.map(&(&1 |> Enum.concat(Enum.map(Enum.zip(&1), fn x -> Tuple.to_list(x) end))))

Part 1

defmodule Bingo do
  defp callout(board, input, index) do
    if Enum.any?(board, fn x -> Enum.empty?(x) end) do
      sum =
        board
        |> Enum.take(5)
        |> Enum.reduce(0, fn x, acc -> acc + Enum.sum(x) end)

      %{index: index, score: sum * Enum.at(input, index - 1)}
    else
      board
      |> Enum.map(&(&1 |> Enum.filter(fn x -> x != Enum.at(input, index) end)))
      |> callout(input, index + 1)
    end
  end

  def play(board, input) do
    callout(board, input, 0)
  end
end

winning_board =
  boards
  |> Enum.map(fn x -> Bingo.play(x, callouts) end)
  |> Enum.min_by(fn x -> x.index end)

winning_board.score

Part 2

winning_board =
  boards
  |> Enum.map(fn x -> Bingo.play(x, callouts) end)
  |> Enum.max_by(fn x -> x.index end)