class CharGrid(val rows: List) : Grid { override val width = rows.firstOrNull()?.count() ?: 0 override val height get() = rows.count() init { assert(rows.all { it.length == width }) } companion object { fun read(name: String): CharGrid = CharGrid(readInput(name).toList()) } fun chars(x: Int, y: Int, dx: Int, dy: Int) = Line(x, y, dx, dy) inner class Line(val x: Int, val y: Int, val dx: Int, val dy: Int) : Sequence { override fun iterator(): Iterator = if (dx == 1 && dy == 0) { rows[y].substring(startIndex = x).iterator() } else iterator { var x = x var y = y while (x in 0.. = sequence { for (y in 0.. = sequence { for (x in 0.. = sequence { for (x in 0.. 0) { yield(chars(x, 0, -1, 1)) } } for (y in 1.. = sequence { yieldAll(rows()) yieldAll(columns()) yieldAll(diagonals()) } override fun get(x: Int, y: Int): Char = rows[y][x] fun find(char: Char): Grid.Coordinate? { for (y in rows.indices) { val index = rows[y].indexOf(char) if (index != -1) { return Grid.Coordinate(index, y) } } return null } override fun map(fn: (Char) -> T): Grid { val data = rows.flatMap { it.map(fn) } return ListGrid(width, height, data) } }