Advent of Code 2023 - Day 07
Mix.install([
{:kino, "~> 0.11.0"},
{:kino_aoc, github: "ljgago/kino_aoc"},
{:explorer, "~> 0.7.0"},
{:kino_explorer, "~> 0.1.10"}
])
Input
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2023", "7", System.fetch_env!("LB_AOC_SESSION"))
require Explorer.DataFrame, as: DF
alias Explorer.Series
{hands, bids} =
puzzle_input
|> String.split(["\n", " "])
|> Enum.chunk_every(2)
|> Enum.map(&List.to_tuple/1)
|> Enum.unzip()
init_df =
DF.new(hand: hands, bid: bids)
|> DF.mutate(bid: Series.cast(bid, :integer))
hand_to_cards = fn hand, j_value ->
hand
|> String.split("", trim: true)
|> Enum.map(fn
"A" -> 14
"K" -> 13
"Q" -> 12
"J" -> j_value
"T" -> 10
x -> String.to_integer(x)
end)
end
put_cards = fn df, j_value ->
[c1, c2, c3, c4, c5] =
df["hand"]
|> Series.to_list()
|> Stream.map(&hand_to_cards.(&1, j_value))
|> Enum.zip_with(&Function.identity/1)
df
|> DF.put(:c1, Series.from_list(c1))
|> DF.put(:c2, Series.from_list(c2))
|> DF.put(:c3, Series.from_list(c3))
|> DF.put(:c4, Series.from_list(c4))
|> DF.put(:c5, Series.from_list(c5))
end
put_strength = fn df, mapper ->
{strengths, types} =
df
|> DF.select(["c1", "c2", "c3", "c4", "c5"])
|> DF.to_columns()
|> Map.values()
|> Stream.zip_with(&Function.identity/1)
|> Stream.map(&Enum.sort(&1, :desc))
|> Stream.map(mapper)
|> Enum.unzip()
df
|> DF.put(:type, Series.from_list(types))
|> DF.put(:strength, Series.from_list(strengths))
end
put_rank_and_winnings = fn df ->
total = Series.size(df["hand"])
ranks = Enum.to_list(total..1)
df
|> DF.arrange(desc: strength, desc: c1, desc: c2, desc: c3, desc: c4, desc: c5)
|> DF.put(:rank, Series.from_list(ranks))
|> DF.mutate(winnings: multiply(rank, bid))
end
Part 1
results =
init_df
|> put_cards.(11)
|> put_strength.(fn
[a, a, a, a, a] -> {6, "five_of_a_kind"}
[a, a, a, a, _] -> {5, "four_of_a_kind"}
[_, a, a, a, a] -> {5, "four_of_a_kind"}
[a, a, a, b, b] -> {4, "full_house"}
[a, a, b, b, b] -> {4, "full_house"}
[a, a, a, _, _] -> {3, "three_of_a_kind"}
[_, a, a, a, _] -> {3, "three_of_a_kind"}
[_, _, a, a, a] -> {3, "three_of_a_kind"}
[a, a, b, b, _] -> {2, "two_pair"}
[a, a, _, b, b] -> {2, "two_pair"}
[_, a, a, b, b] -> {2, "two_pair"}
[a, a, _, _, _] -> {1, "one_pair"}
[_, a, a, _, _] -> {1, "one_pair"}
[_, _, a, a, _] -> {1, "one_pair"}
[_, _, _, a, a] -> {1, "one_pair"}
[_, _, _, _, _] -> {0, "high_card"}
end)
|> put_rank_and_winnings.()
|> DF.select(["hand", "type", "rank", "bid", "winnings"])
DF.summarise(results, total_winnings: sum(winnings))
Part 2
results =
init_df
|> put_cards.(1)
|> put_strength.(fn
[a, a, a, a, a] -> {6, "five_of_a_kind"}
[a, a, a, a, 1] -> {6, "five_of_a_kind"}
[a, a, a, 1, 1] -> {6, "five_of_a_kind"}
[a, a, 1, 1, 1] -> {6, "five_of_a_kind"}
[_, 1, 1, 1, 1] -> {6, "five_of_a_kind"}
[a, a, a, a, _] -> {5, "four_of_a_kind"}
[_, a, a, a, a] -> {5, "four_of_a_kind"}
[a, a, a, _, 1] -> {5, "four_of_a_kind"}
[_, a, a, a, 1] -> {5, "four_of_a_kind"}
[a, a, _, 1, 1] -> {5, "four_of_a_kind"}
[_, a, a, 1, 1] -> {5, "four_of_a_kind"}
[_, _, 1, 1, 1] -> {5, "four_of_a_kind"}
[a, a, a, b, b] -> {4, "full_house"}
[a, a, b, b, b] -> {4, "full_house"}
[a, a, a, _, 1] -> {4, "full_house"}
[a, a, b, b, 1] -> {4, "full_house"}
[a, a, b, b, 1] -> {4, "full_house"}
[a, a, _, 1, 1] -> {4, "full_house"}
[a, a, a, _, _] -> {3, "three_of_a_kind"}
[_, a, a, a, _] -> {3, "three_of_a_kind"}
[_, _, a, a, a] -> {3, "three_of_a_kind"}
[a, a, _, _, 1] -> {3, "three_of_a_kind"}
[_, a, a, _, 1] -> {3, "three_of_a_kind"}
[_, _, a, a, 1] -> {3, "three_of_a_kind"}
[_, _, _, 1, 1] -> {3, "three_of_a_kind"}
[a, a, b, b, _] -> {2, "two_pair"}
[a, a, _, b, b] -> {2, "two_pair"}
[_, a, a, b, b] -> {2, "two_pair"}
[a, a, _, _, 1] -> {2, "two_pair"}
[a, a, _, _, _] -> {1, "one_pair"}
[_, a, a, _, _] -> {1, "one_pair"}
[_, _, a, a, _] -> {1, "one_pair"}
[_, _, _, a, a] -> {1, "one_pair"}
[_, _, _, _, 1] -> {1, "one_pair"}
[_, _, _, _, _] -> {0, "high_card"}
end)
|> put_rank_and_winnings.()
|> DF.select(["hand", "type", "rank", "bid", "winnings"])
DF.summarise(results, total_winnings: sum(winnings))