Day 4: Giant Squid
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Setup
[numbers_str | boards_str] =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
numbers = numbers_str |> String.split(",") |> Enum.map(&String.to_integer/1)
boards =
boards_str
|> Enum.chunk_every(5)
|> Enum.map(fn board_str ->
board_str
|> Enum.map(fn board_line ->
board_line |> String.split() |> Enum.map(&String.to_integer/1)
end)
end)
Part 1
https://adventofcode.com/2021/day/4
Solve: Part 1
defmodule Day4.Part1.Bingo do
def has_bingo?(board) do
rows = board
columns = board |> transpost()
[rows, columns] |> Enum.any?(&do_has_bingo?(&1))
end
def mark_number(board, number) do
board
|> Enum.map(fn line -> line |> replace_number_with_nil(number) end)
end
def calc_score(board, bingo_number) do
unmarked_number_sum = board |> List.flatten() |> Enum.reject(&is_nil(&1)) |> Enum.sum()
unmarked_number_sum * bingo_number
end
defp do_has_bingo?(lines) do
lines |> Enum.any?(fn line -> Enum.all?(line, &is_nil(&1)) end)
end
defp replace_number_with_nil(line, number) do
line
|> Enum.map(fn
^number -> nil
other -> other
end)
end
defp transpost(board) do
board |> Enum.zip_with(& &1)
end
end
alias Day4.Part1.Bingo
{_, bingo_number, bingo_board} =
numbers
|> Enum.reduce_while(
{boards, _bingo_number = nil, _bingo_board = nil},
fn number, {boards, nil, nil} ->
new_boards = boards |> Enum.map(&Bingo.mark_number(&1, number))
case new_boards |> Enum.find(&(&1 |> Bingo.has_bingo?())) do
nil ->
{:cont, {new_boards, nil, nil}}
bingo_board ->
{:halt, {new_boards, number, bingo_board}}
end
end
)
_answer = Bingo.calc_score(bingo_board, bingo_number)
Part 2
https://adventofcode.com/2021/day/4#part2
Solve: Part 2
{_, bingo_number, bingo_board} =
numbers
|> Enum.reduce_while({boards, _bingo_number = nil, _bingo_board = nil}, fn number,
{boards, nil, nil} ->
{bingo_boards, rest_boards} =
boards
|> Enum.map(&Bingo.mark_number(&1, number))
|> Enum.split_with(&Bingo.has_bingo?(&1))
case {bingo_boards, rest_boards} do
{[last_board], []} -> {:halt, {[], number, last_board}}
_ -> {:cont, {rest_boards, nil, nil}}
end
end)
_answer = Bingo.calc_score(bingo_board, bingo_number)