This commit is contained in:
parent
0f2b85f2ad
commit
7a1dba17f1
136
day12.kts
Executable file
136
day12.kts
Executable file
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env kotlin
|
||||
import java.util.Scanner
|
||||
|
||||
|
||||
val scanner = Scanner(System.`in`)
|
||||
|
||||
class Map(private val grid: List<List<String>>) {
|
||||
private val fields = mutableSetOf<Field>()
|
||||
private val map = mutableListOf<List<Plot>>()
|
||||
init {
|
||||
for ((y, line) in grid.withIndex()) {
|
||||
map.add(line.mapIndexed { x, s -> Plot(Pair(x, y), s) })
|
||||
}
|
||||
for (y in 0 until this.getHeight()) {
|
||||
for (x in 0 until this.getWidth()) {
|
||||
val plot = getPlot(x, y)
|
||||
if (!plot.hasField()) {
|
||||
val field = Field(this)
|
||||
plot.addField(field)
|
||||
fields.add(field)
|
||||
field.expand(plot)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
fun getWidth(): Int = grid[0].size
|
||||
fun getHeight(): Int = grid.size
|
||||
fun getPlot(x: Int, y: Int): Plot = map[y][x]
|
||||
|
||||
fun getFields(): Set<Field> = fields
|
||||
|
||||
fun getPrice(): Long = fields.sumOf { it.getPrice() }
|
||||
fun getBulkPrice(): Long = fields.sumOf { it.getBulkPrice() }
|
||||
|
||||
}
|
||||
|
||||
class Field(private val map: Map) {
|
||||
private val fieldPlots = mutableSetOf<Plot>()
|
||||
private val borderPlots = mutableSetOf<Pair<Plot, Plot>>()
|
||||
fun addPlot(plot: Plot) {
|
||||
fieldPlots.add(plot)
|
||||
}
|
||||
|
||||
fun expand(plot: Plot) {
|
||||
val (x, y) = plot.getPosition()
|
||||
val checkPositions = listOf(Pair(x - 1, y), Pair(x + 1, y), Pair(x, y - 1), Pair(x, y + 1))
|
||||
for ((checkX, checkY) in checkPositions) {
|
||||
if (checkX < 0 || checkX >= map.getWidth() || checkY < 0 || checkY >= map.getHeight()) {
|
||||
addBorder(plot, Plot(Pair(checkX, checkY), "."))
|
||||
continue
|
||||
}
|
||||
val checkedPlot = map.getPlot(checkX, checkY)
|
||||
if (plot.getType() == checkedPlot.getType()) {
|
||||
if (!checkedPlot.hasField()) {
|
||||
checkedPlot.addField(this)
|
||||
expand(checkedPlot)
|
||||
}
|
||||
} else {
|
||||
addBorder(plot, checkedPlot)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun addBorder(plot: Plot, checkedPlot: Plot) {
|
||||
borderPlots.add(Pair(plot, checkedPlot))
|
||||
}
|
||||
|
||||
fun getPrice(): Long {
|
||||
return getArea() * getCircumference()
|
||||
}
|
||||
|
||||
fun getArea(): Long = fieldPlots.size.toLong()
|
||||
fun getCircumference(): Long = borderPlots.size.toLong()
|
||||
fun getBulkPrice(): Long {
|
||||
return getArea() * getNumberOfSides()
|
||||
}
|
||||
|
||||
private fun getNumberOfSides(): Long {
|
||||
val leftBorders = borderPlots.filter { it.first.getPosition().first > it.second.getPosition().first}.map { it.first.getPosition() }
|
||||
val rightBorders = borderPlots.filter { it.first.getPosition().first < it.second.getPosition().first}.map { it.first.getPosition() }
|
||||
val topBorders = borderPlots.filter { it.first.getPosition().second > it.second.getPosition().second}.map { it.first.getPosition() }
|
||||
val bottomBorders = borderPlots.filter { it.first.getPosition().second < it.second.getPosition().second}.map { it.first.getPosition() }
|
||||
|
||||
return countSides(leftBorders) + countSides(rightBorders) + countSides(topBorders) + countSides(bottomBorders)
|
||||
}
|
||||
|
||||
private fun countSides(coordinates: List<Pair<Int, Int>>): Long {
|
||||
val visited = mutableSetOf<Pair<Int, Int>>()
|
||||
val coordinateSet = coordinates.toSet()
|
||||
var sideCount = 0
|
||||
val directions = listOf(Pair(1, 0), Pair(0, 1), Pair(-1, 0), Pair(0, -1))
|
||||
|
||||
fun dfs(coord: Pair<Int, Int>) {
|
||||
val stack = mutableListOf(coord)
|
||||
while (stack.isNotEmpty()) {
|
||||
val current = stack.removeLast()
|
||||
if (current in visited) continue
|
||||
visited.add(current)
|
||||
directions.map { (dx, dy) -> Pair(current.first + dx, current.second + dy) }
|
||||
.filter { it in coordinateSet && it !in visited }
|
||||
.forEach { stack.add(it) }
|
||||
}
|
||||
}
|
||||
for (coord in coordinates) {
|
||||
if (coord !in visited) {
|
||||
sideCount++
|
||||
dfs(coord)
|
||||
}
|
||||
}
|
||||
|
||||
return sideCount.toLong()
|
||||
}
|
||||
}
|
||||
|
||||
class Plot(private val position: Pair<Int, Int>, private val type: String) {
|
||||
private var field: Field? = null
|
||||
fun addField(field: Field) {
|
||||
this.field = field
|
||||
field.addPlot(this)
|
||||
}
|
||||
|
||||
fun hasField(): Boolean = field != null
|
||||
fun getPosition(): Pair<Int, Int> = position
|
||||
fun getType(): String = type
|
||||
}
|
||||
|
||||
val grid = mutableListOf<List<String>>()
|
||||
while (scanner.hasNextLine()) {
|
||||
grid.add(scanner.nextLine().split("").filter { it.isNotEmpty() })
|
||||
}
|
||||
|
||||
val map = Map(grid.reversed())
|
||||
println("The price is: ${map.getPrice()}")
|
||||
println("The bulk price is ${map.getBulkPrice()}")
|
2
day12.kts.testvalue
Normal file
2
day12.kts.testvalue
Normal file
@ -0,0 +1,2 @@
|
||||
The price is: 1375476
|
||||
The bulk price is 821372
|
Loading…
Reference in New Issue
Block a user