Day 7
Mix.install([
{:kino, "~> 0.11.3"}
])
Input
example = """
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
"""
input = Kino.Input.textarea("Input", default: example)
Part 1
expected = [765 * 1, 220 * 2, 28 * 3, 684 * 4, 483 * 5]
[765, 440, 84, 2736, 2415]
defmodule Part1 do
def parse(input, joker \\ 11) do
for line <- String.split(input, "\n", trim: true) do
[hand, bid] = String.split(line, " ")
labels =
for c <- String.to_charlist(hand) do
case c do
?T -> 10
?J -> joker
?Q -> 12
?K -> 13
?A -> 14
_ -> c - ?0
end
end
{labels, String.to_integer(bid)}
end
end
def type(hand) do
freq =
Enum.frequencies(hand)
|> Map.values()
|> Enum.sort(:desc)
case freq do
[5] -> 7
[4, 1] -> 6
[3, 2] -> 5
[3, 1, 1] -> 4
[2, 2, 1] -> 3
[2, 1, 1, 1] -> 2
[1, 1, 1, 1, 1] -> 1
end
end
def tiebreak(list) do
Enum.sort_by(list, &elem(&1, 0))
|> Enum.map(&elem(&1, 1))
end
def run(input) do
parse(input)
|> Enum.group_by(fn {hand, _} -> type(hand) end)
|> Enum.sort_by(&elem(&1, 0))
|> Enum.flat_map(fn {_type, list} -> tiebreak(list) end)
|> Enum.with_index(1)
|> Enum.map(fn {bid, rank} -> bid * rank end)
end
end
Part1.run(example) == expected
true
Kino.Input.read(input)
|> Part1.run()
|> Enum.sum()
|> then(&Kino.Markdown.new("Part 1: #{&1}"))
Part 2
expected = 5905
5905
defmodule Part2 do
def replace_zero(hand, replacement) do
Enum.map(hand, fn
0 -> replacement
n -> n
end)
end
def type(hand) do
jokers = Enum.count(hand, &(&1 == 0))
if jokers in [0, 5] do
Part1.type(hand)
else
hand
|> Enum.uniq()
|> Enum.map(&replace_zero(hand, &1))
|> Enum.map(&Part1.type/1)
|> Enum.max()
end
end
def run(input) do
Part1.parse(input, 0)
|> Enum.group_by(fn {hand, _} -> type(hand) end)
|> Enum.sort_by(&elem(&1, 0))
|> Enum.flat_map(fn {_type, list} -> Part1.tiebreak(list) end)
|> Enum.with_index(1)
|> Enum.map(fn {bid, rank} -> bid * rank end)
|> Enum.sum()
end
end
Part2.run(example) == expected
true
Kino.Input.read(input)
|> Part2.run()
|> then(&Kino.Markdown.new("Part 2: #{&1}"))