Den 11. byl opět performance peklo 🙂 . Jelikož jsem neznal “Summed-area table” algoritmus, pokusil jsem se přijít s něčím vlastním, což nebylo zdaleka tak efektivní, ale doběhlo to! (naštěstí se správným výsledkem):
class FuelCell(val x: Int, val y: Int, val serialNumber: Int) {
val rackId = (x + 10).toLong()
val powerLevel = run {
var result = rackId * y
result += serialNumber
result *= rackId
assert(result >= 0)
val threeDigitResult = result % 1000
val hundredDigit = when {
threeDigitResult >= 100 -> {
"$threeDigitResult"[0].toString().toLong()
}
else -> 0
}
hundredDigit - 5
}
}
interface Square {
val refX: Int
val refY: Int
val serialNumber: Int
val size: Int
val totalPower: Long
}
data class FuelSquare(
override val refX: Int,
override val refY: Int,
override val serialNumber: Int,
override val size: Int
) : Square {
override val totalPower = sequence {
for (x in 0 until size) {
for (y in 0 until size) {
yield(FuelCell(refX + x, refY + y, serialNumber).powerLevel)
}
}
}.sum()
}
class DiffSquare(val smallerSquare: Square, val diff: Int) : Square {
override val refX = smallerSquare.refX
override val refY = smallerSquare.refY
override val serialNumber = smallerSquare.serialNumber
override val size = smallerSquare.size + diff
override val totalPower = run {
val remainingPower = sequence {
for (x in 0 until size) {
for (y in 0 until size) {
yield(
when {
x >= size - diff || y >= size - diff -> FuelCell(
refX + x,
refY + y,
serialNumber
).powerLevel
else -> 0
}
)
}
}
}.sum()
smallerSquare.totalPower + remainingPower
}
override fun toString() = "$refX,$refY,$size"
}
var squaresMap = mutableMapOf<Triple<Int, Int, Int>, Square>()
private fun findMostPowerfulSquare(
maxX: Int,
maxY: Int,
serialInput: Int,
size: Int
): Square {
var mostPowerfulSquare: Square? = null
val newMap = mutableMapOf<Triple<Int, Int, Int>, Square>()
for (x in 0 until maxX - size + 1) {
for (y in 0 until maxY - size + 1) {
val smallerSquareKey = Triple(x, y, size - 1)
val fuelSquare = squaresMap[smallerSquareKey]?.let { DiffSquare(it, 1) }
?: FuelSquare(x, y, serialInput, size)
newMap[Triple(x, y, size)] = fuelSquare
if (mostPowerfulSquare != null) {
if (fuelSquare.totalPower > mostPowerfulSquare.totalPower) {
mostPowerfulSquare = fuelSquare
}
} else mostPowerfulSquare = fuelSquare
}
}
squaresMap = newMap
return mostPowerfulSquare ?: throw Exception("Couldn't find it!")
}
fun main() {
val serialInput = 7803
val maxX = 300
val maxY = 300
//A
val mostPowerfulSquareA = findMostPowerfulSquare(maxX, maxY, serialInput, 3)
println("Most powerful square A is: $mostPowerfulSquareA")
//B
val mostPowerfulSquareB = (1..300).asSequence().map { size ->
println("Searching for size $size")
findMostPowerfulSquare(maxX, maxY, serialInput, size)
}.maxBy { it.totalPower }
println("Most powerful square B is: $mostPowerfulSquareB")
}