diff --git a/day12.kts b/day12.kts new file mode 100755 index 0000000..b669db8 --- /dev/null +++ b/day12.kts @@ -0,0 +1,136 @@ +#!/usr/bin/env kotlin +import java.util.Scanner + + +val scanner = Scanner(System.`in`) + +class Map(private val grid: List>) { + private val fields = mutableSetOf() + private val map = mutableListOf>() + 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 = 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() + private val borderPlots = mutableSetOf>() + 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>): Long { + val visited = mutableSetOf>() + 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) { + 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, 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 = position + fun getType(): String = type +} + +val grid = mutableListOf>() +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()}") \ No newline at end of file diff --git a/day12.kts.testvalue b/day12.kts.testvalue new file mode 100644 index 0000000..a84c233 --- /dev/null +++ b/day12.kts.testvalue @@ -0,0 +1,2 @@ +The price is: 1375476 +The bulk price is 821372