Skip to content

Instantly share code, notes, and snippets.

@Szer
Last active December 7, 2023 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Szer/3bdf613c93a3e9b50db5f207d1a278a8 to your computer and use it in GitHub Desktop.
Save Szer/3bdf613c93a3e9b50db5f207d1a278a8 to your computer and use it in GitHub Desktop.
Advent of Code 2023 7
let input2 = """32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483""" |> fun x -> x.Split('\n') // 6440
let cardPower isPart1 = function
| 'A' -> 0xE
| 'K' -> 0xD
| 'Q' -> 0xC
| 'J' -> if isPart1 then 0xB else 0x1
| 'T' -> 0xA
| x -> int x - 48
type Hand = { handPower: int; bet: int }
let parseHand isPart1 (rawHand: string) =
let [|rawCards; rawBet|] = rawHand.Split(' ')
let handPower =
(0, rawCards)
||> Seq.fold (fun result card ->
cardPower isPart1 card + (result <<< 4)
)
let counts =
rawCards
|> Seq.filter (fun x -> isPart1 || x <> 'J')
|> Seq.countBy id
|> Seq.toArray
let jokerCounts = rawCards |> Seq.filter (fun x -> x = 'J') |> Seq.length
let inline (<?>) x y =
if isPart1 then x = y
else x + jokerCounts = y
let isFiveOfAKind = counts |> Seq.exists (fun (_, count) -> count <?> 5) || jokerCounts = 5
let isFourOfAKind = counts |> Seq.exists (fun (_, count) -> count <?> 4)
let isThreeOfAKind = counts |> Seq.exists (fun (_, count) -> count <?> 3)
let pairs = counts |> Array.filter (fun (_, count) -> count >= 2) |> Array.sortBy snd
let isTwoPair = (pairs.Length + if isPart1 then 0 else jokerCounts) = 2
let isOnePair = (pairs.Length + if isPart1 then 0 else jokerCounts) = 1
let isFullHouse =
if isPart1 || jokerCounts = 0 then
if pairs.Length = 2 then
let [|(_, twoCounts); (_, threeCounts)|] = pairs
twoCounts = 2 && threeCounts = 3
else false
else
// we don't care about 2+ Jokers as FH with 2 Js is possible only with another pair
// which makes it a 4+ of a kind
// and 2 Js with rainbow is a 3 of a kind
if jokerCounts = 1 && pairs.Length = 2 then
let [|(_, twoCounts1); (_, twoCounts2)|] = pairs
twoCounts1 = 2 && twoCounts2 = 2
else false
let comboPower =
if isFiveOfAKind then 0xF
elif isFourOfAKind then 0xE
elif isFullHouse then 0xD
elif isThreeOfAKind then 0xC
elif isTwoPair then 0xB
elif isOnePair then 0xA
else (* high card *) 0x9
let finalHandPower = (comboPower <<< 20) + handPower
{ handPower = finalHandPower
bet = int rawBet }
let game isPart1 =
input
|> Array.map (parseHand isPart1)
|> Array.sortWith (fun h1 h2 -> h1.handPower.CompareTo h2.handPower)
|> Seq.mapi (fun i hand -> hand.bet * (i + 1))
|> Seq.sum
let part1 = game true // 6440
let part2 = game false // 5905
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment