Maximise adjacent numbers in a functional style (PE#11)
You can parse your grid using some very useful functions in kotlin-stdlib:

val numbers = grid.lines().map { line -&gt; line.split(' ').map(String::toInt) }

Personally I prefer "row/column" instead of "y/x". Thinking "y" before "x" is unnatural.
You can always define your own methods too which can improve readability. e.g.:

fun Iterable&lt;Int&gt;.product(): Int = reduce(Int::times)

Instead of using Math.max you might check to see if the given product is greater than the currently known maximum product and then assign it if it is. This is minor but personally I prefer to avoid unnecessary assignments.
I wouldn't worry about trying to do all of this in one pass. Each directional slice has different row/column bounds so I think four separate loops is the clearest/cleanest.
You can remove some duplicated code when it comes to calculating the product and updating the maximum.


e.g.:

var product = 0

fun maximizeProduct(numbers: List&lt;Int&gt;) {
    with(numbers.product()) { if (this &gt; product) product = this }
}

// Horizontal
for (y in 0 until numbers.size)
    for (x in 0 until numbers[y].size - 3)
        maximizeProduct(numbers[y].slice(x..x + 3))

// Vertical
for (y in 0 until numbers.size - 3)
    for (x in 0 until numbers[y].size)
        maximizeProduct(numbers.slice(y..y + 3).map { it[x] })

// Down Right
for (y in 0 until numbers.size - 3)
    for (x in 0 until numbers[y].size - 3)
        maximizeProduct(numbers.slice(y..y + 3).mapIndexed { i, it -&gt; it[x + i] })

// Down Left
for (y in 0 until numbers.size - 3)
    for (x in 3 until numbers[y].size)
        maximizeProduct(numbers.slice(y..y + 3).mapIndexed { i, it -&gt; it[x - i] })

println(product)