-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathday_07.ex
101 lines (88 loc) · 2.43 KB
/
day_07.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
defmodule AdventOfCode.Y2023.Day07 do
@moduledoc """
--- Day 7: Camel Cards ---
Problem Link: https://adventofcode.com/2023/day/7
Difficulty: m
Tags: map pattern-matching
"""
alias AdventOfCode.Helpers.{InputReader, Transformers}
@card_rank_1 %{
"2" => 1,
"3" => 2,
"4" => 3,
"5" => 4,
"6" => 5,
"7" => 6,
"8" => 7,
"9" => 8,
"T" => 9,
"J" => 10,
"Q" => 11,
"K" => 12,
"A" => 13
}
@card_rank_2 %{@card_rank_1 | "J" => 0}
def input, do: InputReader.read_from_file(2023, 7)
def run(input \\ input()) do
input = parse(input)
{run_1(input), run_2(input)}
end
defp run_1(input), do: get_winnings(input, @card_rank_1)
defp run_2(input) do
input
|> Enum.map(fn {rank, hand, bid} -> {jokered_rank(rank, hand), hand, bid} end)
|> get_winnings(@card_rank_2)
end
def get_winnings(card_configuration, value_mapping) do
card_configuration
|> Enum.group_by(&elem(&1, 0))
|> Enum.sort_by(fn {rank, _} -> rank end)
|> Enum.flat_map(fn {_, hands} ->
hands |> Enum.sort(fn {_, h1, _}, {_, h2, _} -> smaller?(h1, h2, value_mapping) end)
end)
|> Enum.with_index(1)
|> Enum.reduce(0, fn {{_, _, bid}, rank}, acc -> acc + bid * rank end)
end
def parse(data \\ input()) do
data
|> Transformers.lines()
|> Enum.map(fn card ->
[hand, bid] = String.split(card, " ")
hand = String.graphemes(hand)
{get_rank(hand), hand, String.to_integer(bid)}
end)
end
def frequency(hand) do
hand
|> Enum.group_by(& &1)
|> Map.new(fn {a, b} -> {a, length(b)} end)
end
def jokered_rank(rank, hand), do: jokered_rank({rank, frequency(hand)["J"]})
def jokered_rank({rank, nil}), do: rank
def jokered_rank({1, _}), do: 2
def jokered_rank({2, _}), do: 4
def jokered_rank({3, 1}), do: 5
def jokered_rank({3, 2}), do: 6
def jokered_rank({4, _}), do: 6
def jokered_rank({5, _}), do: 7
def jokered_rank({6, _}), do: 7
def jokered_rank({rank, _}), do: rank
def get_rank(hand) do
case hand |> frequency() |> Map.values() |> Enum.sort() do
[1, 1, 1, 1, 1] -> 1
[1, 1, 1, 2] -> 2
[1, 2, 2] -> 3
[1, 1, 3] -> 4
[2, 3] -> 5
[1, 4] -> 6
[5] -> 7
end
end
def smaller?([a | rest_1], [b | rest_2], mapping) do
cond do
mapping[a] > mapping[b] -> false
mapping[a] < mapping[b] -> true
true -> smaller?(rest_1, rest_2, mapping)
end
end
end