Day 4
Setup
input = Aoc.get_input(4)
textarea = Kino.Input.textarea("Puzzle input", default: input)
test_input = """
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
"""
textarea_test = Kino.Input.textarea("Test input", default: test_input)
lines =
textarea
|> Kino.Input.read()
|> String.split("\n\n")
|> Enum.map(&String.split(&1, "\n", trim: true))
test_lines =
textarea_test
|> Kino.Input.read()
|> String.split("\n\n")
|> Enum.map(&String.split(&1, "\n", trim: true))
options = [
puzzle: "Puzzle",
test: "Test"
]
select = Kino.Input.select("Input Source", options)
lines =
select
|> Kino.Input.read()
|> case do
:puzzle -> lines
:test -> test_lines
end
:ok
Part 1
[numbers | boards] = lines
numbers = Enum.at(numbers, 0) |> String.split(",") |> IO.inspect(label: "numbers")
boards =
boards
|> Enum.map(fn rows ->
rows
|> Enum.map(&(String.split(&1, ~r{\s+}, trim: true) |> Enum.map(fn a -> {a, false} end)))
end)
{winning_board, last_call} =
numbers
|> Enum.reduce_while(boards, fn n, boards ->
# update boards
boards =
boards
|> Enum.map(fn rows ->
rows
|> Enum.map(fn row ->
row
|> Enum.map(fn
{^n, false} -> {n, true}
r -> r
end)
end)
end)
boards
|> Enum.find(fn rows ->
# check if winner
winning_row? =
rows
|> Enum.find(fn
[{_, true}, {_, true}, {_, true}, {_, true}, {_, true}] -> true
_ -> false
end)
winning_col? =
rows
|> Enum.reduce(%{}, fn row, acc ->
row
|> Enum.with_index()
|> Enum.reduce(acc, fn {{_, bool}, i}, acc ->
if bool == true do
Map.update(acc, i, 1, fn v -> v + 1 end)
else
acc
end
end)
end)
|> Enum.find(fn {_k, v} -> v == 5 end)
winning_row? || winning_col?
end)
|> case do
nil ->
{:cont, boards}
board ->
{:halt, {board, n}}
end
end)
%{false: unmarked, true: marked} =
winning_board
|> Enum.flat_map(& &1)
|> Enum.group_by(fn {_n, b?} -> b? end)
sum =
unmarked
|> Enum.map(fn {n, _} -> n |> String.to_integer() end)
|> IO.inspect(label: "unmarked")
|> Enum.sum()
|> IO.inspect(label: "sum")
marked |> Enum.map(fn {n, _} -> n |> String.to_integer() end) |> IO.inspect(label: "marked")
last_call = String.to_integer(last_call) |> IO.inspect(label: "last call")
score = sum * last_call
Part 2
[numbers | boards] = lines
numbers = Enum.at(numbers, 0) |> String.split(",") |> IO.inspect(label: "numbers")
boards =
boards
|> Enum.map(fn rows ->
rows
|> Enum.map(&(String.split(&1, ~r{\s+}, trim: true) |> Enum.map(fn a -> {a, false} end)))
end)
{winning_board, last_call} =
numbers
|> Enum.reduce_while(boards, fn n, boards ->
# update boards
boards =
boards
|> Enum.map(fn rows ->
rows
|> Enum.map(fn row ->
row
|> Enum.map(fn
{^n, false} -> {n, true}
r -> r
end)
end)
end)
boards
|> Enum.reject(fn rows ->
# check if winner
winning_row? =
rows
|> Enum.find(fn
[{_, true}, {_, true}, {_, true}, {_, true}, {_, true}] -> true
_ -> false
end)
winning_col? =
rows
|> Enum.reduce(%{}, fn row, acc ->
row
|> Enum.with_index()
|> Enum.reduce(acc, fn {{_, bool}, i}, acc ->
if bool == true do
Map.update(acc, i, 1, fn v -> v + 1 end)
else
acc
end
end)
end)
|> Enum.find(fn {_k, v} -> v == 5 end)
winning_row? || winning_col?
end)
|> case do
[] ->
[board] = boards
{:halt, {board, n}}
boards ->
{:cont, boards}
end
end)
%{false: unmarked, true: marked} =
winning_board
|> Enum.flat_map(& &1)
|> Enum.group_by(fn {_n, b?} -> b? end)
sum =
unmarked
|> Enum.map(fn {n, _} -> n |> String.to_integer() end)
|> IO.inspect(label: "unmarked", charlists: :as_lists)
|> Enum.sum()
|> IO.inspect(label: "sum")
marked |> Enum.map(fn {n, _} -> n |> String.to_integer() end) |> IO.inspect(label: "marked")
last_call = String.to_integer(last_call) |> IO.inspect(label: "last call")
score = sum * last_call