-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday07.fsx
140 lines (115 loc) · 4.13 KB
/
day07.fsx
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
open System
open System.Text.RegularExpressions
// --- Part A ---
let labels = ['A';'K';'Q';'J';'T';'9';'8';'7';'6';'5';'4';'3';'2']
let labelScores =
List.zip
labels
[labels.Length..(-1)..1]
|> Map.ofList
type HandScore = FiveOfAKind=7 | FourOfAKind=6 | FullHouse=5 | ThreeOfAKind=4 | TwoPair=3 | OnePair=2 | HighCard=1 | Unscored=0
type Hand = {
Cards: char list
Bet: int
HandStrength : HandScore
CardValues : int list
}
let scoreGroup (groupedHand: List<char * char list>) =
if groupedHand.Length = 1 then // five cards same label
HandScore.FiveOfAKind
else if groupedHand.Length = 2 && (snd groupedHand[0]).Length = 4 then // four cards same label
HandScore.FourOfAKind
else if groupedHand.Length = 2 then // three cards same, two cards same
HandScore.FullHouse
else if groupedHand.Length = 3 && (snd groupedHand[0]).Length = 3 then // three cards same, two cards different
HandScore.ThreeOfAKind
else if (snd groupedHand[0]).Length = 2 && (snd groupedHand[1]).Length = 2 then // two cards same, two cards same
HandScore.TwoPair
else if (snd groupedHand[0]).Length = 2 then // two cards same
HandScore.OnePair
else
HandScore.HighCard
let scoreHand (hand: char list) =
hand
|> List.groupBy (fun c -> c)
|> List.sortByDescending (fun (_, ls) -> ls.Length)
|> scoreGroup
let handExpression = Regex "([0-9AKQJT]{5}) ([0-9]+)"
let parseHand (line: string) =
let res = handExpression.Match line
{
Cards = res.Groups[1].Value |> Seq.toList
Bet = res.Groups[2].Value |> int
HandStrength = HandScore.Unscored
CardValues = []
}
{ Cards = ['3';'2';'T';'3';'K']; Bet = 765; HandStrength = HandScore.Unscored; CardValues = []} = parseHand "32T3K 765"
// identifies what kind of hand and scores the individual cards
let rankHand (labelScores: Map<char, int>) (hand: Hand) =
{
hand with
HandStrength = scoreHand hand.Cards
CardValues = hand.Cards |> List.map (fun c -> labelScores[c])
}
let sortHands (hands: Hand list) =
hands
|> List.sortBy (fun h -> h.HandStrength, h.CardValues)
let example = [
"32T3K 765"
"T55J5 684"
"KK677 28"
"KTJJT 220"
"QQQJA 483"
]
let partA (lines: string list) =
lines
|> List.map (fun l -> l |> parseHand |> rankHand labelScores)
|> List.sortBy (fun h -> h.HandStrength, h.CardValues)
|> List.zip [1..lines.Length]
|> List.map (fun (rank: int, hand: Hand) -> rank * hand.Bet)
|> List.sum
partA example
let lines = (IO.File.ReadAllLines "day07inp.txt") |> List.ofSeq
partA lines
// --- Part B ---
let revisedLabels = ['A';'K';'Q';'T';'9';'8';'7';'6';'5';'4';'3';'2';'J']
let revisedLabelScores =
List.zip
revisedLabels
[revisedLabels.Length..(-1)..1]
|> Map.ofList
let mergeJokers (groups: List<char * char list>) =
if groups.Length = 1 then
groups
else
let splitter = groups |> List.tryFind (fun g -> (fst g) = 'J')
match splitter with
| Some (_, js) ->
let jokerlessGroup = groups |> List.filter (fun g -> not((fst g) = 'J'))
let (c, ls) = jokerlessGroup[0]
(c, List.append ls js) :: jokerlessGroup.Tail
| None -> groups
mergeJokers [('A', ['A';'A']); ('J', ['J'])]
let scoreHandRevised (hand: char list) =
hand
|> List.groupBy (fun c -> c)
|> List.sortByDescending (fun (_, ls) -> ls.Length)
|> mergeJokers
|> scoreGroup
// identifies what kind of hand and scores the individual cards
let rankHandRevised (scores: Map<char, int>) (hand: Hand) =
{
hand with
HandStrength = scoreHandRevised hand.Cards
CardValues = hand.Cards |> List.map (fun c -> scores[c])
}
let partB (lines: string list) =
lines
|> List.map (fun l -> l |> parseHand |> rankHandRevised revisedLabelScores)
|> List.sortBy (fun h -> h.HandStrength, h.CardValues)
|> List.zip [1..lines.Length]
|> List.map (fun (rank: int, hand: Hand) -> rank * hand.Bet)
|> List.sum
partB example
partB lines
// 426350789 is wrong