-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday7.hs
179 lines (150 loc) · 4.73 KB
/
day7.hs
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import Data.List
import Data.Map qualified as M
import Data.Maybe (fromJust)
import Data.Set qualified as S
import Data.Tuple (swap)
import GHC.Utils.Misc (count)
data Hand = Hand {cards :: [Card], bid :: Int}
deriving (Show)
parseHand :: String -> Hand
parseHand s = Hand {cards = map parseCard (head parts), bid = read (parts !! 1)}
where
parts = words s
data Hand' = Hand' {cards' :: [Card'], bid' :: Int}
deriving (Show)
parseHand' :: String -> Hand'
parseHand' s = Hand' {cards' = map parseCard' (head parts), bid' = read (parts !! 1)}
where
parts = words s
instance Eq Hand' where
(==) :: Hand' -> Hand' -> Bool
(==) (Hand' c1 _) (Hand' c2 _) = c1 == c2
instance Eq Hand where
(==) :: Hand -> Hand -> Bool
(==) (Hand c1 _) (Hand c2 _) = c1 == c2
data Card
= Two
| Three
| Four
| Five
| Six
| Seven
| Eight
| Nine
| Ten
| Jack
| Queen
| King
| Ace
deriving (Enum, Eq, Show, Ord)
data Card'
= Joker
| Two'
| Three'
| Four'
| Five'
| Six'
| Seven'
| Eight'
| Nine'
| Ten'
| Queen'
| King'
| Ace'
deriving (Enum, Eq, Show, Ord)
parseCard :: Char -> Card
parseCard s = case s of
'2' -> Two
'3' -> Three
'4' -> Four
'5' -> Five
'6' -> Six
'7' -> Seven
'8' -> Eight
'9' -> Nine
'T' -> Ten
'J' -> Jack
'Q' -> Queen
'K' -> King
'A' -> Ace
_ -> error ("Unknown value was parsed as a card: " ++ show s)
parseCard' :: Char -> Card'
parseCard' s = case s of
'2' -> Two'
'3' -> Three'
'4' -> Four'
'5' -> Five'
'6' -> Six'
'7' -> Seven'
'8' -> Eight'
'9' -> Nine'
'T' -> Ten'
'J' -> Joker
'Q' -> Queen'
'K' -> King'
'A' -> Ace'
_ -> error ("Unknown value was parsed as a card: " ++ show s)
data HandValue = FiveKind | FourKind | FullHouse | ThreeKind | TwoPair | OnePair | HighCard
deriving (Eq, Ord, Show, Enum)
valueOfHand :: Hand -> HandValue
valueOfHand (Hand cards _) = case () of
_
| length cardSet == 1 -> FiveKind
| fst (head cardSet) == 4 -> FourKind
| fst (head cardSet) == 3 && fst (cardSet !! 1) == 2 -> FullHouse
| fst (head cardSet) == 3 && length cardSet == 3 -> ThreeKind
| fst (head cardSet) == 2 && fst (cardSet !! 1) == 2 -> TwoPair
| fst (head cardSet) == 2 -> OnePair
| otherwise -> HighCard
where
cardSet = reverse (sort (map swap (M.toList ((M.fromListWith (+) . map (,1)) cards))))
-- NOTE: This still doesn't work because of some edge cases with Jokers being the dominant type
-- We shouldn't just remove them indiscriminantly
valueOfHand' :: Hand' -> HandValue
valueOfHand' (Hand' cards _) = case () of
_
| length cardSet == 1 -> FiveKind
| fst (head cardSet) == 4 -> toEnum (fromEnum FourKind - min jokers 1)
| fst (head cardSet) == 3 && fst (cardSet !! 1) == 2 -> toEnum (fromEnum FullHouse - min jokers 2)
-- With three kind, we can change one to get to four kind
| fst (head cardSet) == 3 && length cardSet == 3 -> toEnum (fromEnum ThreeKind - min (if jokers > 0 then jokers + 1 else 0) 2)
-- With two pair, we can get to full house with one card
| fst (head cardSet) == 2 && fst (cardSet !! 1) == 2 -> toEnum (fromEnum TwoPair - min (if jokers > 0 then jokers + 1 else 0) 3)
| fst (head cardSet) == 2 -> toEnum (fromEnum OnePair - min jokers 5)
| otherwise -> toEnum (fromEnum HighCard - min jokers 6)
where
removeFirstJoker :: [(Int, Card')] -> [(Int, Card')]
removeFirstJoker arr@[(_, Joker)] = arr
removeFirstJoker ((_, Joker) : rest) = rest
removeFirstJoker arr = arr
cardSet = removeFirstJoker (reverse (sort (map swap (M.toList ((M.fromListWith (+) . map (,1)) cards)))))
jokers = count (== Joker) cards
instance Ord Hand where
compare :: Hand -> Hand -> Ordering
compare h1@(Hand c1 _) h2@(Hand c2 _) = case compare (valueOfHand h1) (valueOfHand h2) of
EQ -> fromJust (find (/= EQ) (map (\(x, y) -> compare y x) (zip c1 c2)))
cmp -> cmp
instance Ord Hand' where
compare :: Hand' -> Hand' -> Ordering
compare h1@(Hand' c1 _) h2@(Hand' c2 _) = case compare (valueOfHand' h1) (valueOfHand' h2) of
EQ -> fromJust (find (/= EQ) (map (\(x, y) -> compare y x) (zip c1 c2)))
cmp -> cmp
totalScore :: [Hand] -> Int
totalScore hands = sum (zipWith (\hand rank -> bid hand * rank) hands [1 ..])
totalScore' :: [Hand'] -> Int
totalScore' hands = sum (zipWith (\hand rank -> bid' hand * rank) hands [1 ..])
main :: IO ()
main = do
input <- fmap lines (readFile "input")
let hands = reverse (sort (map parseHand input))
print hands
print (map valueOfHand hands)
-- Part 1
print (totalScore hands)
let hands' = reverse (sort (map parseHand' input))
print hands'
let vals = map valueOfHand' hands'
print vals
let jokers = 4
print (toEnum (fromEnum HighCard - min jokers 6) :: HandValue)
print (totalScore' hands')