-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay07CamelCards.kt
77 lines (67 loc) · 2.93 KB
/
Day07CamelCards.kt
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
package adventofcode.year2023
import adventofcode.Puzzle
import adventofcode.PuzzleInput
import adventofcode.year2023.Day07CamelCards.Companion.HandType.FIVE_OF_A_KIND
import adventofcode.year2023.Day07CamelCards.Companion.HandType.FOUR_OF_A_KIND
import adventofcode.year2023.Day07CamelCards.Companion.HandType.FULL_HOUSE
import adventofcode.year2023.Day07CamelCards.Companion.HandType.HIGH_CARD
import adventofcode.year2023.Day07CamelCards.Companion.HandType.ONE_PAIR
import adventofcode.year2023.Day07CamelCards.Companion.HandType.THREE_OF_A_KIND
import adventofcode.year2023.Day07CamelCards.Companion.HandType.TWO_PAIR
class Day07CamelCards(customInput: PuzzleInput? = null) : Puzzle(customInput) {
override fun partOne() =
input
.lines()
.asSequence()
.map { it.split(" ") }
.map { (hand, bid) -> Hand(hand) to bid.toInt() }
.sortedBy { (hand) -> hand }
.mapIndexed { rank, (_, bid) -> (rank + 1) * bid }
.sum()
companion object {
private data class Card(
val label: Char,
) : Comparable<Card> {
override fun compareTo(other: Card) = cardRank.indexOf(label) - cardRank.indexOf(other.label)
companion object {
private val cardRank = listOf('2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A')
}
}
private data class Hand(
val cards: List<Card>,
) : Comparable<Hand> {
private val cardCounts = cards.groupingBy { it }.eachCount()
fun handType() =
when {
cardCounts.any { (_, count) -> count == 5 } -> FIVE_OF_A_KIND
cardCounts.any { (_, count) -> count == 4 } -> FOUR_OF_A_KIND
cardCounts.size == 2 -> FULL_HOUSE
cardCounts.any { (_, count) -> count == 3 } -> THREE_OF_A_KIND
cardCounts.filter { (_, count) -> count == 2 }.size == 2 -> TWO_PAIR
cardCounts.any { (_, count) -> count == 2 } -> ONE_PAIR
else -> HIGH_CARD
}
override fun compareTo(other: Hand) =
when (val rank = handType().rank - other.handType().rank) {
0 ->
cards
.zip(other.cards)
.map { (thisHandCard, otherHandCard) -> thisHandCard.compareTo(otherHandCard) }
.first { it != 0 }
else -> rank
}
companion object {
operator fun invoke(input: String) = Hand(input.toList().map(::Card))
}
}
private enum class HandType(val rank: Int) {
FIVE_OF_A_KIND(6),
FOUR_OF_A_KIND(5),
FULL_HOUSE(4),
THREE_OF_A_KIND(3),
TWO_PAIR(2),
ONE_PAIR(1),
HIGH_CARD(0),
}
}
}