-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay22CrabCombat.kt
74 lines (59 loc) · 2.79 KB
/
Day22CrabCombat.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
package adventofcode.year2020
import adventofcode.Puzzle
import adventofcode.PuzzleInput
class Day22CrabCombat(customInput: PuzzleInput? = null) : Puzzle(customInput) {
private val player1 by lazy { input.split("\n\n").first().lines().drop(1).map(String::toInt) }
private val player2 by lazy { input.split("\n\n").last().lines().drop(1).map(String::toInt) }
override fun partOne() = CrabCombatGame(player1.toMutableList(), player2.toMutableList()).playRegularGame()
override fun partTwo() = CrabCombatGame(player1.toMutableList(), player2.toMutableList()).playRecursiveGame(true)
companion object {
private data class CrabCombatGame(
val player1: MutableList<Int>,
val player2: MutableList<Int>,
) {
private fun computeScore() = (player1 + player2).reversed().mapIndexed { position, card -> card * (position + 1) }.sum()
fun playRegularGame(): Int {
while (player1.isNotEmpty() && player2.isNotEmpty()) {
val card1 = player1.removeAt(0)
val card2 = player2.removeAt(0)
if (card1 > card2) {
player1.addAll(listOf(card1, card2))
} else {
player2.addAll(listOf(card2, card1))
}
}
return computeScore()
}
fun playRecursiveGame(startingGame: Boolean): Int {
val previousConfigurations = hashSetOf<CrabCombatGame>()
while (player1.isNotEmpty() && player2.isNotEmpty()) {
if (previousConfigurations.contains(this)) {
return 1
}
previousConfigurations.add(this)
val card1 = player1.removeAt(0)
val card2 = player2.removeAt(0)
val winningPlayer =
when {
player1.size >= card1 && player2.size >= card2 ->
CrabCombatGame(
player1.take(card1).toMutableList(),
player2.take(card2).toMutableList(),
).playRecursiveGame(false)
card1 > card2 -> 1
else -> 2
}
if (winningPlayer == 1) {
player1.addAll(listOf(card1, card2))
} else {
player2.addAll(listOf(card2, card1))
}
}
return when (startingGame) {
true -> computeScore()
false -> if (player1.size > player2.size) 1 else 2
}
}
}
}
}