Josh Skeen, David Greenhalgh著『Kotlinプログラミング』には章末問題がある。残念なことに解答がないので、第13章に引き続き本を読み進めながら答案を記述する。
もし回答に間違いや意見があれば、ぜひご指摘いただきたい。
第15章 章末問題 回答案
15.9 チャレンジ! quitコマンド
ゲームを終了するためのquitコマンド、exitコマンドを追加するために、本書p260ページまでのコードの次のように変更した。
まず、ゲームを続行するためのフラグisContinueをGameオブジェクト宣言に追加した。
object Game {
private val player = Player("Madrigal")
private var currentRoom: Room = TownSquare()
private var isContinue = true // <==ゲームを継続するためのフラグを追加
// 以下省略
}
while()の括弧内をtrueからisContinueに変更する。isContinueがfalseになるとループを抜けることができ、ゲームが終了する。
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になるため、ゲームは終了する。
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()関数が呼ばれる。
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成分を取り出す。
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()関数が呼ばれる。
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以外の別のクラスから呼び出さなければいけないのでしょうか?
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章チャレンジ!答案