Add grid interface and generic implementation.
This commit is contained in:
parent
013d3df0ae
commit
267ffda2e9
4 changed files with 46 additions and 22 deletions
|
@ -1,6 +1,6 @@
|
||||||
class CharGrid(val rows: List<String>) {
|
class CharGrid(val rows: List<String>) : Grid<Char> {
|
||||||
val width = rows.firstOrNull()?.count() ?: 0
|
override val width = rows.firstOrNull()?.count() ?: 0
|
||||||
val height get() = rows.count()
|
override val height get() = rows.count()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
assert(rows.all { it.length == width })
|
assert(rows.all { it.length == width })
|
||||||
|
@ -59,21 +59,20 @@ class CharGrid(val rows: List<String>) {
|
||||||
yieldAll(diagonals())
|
yieldAll(diagonals())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(x: Int, y: Int): Char = rows[y][x]
|
override fun get(x: Int, y: Int): Char = rows[y][x]
|
||||||
|
|
||||||
fun find(char: Char): Coordinate? {
|
fun find(char: Char): Grid.Coordinate? {
|
||||||
for (y in rows.indices) {
|
for (y in rows.indices) {
|
||||||
val index = rows[y].indexOf(char)
|
val index = rows[y].indexOf(char)
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
return Coordinate(index, y)
|
return Grid.Coordinate(index, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun inside(coordinate: Coordinate) = coordinate.x in 0..<width && coordinate.y in 0..<height
|
override fun <T> map(fn: (Char) -> T): Grid<T> {
|
||||||
|
val data = rows.flatMap { it.map(fn) }
|
||||||
operator fun get(coordinate: Coordinate) = get(coordinate.x, coordinate.y)
|
return ListGrid(width, height, data)
|
||||||
|
}
|
||||||
data class Coordinate(val x: Int, val y: Int)
|
|
||||||
}
|
}
|
||||||
|
|
25
2024/src/main/kotlin/Grid.kt
Normal file
25
2024/src/main/kotlin/Grid.kt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
interface Grid<T> {
|
||||||
|
val width: Int
|
||||||
|
val height: Int
|
||||||
|
|
||||||
|
fun <U> map(fn: (T) -> U): Grid<U>
|
||||||
|
|
||||||
|
fun get(x: Int, y: Int): T
|
||||||
|
|
||||||
|
data class Coordinate(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
fun inside(coordinate: Coordinate) = coordinate.x in 0..<width && coordinate.y in 0..<height
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun <T> Grid<T>.get(coordinate: Grid.Coordinate) = get(coordinate.x, coordinate.y)
|
||||||
|
operator fun <T> Grid<T>.contains(coordinate: Grid.Coordinate) = inside(coordinate)
|
||||||
|
|
||||||
|
class ListGrid<T>(override val width: Int, override val height: Int, private val content: List<T>) : Grid<T> {
|
||||||
|
init {
|
||||||
|
assert(width * height == content.count())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(x: Int, y: Int): T = content[x + y * width]
|
||||||
|
|
||||||
|
override fun <U> map(fn: (T) -> U): Grid<U> = ListGrid(width, height, content.map(fn))
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ enum class Direction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CharGrid.Coordinate.step(direction: Direction) =
|
fun Grid.Coordinate.step(direction: Direction) =
|
||||||
when (direction) {
|
when (direction) {
|
||||||
Direction.North -> copy(y = y - 1)
|
Direction.North -> copy(y = y - 1)
|
||||||
Direction.East -> copy(x = x + 1)
|
Direction.East -> copy(x = x + 1)
|
||||||
|
@ -25,7 +25,7 @@ fun main() {
|
||||||
|
|
||||||
var position = grid.find('^') ?: error("Guard not found")
|
var position = grid.find('^') ?: error("Guard not found")
|
||||||
var direction = Direction.North
|
var direction = Direction.North
|
||||||
val visitedPositions = mutableSetOf<CharGrid.Coordinate>()
|
val visitedPositions = mutableSetOf<Grid.Coordinate>()
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
visitedPositions.add(position)
|
visitedPositions.add(position)
|
||||||
|
|
|
@ -1,36 +1,36 @@
|
||||||
fun main() {
|
fun main() {
|
||||||
val grid = CharGrid.read("day8.txt")
|
val grid = CharGrid.read("day8.txt")
|
||||||
|
|
||||||
val antennasByFrequency = mutableMapOf<Char, MutableList<CharGrid.Coordinate>>()
|
val antennasByFrequency = mutableMapOf<Char, MutableList<Grid.Coordinate>>()
|
||||||
for (y in 0..<grid.height) {
|
for (y in 0..<grid.height) {
|
||||||
for (x in 0..<grid.width) {
|
for (x in 0..<grid.width) {
|
||||||
val value = grid.get(x, y)
|
val value = grid.get(x, y)
|
||||||
if (value != '.') {
|
if (value != '.') {
|
||||||
antennasByFrequency.getOrPut(value) { mutableListOf() }.add(CharGrid.Coordinate(x, y))
|
antennasByFrequency.getOrPut(value) { mutableListOf() }.add(Grid.Coordinate(x, y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAntinode(coordinate: CharGrid.Coordinate, frequency: Char, antennas: List<CharGrid.Coordinate>) =
|
fun isAntinode(coordinate: Grid.Coordinate, frequency: Char, antennas: List<Grid.Coordinate>) =
|
||||||
antennas.any { antenna ->
|
antennas.any { antenna ->
|
||||||
val dx = antenna.x - coordinate.x
|
val dx = antenna.x - coordinate.x
|
||||||
val dy = antenna.y - coordinate.y
|
val dy = antenna.y - coordinate.y
|
||||||
val secondAntenna = CharGrid.Coordinate(antenna.x + dx, antenna.y + dy)
|
val secondAntenna = Grid.Coordinate(antenna.x + dx, antenna.y + dy)
|
||||||
|
|
||||||
secondAntenna != antenna && grid.inside(secondAntenna) && grid[secondAntenna] == frequency
|
secondAntenna != antenna && grid.inside(secondAntenna) && grid[secondAntenna] == frequency
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isAntinode(coordinate: CharGrid.Coordinate) =
|
fun isAntinode(coordinate: Grid.Coordinate) =
|
||||||
antennasByFrequency.any { (frequency, positions) ->
|
antennasByFrequency.any { (frequency, positions) ->
|
||||||
isAntinode(coordinate, frequency, positions)
|
isAntinode(coordinate, frequency, positions)
|
||||||
}
|
}
|
||||||
|
|
||||||
val antinodes = mutableSetOf<CharGrid.Coordinate>()
|
val antinodes = mutableSetOf<Grid.Coordinate>()
|
||||||
|
|
||||||
for (y in 0..<grid.height) {
|
for (y in 0..<grid.height) {
|
||||||
for (x in 0..<grid.width) {
|
for (x in 0..<grid.width) {
|
||||||
|
|
||||||
val coordinate = CharGrid.Coordinate(x, y)
|
val coordinate = Grid.Coordinate(x, y)
|
||||||
if (isAntinode(coordinate)) {
|
if (isAntinode(coordinate)) {
|
||||||
antinodes.add(coordinate)
|
antinodes.add(coordinate)
|
||||||
}
|
}
|
||||||
|
@ -50,13 +50,13 @@ fun main() {
|
||||||
var pos = first
|
var pos = first
|
||||||
while (grid.inside(pos)) {
|
while (grid.inside(pos)) {
|
||||||
antinodes.add(pos)
|
antinodes.add(pos)
|
||||||
pos = CharGrid.Coordinate(pos.x + dx, pos.y + dy)
|
pos = Grid.Coordinate(pos.x + dx, pos.y + dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = first
|
pos = first
|
||||||
while (grid.inside(pos)) {
|
while (grid.inside(pos)) {
|
||||||
antinodes.add(pos)
|
antinodes.add(pos)
|
||||||
pos = CharGrid.Coordinate(pos.x - dx, pos.y - dy)
|
pos = Grid.Coordinate(pos.x - dx, pos.y - dy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue