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