0
\$\begingroup\$

I'm new with Kotlin, and this is my first attempt of a two dimensional array.

 // private var roomGrid = arrayOfNulls<arrayOfNulls<Room>>(4)
private var roomGrid = Array(roomCountX) {arrayOfNulls<Room>(roomCountY)}

 init {
    for (gridY in 0 until roomCountY) {
        for (gridX in 0 until roomCountX) {
            val pixelX = gridX * roomWidth
            val pixelY = gridY * roomHeight
            val room = Room(pixelX.toFloat(), pixelY.toFloat(), s)
            roomGrid[gridX][gridY] = room
        }
    }

     // neighbor relations
    for (gridY in 0 until roomCountY) {
        for (gridX in 0 until roomCountX) {
            val room = roomGrid[gridX][gridY]
            if (gridY > 0)
                roomGrid[gridX][gridY - 1]?.let { room?.setNeighbor(Room.SOUTH, it) }
            if (gridY < roomCountY - 1)
                roomGrid[gridX][gridY + 1]?.let { room?.setNeighbor(Room.NORTH, it) }
            if (gridX > 0)
                roomGrid[gridX - 1][gridY]?.let { room?.setNeighbor(Room.WEST, it) }
            if (gridX < roomCountX - 1)
                roomGrid[gridX + 1][gridY]?.let { room?.setNeighbor(Room.EAST, it) }
        }
    }
}

Even though it works I don't like the look of these:

roomGrid[gridX][gridY + 1]?.let { room?.setNeighbor(Room.NORTH, it) }

They are harder to read, and I'm not really sure what .let and it are. I would like some simpler syntax/solution to a two dimensional array.

How might I improve this?

\$\endgroup\$
2
  • \$\begingroup\$ can't you get rid of the nulls? \$\endgroup\$
    – elect
    Sep 4, 2019 at 12:42
  • 2
    \$\begingroup\$ What are these arrays for? What is the actual problem you are working on? \$\endgroup\$
    – t3chb0t
    Sep 7, 2019 at 7:57

1 Answer 1

2
\$\begingroup\$

let

If you use let, you ask Kotlin to create an invisible function with a parameter.

1.let { println(5) }
    //changes to:
    fun func(it : Int) {
        println(5)
    }
    func(1)

Do you see the it? That's the name of the parameter. Therefor, you can use it inside let.

1.let { println(it) }
//changes to
fun func(it : Int) {
    println(it)
}
func(1)

Now, the function returns something too, namely the result of the last statement. In this case, it's just Unit, or void in Java (emptyNess):

fun func(it : Int) : Unit {
    return println(it)
}
func(1)

If we take another example, it will be clearer:

val a = 5.let { 3 + it }
//changes to
fun func(it: Int) : Int {
     return 3 + it
}
val a = func(5)

?.let

?. is very simple:

val b = a?.foo()
//changes to:
val b = if (a == null) a else a.foo()

?.let is exactly the same:

val b = a?.let { it+3 }
//changes to
fun func(it: Int){
   it + 3
}
val b = if (a == null) null else func(a)

inline

Kotlin is smart. it actually uses an inline function for let.
An inline function is a function that actually doesn't exist.
Instead, the code is copy pasted into the real code.
The parameters are just variables with random names.

so

val b = a?.let { it + 3 }
//is actually changed to
val b = if (a == null) null else {
    val ac432cd = a
    ac432cd + 3
}

simplyfication

roomGrid[gridX][gridY - 1]?.let { room?.setNeighbor(Room.SOUTH, it) }

step 1

// I would check room first:
if (room != null) {
   roomGrid[gridX][gridY - 1]?.let { room.setNeighbor(room.SOUTH, it) }
}

step 2

// flip the rooms (and directions)
if (room != null) {
   roomGrid[gridX][gridY - 1]?.let{ it.setNeighbor(room.SOUTH, room) }
}

step 3

//remove let
if (room != null) {
   roomGrid[gridX][gridY - 1]?.setNeighbor(room.SOUTH, room)
}

full code until now

 // neighbor relations
for (gridY in 0 until roomCountY) {
    for (gridX in 0 until roomCountX) {
        val room = roomGrid[gridX][gridY]
        if (room != null) {
            if (gridY > 0)
                roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
            if (gridY < roomCountY - 1)
                roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
            if (gridX > 0)
                roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
            if (gridX < roomCountX - 1)
                roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
        }
    }
}

step 4

At the moment, we test in the beginning if room isn't null.
If it is, it skips the if-statement and continues with the next iteration.
We can tell to go to the next iteration immediately using the keyword continue.

// neighbor relations
for (gridY in 0 until roomCountY) {
    for (gridX in 0 until roomCountX) {
        val room = roomGrid[gridX][gridY]
        if (room == null) continue
        if (gridY > 0)
            roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
        ...
    }
}

step 5

last, kotlin has another language feature: ?:

val a = foo() ?: bar()
//will be rewritten to
val tmp = foo()
val a = if (tmp != null) tmp else bar()

Just as return continue skips immediately to the next variable. This means that we can rewrite the code we wrote in step 4.

// neighbor relations
for (gridY in 0 until roomCountY) {
    for (gridX in 0 until roomCountX) {
        val room = roomGrid[gridX][gridY] ?: continue
        if (gridY > 0)
            roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
        ...
    }
}

full code

 // neighbor relations
for (gridY in 0 until roomCountY) {
    for (gridX in 0 until roomCountX) {
        val room = roomGrid[gridX][gridY] ?: continue
        if (gridY > 0)
            roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
        if (gridY < roomCountY - 1)
            roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
        if (gridX > 0)
            roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
        if (gridX < roomCountX - 1)
            roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
    }
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Your right. val room = expr ?: continue. I update tomorrow, as I don't have access to a computer at the moment... Thx! \$\endgroup\$
    – tieskedh
    Sep 8, 2019 at 9:24
  • 1
    \$\begingroup\$ @RolandIllig fixed. Hopefully, it can helpsome people understand Kotlin better. \$\endgroup\$
    – tieskedh
    Sep 10, 2019 at 8:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.