advent2023/seven.kt

73 lines
2.4 KiB
Kotlin

/**
* absolute ranking (as opposed to hands ranked against another set of hands)
* only care about the partitioning, not the pips
*/
fun hand_absrank(h: List<Pair<Int, Int>>): Int = h
.fold("") { acc, (_, r) -> acc + r.toString() }
.let {
mapOf("5" to 6, "41" to 5, "32" to 4, // https://oeis.org/A322761
"311" to 3, "221" to 2, "2111" to 1, "11111" to 0)[it]!!
}
/**
* In: [10, 5, ...
* Out: [(5, 3), ...
*/
fun card_count(hand: List<Int>): List<Pair<Int, Int>> = hand
.groupingBy { it }.eachCount()
.toList().sortedByDescending { it.second }
/**
* In: [10, 5, ...
* Out: 10*16^4 + 5*16^3 + 5*16^2 + 11*16 + 5 + 3*16^5 = 3823029
* or
* 10*16^4 + 5*16^3 + 5*16^2 + -1*16 + 5 + 5*16^5 = 5919989
*/
fun score(h: List<Int>, preprocess: (List<Pair<Int, Int>>) -> List<Pair<Int, Int>> = { x -> x }): Int {
return hand_absrank(preprocess(card_count(h))) * 1048576 +
h.foldRight(Pair(1, 0)) { it, (mul, acc) -> Pair(mul * 16, acc + it * mul) }.second
}
/**
* In: [(5, 3), (10, 1), (11, 1)]
* Out: [(5, 4), (10, 1)]
*/
fun jokered(h: List<Pair<Int, Int>>): List<Pair<Int, Int>> {
val numjokers = h.map { when(it.first) { -1 -> it.second else -> 0 }}.reduce { n, acc -> n + acc }
if (numjokers == 5) return h
return h.filter { (c, _) -> c != -1 }.mapIndexed { i, it -> when(i) {
0 -> Pair(it.first, it.second + numjokers)
else -> it
}}
}
/**
* In: T55J5
* Out: [10, 5, ...]
*/
fun cards(hand: String, jack_value: Int = 11): List<Int> = hand.toCharArray() // T55J5
.map { mapOf<Char, Int>('T' to 10, 'J' to jack_value, 'Q' to 12, 'K' to 13, 'A' to 14)[it] ?:
(it - '0').toInt() }
fun solve(
hands_and_bids: List<List<String>>,
jack_value: Int = 11,
fudge: (List<Pair<Int, Int>>) -> List<Pair<Int, Int>> = { it }
): Int {
val sequenced = hands_and_bids.map { Pair<List<Int>, Int>(cards(it[0], jack_value), it[1].toInt()) }
val scored = sequenced.map { (hand, bid) -> listOf(hand, bid, score(hand, fudge)) }
val sorted = scored.toList().sortedBy { it[2] as Int }
val ranked = sorted.mapIndexed { i, it ->
Pair(i + 1, it[1]) }
val sum = ranked.fold(0) { acc, (rank, bid) -> acc + rank * bid as Int}
return sum
}
fun main() {
val hands_and_bids = generateSequence(::readLine).map { it // "T55J5 684"
.split(' ') // "T55J5" "684"
}.toList()
println(solve(hands_and_bids))
println(solve(hands_and_bids, -1, ::jokered))
}