Edgar Avuzi
12/24/2024, 2:49 AMfor comprehension
in KotlinEdgar Avuzi
12/24/2024, 2:50 AMimport scala.io.Source
object Main
val XMAS = "XMAS"
val directions: List[(Int, Int)] = List(
(0, 1), // Right (horizontal)
(1, 0), // Down (vertical)
(1, 1), // Diagonal down-right
(1, -1), // Diagonal down-left
(0, -1), // Left (reverse horizontal)
(-1, 0), // Up (reverse vertical)
(-1, -1), // Diagonal up-left
(-1, 1) // Diagonal up-right
)
@main def run(): Unit = {
val grid =
Option(Main.getClass.getClassLoader.getResourceAsStream("input4.txt"))
.map(Source.fromInputStream)
.map(_.getLines().toList)
.getOrElse(List.empty)
val count = for {
i <- grid.indices
j <- grid(i).indices
(dx, dy) <- directions
if isMatch(grid, i, j, dx, dy)
} yield 1
println(s"Total occurrences of XMAS: ${count.sum}")
}
def isMatch(grid: List[String], i: Int, j: Int, dx: Int, dy: Int): Boolean = {
val endX = i + (XMAS.length - 1) * dx
val endY = j + (XMAS.length - 1) * dy
(grid.isDefinedAt(endX) && grid.isDefinedAt(endY)) &&
XMAS.indices.forall { k =>
grid(i + k * dx)(j + k * dy) == XMAS(k)
}
}
Edgar Avuzi
12/24/2024, 2:51 AMephemient
12/24/2024, 2:51 AMephemient
12/24/2024, 2:54 AMval count = grid.indices
.flatMap { i -> grid[i].indices.map(i::to) }
.flatMap { ij -> directions.map(ij::to) }
.count { (ij, dxdy) -> isMatch(grid, ij.first, ij.second, dxdy.first, dxdy.second) }
ephemient
12/24/2024, 2:55 AMfor
comprehensions desugar into a chain of flatMap
calls somewhat like thatEdgar Avuzi
12/24/2024, 3:16 AMconst val XMAS = "XMAS"
val directions: List<Pair<Int, Int>> = listOf(
Pair(0, 1), // Right (horizontal)
Pair(1, 0), // Down (vertical)
Pair(1, 1), // Diagonal down-right
Pair(1, -1), // Diagonal down-left
Pair(0, -1), // Left (reverse horizontal)
Pair(-1, 0), // Up (reverse vertical)
Pair(-1, -1), // Diagonal up-left
Pair(-1, 1) // Diagonal up-right
)
fun main() {
val grid =
({}.javaClass.classLoader.getResourceAsStream("input4.txt") ?: return)
.reader()
.use { it.readLines() }
val count = grid.indices
.flatMap { i -> grid[i].indices.map(i::to) }
.flatMap { ij -> directions.map(ij::to) }
.count { (ij, dxdy) -> isMatch(grid, ij.first, ij.second, dxdy.first, dxdy.second) }
println("Total occurrences of XMAS: $count")
}
fun isMatch(grid: List<String>, i: Int, j: Int, dx: Int, dy: Int): Boolean {
val endX = i + (XMAS.length - 1) * dx
val endY = j + (XMAS.length - 1) * dy
return (endX in grid.indices && endY in grid[0].indices)
&&
XMAS.indices.all { k ->
grid[i + k * dx][j + k * dy] == XMAS[k]
}
}
CLOVIS
12/24/2024, 9:19 AMval count = sequence {
parameterize {
val i by parameterOf(grid.indices)
val ij by parameterOf(grid[i].indices.map(i::to))
yield(directions.map(ij::to))
}
}.count [ (ij, dxdy) -> isMatch(grid, ij.first, ij.second, dxdy.first, dxdy.second) }
That looks fairly close to the Scala example 🤔Edgar Avuzi
12/24/2024, 10:12 AMephemient
12/26/2024, 10:10 AMCLOVIS
12/26/2024, 10:15 AMephemient
12/26/2024, 10:22 AMsuspend
, so we have tests that do
@get:Rule
val errorCollector = ErrorCollector()
@Test
fun test() = runTest {
chooseAll(errorCollector::addError) {
coroutineScope {
val foo = choose(...)
val bar = choose(...)
but I have been thinking that longer-term it's probably better to build this on top of the Compose machinery instead, so that we get to have the benefits of skipping (which is more likely what a user would expect)CLOVIS
12/26/2024, 10:32 AM