0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Josh Skeen, David Greenhalgh著 『Kotlinプログラミング』 章末問題に挑戦(第15章)

Last updated at Posted at 2020-12-23

 Josh Skeen, David Greenhalgh著『Kotlinプログラミング』には章末問題がある。残念なことに解答がないので、第13章に引き続き本を読み進めながら答案を記述する。
 もし回答に間違いや意見があれば、ぜひご指摘いただきたい。

第15章 章末問題 回答案

15.9 チャレンジ! quitコマンド

 ゲームを終了するためのquitコマンド、exitコマンドを追加するために、本書p260ページまでのコードの次のように変更した。

まず、ゲームを続行するためのフラグisContinueをGameオブジェクト宣言に追加した。

Game.kt#main()
object Game {
    private val player = Player("Madrigal")
    private var currentRoom: Room = TownSquare()
    private var isContinue = true   // <==ゲームを継続するためのフラグを追加

// 以下省略
}

while()の括弧内をtrueからisContinueに変更する。isContinueがfalseになるとループを抜けることができ、ゲームが終了する。

Game.kt#play()
    fun play() {
        while (isContinue) {    // <==ケームを継続するためのループ条件を true から isContinue に変更
                                // isContinue が falseの時ループから抜ける
            // Play NyetHack
            println(currentRoom.description())
            println(currentRoom.load())

            // Player Status
            printPlayerStatus(player)

            print("> Enter your command: ")
            println(GameInput(readLine()).processCommand())    // ここでreadLine()にexitまたはquitが入力されると
                                                               // GameInput()でisContinueがfalseに変わる
        }
    }

 GameInput()クラスの中の fun processCommand()のwhen()のブランチに"quit", "exit"をついかした。
 このブランチを選択したときに冒険者へのメッセージ"さようなら!"を返すとともに、ゲーム継続のフラグisContinue を falseに変更する。このメソッドを終了したときに、play()の中のwhileループに戻るが、ループ条件がfalseになるため、ゲームは終了する。

Game.kt#GameInput()
    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" -> {
                isContinue = false  // ゲームを終了するためにisContinueフラグをfalseに変更
                "さようなら!"        // 冒険者への別れのメッセージ
            }
            else -> commandNotFound()
        }

        private fun commandNotFound() =
            "あなたの意図かよくわかりません!"
    }
}

15.10 チャレンジ! ワールドマップを実装する

ワールドマップを実装するために、まずmapコマンドをGameInputクラスのprocessCommand()に実装する。ゲーム上でプレイヤーがmapと入力すると、map()関数が呼ばれる。

Game.kt#GameInputクラス
    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" -> {
                isContinue = false  // ゲームを終了するためにisContinueフラグをfalseに変更
                "さようなら!"        // 冒険者への別れのメッセージ
            }
            "map" -> map()     // <== mapコマンドを実装するために追加
            else -> commandNotFound()
        }

        private fun commandNotFound() =
            "あなたの意図かよくわかりません!"
    }

 次にmap()関数を作る。worldMapをひとつひとつ調べ、プレイヤーがいる場所currentRoomかどうかを調べる。for(worldMapY in worldMap)でworldMapのリストArrayからまずY成分を取り出し、次にfor(locationXY in worldMapY)でX成分を取り出す。

Game.kt#map()関数
object Game {

    // 前部分省略

    fun play() {
        // 省略
    }

    private fun map(): String{
        var locationMap = ""    // プレイヤーが部屋にいるかいないかを表す地図

        for(worldMapY in worldMap) {
            for(locationXY in worldMapY){
                if(locationXY == currentRoom){
                    locationMap += "X"      // プレイヤーがいる時
                } else locationMap += "O"   // プレイヤーがいない時
            }
            locationMap += "\n"
        }
        return locationMap
    }

    private fun move(directionInput: String): String {
        // 省略
    }

    // 以下省略

 この結果次のように表示される。

> Enter your command: map
XOO
OO

Room: Town Square

15.11 チャレンジ! 鐘を鳴らす

 「鐘を鳴らすring」を実装するために、まずringコマンドをGameInputクラスのprocessCommand()に実装する。ゲーム上でプレイヤーがmapと入力すると、map()関数が呼ばれる。

Game.kt#GameInputクラス
    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" -> {
                isContinue = false  // ゲームを終了するためにisContinueフラグをfalseに変更
                "さようなら!"        // 冒険者への別れのメッセージ
            }
            "map" -> map()
            "ring" -> ringBell()
            else -> commandNotFound()
        }

        private fun commandNotFound() =
            "あなたの意図かよくわかりません!"
    }

 次にring()関数を作る。現在位置が町の広場(Town Squere)ならばベルを鳴らすようにし、町の広場でなければその旨を告げました。
 ここで、ひとつ疑問なのですが、本書のヒントにringBell関数をpublicにするように書いてありますが、その理由がわかりません。本当はGame.kt以外の別のクラスから呼び出さなければいけないのでしょうか?

Game.kt#ringBell()
    private fun ringBell(): String {
//        if(currentRoom.name == Room("Town Square").name)
        if (currentRoom == worldMap[0][0])
            return "Ringing Bell!"
        else return "This is not Town Square."
    }

第2章チャレンジ!答案
第3章チャレンジ!答案
第4章チャレンジ!答案
第7章チャレンジ!答案
第8章チャレンジ!答案
第10章チャレンジ!答案
第13章チャレンジ!答案
第15章チャレンジ!答案
第18章チャレンジ!答案

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?