Challenge World Map

I made a solution that works. However, every time my function prints the map it ends with “kotlin.Unit”. I know my function returns a Unit but is there a way to prevent the console from printing “kotlin.Unit”?

//here is the original processCommand()
fun processCommand() = when (command.toLowerCase()) {
“move” -> move(input.split(" ").getOrElse(1, { “” }))
“map” -> showMap(player).toString()
“quit” -> “leaving game…”
else -> commandNotFound()
}

//here is my showMap() function
private fun showMap(player : Player) {
val listMap = mutableListOf(
mutableListOf(“O”,“O”,“O”),
mutableListOf(“O”,“O”))
val position = player.currentPositon
listMap[position.y][position.x] = “X”

listMap[0].forEach{it -> print("$it “)}
println()
listMap[1].forEach { it -> print(”$it ") }

}

Thanks in Advance. Oh if anyone has a more elegant solution, please share! :slight_smile:

Angel

I’ll take a stab at the answer to this. I’ve been working through the book and just reached this chapter.

For functions, if return is not used then the last line is assumed to be the return value for the function. For the showMap() function, this is the last line

listMap[1].forEach { it -> print(”$it ") }

Further, there is no explicit return type so the type of the last line is used. The result of the forEach lambda does not return anything, so in Java/C++ we’d expect this function return type to be void. But in Kotlin, the equivalent to void is Unit.

Thus, in your processCommand() method when you showMap(player).toString(), I suspect the toString() was added to remove a prior warning/error. So doing Unit.toString() prints kotlin.Unit to the terminal.

I have structured my processCommand() function as follows:

fun processCommand(): String = when (command.toLowerCase()) {
        "map" -> printMap()
        "move" -> move(argument)
        "ring" -> if(currentRoom is TownSquare) {
            (currentRoom as TownSquare).ringBell()
        } else {
            "There is no bell here"
        }
        "quit" -> endGame()
        "exit" -> endGame()
        else -> commandNotFound()
    }

All of my helper functions then return a string.

My printMap() functions then looks as follows

private fun printMap(): String {
    var magicMap = ""
    for( row in worldMap ) {
        for( col in row ) {
            if( col == currentRoom ) {
                magicMap += "X "
            } else {
                magicMap += "o "
            }
        }
        magicMap += "\n"
    }
    return magicMap
}

Whether string manipulation is the most efficient can be argued, but didn’t want to assume a size on the map and threw a quick solution together.

nice! sorry for the late reply. thank you :slight_smile:

Indeed. I was having the same issue – getting a printout of “kotlin.unit”. It’s because the line println(GameInput(readLine()).processCommand())
is looking for a string to print to the screen. Therefore each “when” branch needs to return a string, and not just work through a formula, otherwise the println function will print “kotlin.unit”.

Here is my solution to the challenge:

object Game {
    private var worldMap = listOf(
            listOf(TownSquare(), Room("Tavern"), Room("Back Room")),
            listOf(Room("Long Corridor"), Room("Generic Room"))
    )

    var whileIsTrue = true
    fun play() {
        while (whileIsTrue) {
            print("> Enter your command: ")
            println(GameInput(readLine()).processCommand())
        }
    }

    private class GameInput(arg: String?) {
        private val input = arg ?: ""
        val command = input.split(" ")[0]
        val argument = input.split(" ").getOrElse(1, { "" })

        fun processCommand() = when (command.toLowerCase()){
            "move" -> move(argument)
            "quit", "exit" -> {whileIsTrue = false; "Quitting..."}
            "map" -> printMap()
            else -> commandNotFound()
        }
    }

    private fun printMap(): String {
        var mapString = ""
        worldMap.forEach {
            it.forEach {
                if (it.name == currentRoom.name) {
                    mapString += "X "
                } else {
                    mapString += "O "
                }
            }
            mapString += "\n"
        }
        return mapString
    }
}

Another solution to the challenge:

Process command:
"map" -> map()

And funnction:

private fun map() = let {
	var mapString = ""
	worldMap.forEach { listRooms ->
		listRooms.forEach { room ->
			mapString += if (room == currentRoom) "X " else "O "
		}
		mapString += "\n"
	}
	mapString.trim()
}