diff --git a/2023/day07.nim b/2023/day07.nim index 1270ca4..1ffdff3 100644 --- a/2023/day07.nim +++ b/2023/day07.nim @@ -36,6 +36,14 @@ func parseHand(text: string): Hand = func parseHands(text: string): seq[Hand] = text.strip.splitLines.map(parseHand) +const five = 7 +const four = 6 +const full = 5 +const three = 4 +const twoPair = 3 +const pair = 2 +const high = 1 + func strength(hand: Hand): int = let count = newCountTable(hand.cards) @@ -44,19 +52,19 @@ func strength(hand: Hand): int = counts.inc v if counts[5] > 0: - return 7 + return five if counts[4] > 0: - return 6 + return four if counts[3] > 0: if counts[2] > 0: - return 5 + return full else: - return 4 + return three if counts[2] == 2: - return 3 + return twoPair if counts[2] == 1: - return 2 - return 1 + return pair + return high func cmpHand(a: Hand, b: Hand): int = let strength = cmp(a.strength, b.strength) @@ -79,4 +87,92 @@ proc part1(): int = for (rank, hand) in enumerate(hands): result += (rank + 1) * hand.bid +func strengthJoker(hand: Hand): int = + let count = newCountTable(hand.cards) + + let jokers = count[1] + + var regular: CountTable[int] + for card, count in pairs(count): + if card == 1: + continue + regular.inc count + + if regular[5] > 0: + return five + if regular[4] > 0: + if jokers == 1: + return five + return four + if regular[3] > 0: + case jokers: + of 2: return five + of 1: return four + else: discard + if regular[2] > 0: + return full + return three + if regular[2] == 2: + if jokers == 1: + return full + return twoPair + if regular[2] == 1: + case jokers: + of 3: return five + of 2: return four + of 1: return three + else: return pair + + case jokers: + of 5: return five + of 4: return five + of 3: return four + of 2: return three + of 1: return pair + else: return high + +func cmpHandJoker(a: Hand, b: Hand): int = + let strength = cmp(a.strengthJoker, b.strengthJoker) + if strength != 0: + return strength + + for (aa, bb) in zip(a.cards, b.cards): + let card = cmp(aa, bb) + if card != 0: + return card + +func parseCardJoker(c: char): int = + case c: + of 'A': 14 + of 'K': 13 + of 'Q': 12 + of 'J': 1 + of 'T': 10 + of '9': 9 + of '8': 8 + of '7': 7 + of '6': 6 + of '5': 5 + of '4': 4 + of '3': 3 + of '2': 2 + else: 0 + +func parseHandJoker(text: string): Hand = + let parts = text.strip.splitWhitespace + (parts[0].map(parseCardJoker), parts[1].parseInt) + +func parseHandsJoker(text: string): seq[Hand] = + text.strip.splitLines.map(parseHandJoker) + +proc part2(): int = + let text = readFile("input/day07.txt") + var hands = parseHandsJoker(text) + + hands.sort(cmpHandJoker) + + for (rank, hand) in enumerate(hands): + result += (rank + 1) * hand.bid + echo part1() +echo part2()