Kotlin で条件付き動作を追加する

1. 始める前に

この Kotlin Codelab では、サイコロを振ってラッキー ナンバーを出すことを狙う、Lucky Dice Roll という別のゲームを作成します。このプログラムでは、ラッキー ナンバーを設定してサイコロを振ります。次に、出目をラッキー ナンバーと照合し、適切なメッセージを出力します。これを実現するために、Kotlin プログラムで値を比較し、さまざまな意思決定を行う方法について学習します。

アプリのユーザー インターフェースを気にすることなくプログラミングの概念に集中できるように、ブラウザベースの Kotlin プログラミング ツールを使用して結果をコンソールに出力します。

前提条件

  • https://developer.android.com/training/kotlinplayground でコードを開き、編集し、実行できる。
  • 変数、引数を含む関数、メソッドを含むクラスを使用し、結果をコンソールに出力する Kotlin プログラムを作成、実行できる。

学習内容

  • if ステートメントと else ステートメントの使用方法。
  • 「大なり(>)」、「小なり(<)」、「等しい(==)」などの演算子を使用して値を比較する方法。
  • when ステートメントを使用して、指定された値に基づいてオプションを選択する方法。
  • Boolean データ型の概要と、意思決定に true および false の値を使用する方法。

作成するアプリの概要

  • Lucky Dice Roll という Kotlin ベースのサイコロゲームで、ラッキー ナンバーを指定できます。プレーヤーがサイコロを振り、出目がラッキー ナンバーであれば勝ちとなります。

必要なもの

  • インターネットに接続されているパソコン。

2. コード内での意思決定

Lucky Dice Roller プログラムは、ユーザーがラッキー ナンバーの目を出して勝利のメッセージを受け取るのか、それとも再挑戦を促すメッセージを受け取るのかを判断する必要があります。

あなたはアプリのデベロッパーとして、アプリがどのように動作し、ユーザーごとに異なる結果を出すようにするかを決める必要があります。

ショッピング アプリをビルドしている場合は、ユーザーが選択した配送オプションに応じて異なる画面を表示します。クイズゲームでは、プレーヤーの解答が正しいかどうかに基づいて異なる画面を表示します。アプリによっては結果が多岐にわたる可能性があるため、それを考慮してコードを記述する必要があります。

Lucky Dice Roller プログラムでは、次のケースを処理します。

  • if: 出目がラッキー ナンバーの場合は、勝利メッセージを表示します。
  • else if: 出目がラッキー ナンバーでない場合は、再挑戦メッセージを表示します。

このロジックをコードに追加するには、ifelsewhen などの特殊な Kotlin キーワードを使用します。

例をいくつか見てみましょう。

if ステートメントを使用して、満たされる条件を設定する

  1. 下記のコードを確認して、出力がどうなるかを考えてみてください。
fun main() {
   val num = 5
   if (num > 4) {
       println("The variable is greater than 4")
   }
}
  1. コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認します。
The variable is greater than 4

このプログラムの判断プロセスは次のとおりです。

  1. 変数 num を作成し、5. に設定します。
  2. num は 4 より大きい」が true の場合、"The variable is greater than 4" を出力します。
  3. それ以外の場合は何もしません。

上記の例では、num が 5 に設定されています。if ステートメントは、変数が 4 より大きいかどうかを比較します。これは true なので、次に中かっこ内の命令を実行し、メッセージを出力します。

if ステートメントの一般的な形式は次のとおりです。

  • if キーワードで始めます。
  • 次に、一組のかっこ () を続けます。かっこの中に条件を記述します。条件は、true または false のいずれかになるものにします。たとえば、ある数値が別の数値より大きいかどうかなどです。
  • その後に、一組の中かっこ {} を続けます。中かっこ内には、条件が true の場合に実行するコードを記述します。
if (condition-is-true) {
    execute-this-code
}

if ステートメントを使用して、満たされない条件を設定する

  1. 次のように、num の値を 3 に変更します。このコードを実行するとどうなるでしょうか。
fun main() {
    val num = 3
    if (num > 4) {
        println("The variable is greater than 4")
    }
}
  1. コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して空の出力を確認します。

num を 3 に設定すると、num の値が 4 未満のため、何も出力されません。num が 4 より大きいという条件が false であるため、中かっこ間のコードは実行されず、何も出力されません。

else を使用して、条件が満たされない場合の代替処理を作成する

条件が満たされない場合に何もしないのではなく、ユーザーに代替処理を提供することもできます。これは通常の英会話の表現と同様に、else ステートメントで実現できます。

  1. num が 4 以下の場合にメッセージを出力する else ステートメントを追加します。このコードを実行するとどうなるでしょうか。
fun main() {
    val num = 3
    if (num > 4) {
        println("The variable is greater than 4")
    } else {
        println("The variable is less than 4")
    }
}
  1. コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認します。
The variable is less than 4
  1. num の値が 3 の場合、num が 4 以下となるため、プログラムは else ステートメントに関連付けられたメッセージ「The variable is less than 4」を出力します。
  2. num を 5 に変更して、プログラムを再実行します。「num が 4 より大きい」が true となり、プログラムは "The variable is greater than 4" を出力します。
  3. num を 4 に変更して、プログラムを実行します。4 は 4 以下であるため、プログラムは "The variable is less than 4" を出力します。

"The variable is less than 4" は、コードで設定した条件の出力としては正しいですが、4 は 4 未満ではないため、出力されたメッセージの内容は正確ではありません。この問題を解決するために、3 つ目の可能性(num が 4 の場合)をチェックして、この条件が true の場合に正しいメッセージを出力する別の条件を追加することもできます。

elseif を組み合わせて代替条件を追加する

条件は複数指定できます。たとえば、次のように num のすべての可能性をカバーできます。

  • If: num が 4 より大きい場合は、"The variable is greater than 4" を出力します。
  • else if: num が 4 に等しい場合は "The variable is equal to 4" を出力します。
  • else: それ以外の場合は、"The variable is less than 4" を出力します。

これらの条件は、if-else ステートメントの「さまざまなケース」と呼びます。ここでは 3 つのケースがリストされています。

更新されたコードは次のようになります。

fun main() {
    val num = 4
    if (num > 4) {
        println("The variable is greater than 4")
    } else if (num == 4) {
        println("The variable is equal to 4")
    } else {
        println("The variable is less than 4")
    }
}

次の点が変更されています。

  • num の値を 4 に設定したので、新しい条件をテストできます。
  • num が 4 の場合に対応できるように、元の if ステートメントと else ステートメントの間に、新しく else if ステートメントが追加されています。
  1. 上記のコードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認してください。
The variable is equal to 4
  1. num の値を変更し、出力にどう影響するかを確認してください。各条件が true になることを確認できるように、num を 2 と 6 に変更します。

制御フロー

上記の if-else ステートメントを見ると、コードが条件によって制御されて実行される(流れる)ことがわかります。そのため、このような条件を使って実行を制御する方法を、プログラムの「制御フロー」と呼びます。

  • たとえば、サイコロの出目の num が 3 だとします。プログラムは最初の条件(num > 4)をチェックします。これは false のため、プログラムは次の条件(num == 4)もチェックしますが、また false となります。その後、このプログラムは最後のオプションである else ステートメントのコードを実行します。
  • 出目が 6 の場合、1 つ目の条件(num > 4)が true となります。プログラムは、「The variable is greater than 4」というメッセージを出力します。この条件は true であるため、プログラムは残りの条件を確認する必要はなく、if-else ステートメントを終了します。
  • 代替条件を追加するには、else と if の組み合わせを使用します。

3.Lucky Dice Roll ゲームを作成する

このセクションでは、前のタスクで学んだことを使って Dice Roller プログラムを更新し、サイコロの出目が事前に設定したラッキー ナンバーに合致するかどうかをチェックできるようにします。出目がラッキー ナンバーに合致していれば勝ちとなります。

スターター コードを設定する

以前の Kotlin Dice Roller プログラムの解答コードに類似したコードを使用して、Lucky Dice Roller の作成を始めます。以前のコードの main() 関数を下のように編集するか、以下のコードをコピーして貼り付けて使用してください。

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${rollResult}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}

出目がラッキー ナンバーかどうかを確認する

最初にラッキー ナンバーを作成し、サイコロの出目をラッキー ナンバーと比較します。

  1. main()println() ステートメントを削除します。
  2. main()luckyNumber という val を追加し、値を 4 に設定します。コードの内容は次のようになります。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
}
  1. その下に if ステートメントを追加し、かっこ () 内に、rollResultluckyNumber に等しい(==)かどうかをチェックする条件を記述します。中かっこ {} の間にコードを追加できるように、スペースを残しておきます。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
    if (rollResult == luckyNumber) {

    }
}
  1. 中かっこ {} 内に、"You win!" と出力する println ステートメントを追加します。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    }
}
  1. プログラムを実行します。出目がラッキー ナンバーと合致して勝利メッセージが出力されるまで、数回実行する必要があるかもしれません。
You win!

出目がラッキー ナンバーと合致しないときの応答を提供する

負けたときにプログラムから何も反応がないと、ユーザーはプログラムが壊れていると思うかもしれません。ユーザーが何かアクションを行うときには、常に応答を提供することをおすすめします。Lucky Dice Roller プログラムでは、else ステートメントを使って負けを伝えます。

  1. "You didn't win, try again!" と出力する else ステートメントを追加します。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    } else {
        println("You didn't win, try again!")
    }
}
  1. プログラムを実行すると、結果にかかわらず常にメッセージが表示されます。

これで、ユーザーは自分の勝敗を確認できるようになりましたが、その理由についてはわからないままです。アクションの結果がわかるように、常にユーザーに情報を提供するようにしてください。たとえば、ローンを申請するプログラムの場合、「お客様の信用格付けが低いため、承認されませんでした」と伝えた方が、「あいにくローンを提供できません。もう一度お試しください」と伝えるよりも多くの情報を提供できます。Lucky Dice Roller の場合は、ユーザーが負けたときに、出目に応じて異なるメッセージを表示できます。これを実現するには、複数の else if ステートメントを使用します。

  1. 複数の else if ステートメントを追加して、出目ごとに異なるメッセージを出力します。必要に応じて、前のタスクで学習した形式を参照してください。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    } else if (rollResult == 1) {
        println("So sorry! You rolled a 1. Try again!")
    } else if (rollResult == 2) {
        println("Sadly, you rolled a 2. Try again!")
    } else if (rollResult == 3) {
        println("Unfortunately, you rolled a 3. Try again!")
    } else if (rollResult == 5) {
        println("Don't cry! You rolled a 5. Try again!")
    } else {
        println("Apologies! You rolled a 6. Try again!")
    }
}

上記のコードでは、次の条件を使用しています。

  • rollResultluckyNumber かどうかを確認します。
  • rollResultluckyNumber の場合、勝利メッセージを出力します。
  • それ以外の場合は、rollResult が 1 であるかどうかを確認し、1 の場合は、再挑戦メッセージを出力します。
  • それ以外の場合は、rollResult が 2 であるかどうかを確認し、2 の場合は、別の再挑戦メッセージを出力します。
  • それ以外の場合は、5 まで確認を続けます。
  • 出目が 1~5 ではなかった場合、残るオプションは 6 のみとなるため、else if で別のテストを行う必要はなく、最後の else ステートメントで最後のオプションを捕捉できます。

複数の else if を使用するケースはよくあるため、Kotlin ではこれを簡単に記述できる方法が用意されています。

4. when ステートメントを使用する

結果(またはケース)が多岐にわたるテストは、プログラミングでは非常に一般的です。考えられる結果のリストは、非常に長くなる場合があります。たとえば、12 面のサイコロを振る場合、勝ちと最後の else の間に 11 個の else if ステートメントが含まれることになります。このようなステートメントの読み書きを容易にしてエラーを回避するために、Kotlin では when ステートメントを使用できます。

when ステートメントを使用するようにプログラムを変更します。when ステートメントはキーワード when で始め、その後にかっこ () を続けます。かっこ内にテストする値を指定します。その後に波かっこ {} を続け、その中にさまざまな条件で実行するコードを記述します。

  1. プログラムの main() で、最初の if ステートメントから、最後の else ステートメントを閉じている中かっこ } までのコードを選択し、削除します。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
}
  1. main()luckyNumber 宣言の下に、when ステートメントを作成します。when は出目の結果と比較してテストする必要があるため、() の間に rollResult を記述します。中かっこ {} を、以下のようにスペースを空けて追加します。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {

    }
}

前と同様に、まず、rollResultluckyNumber と同じかどうかをテストします。

  1. when ステートメントの中かっこ {} 内に、rollResultluckyNumber と比較してテストするステートメントを追加します。それらが同じ場合は、勝利メッセージを出力します。ステートメントは次のようになります。
luckyNumber -> println("You win!")

これは次のことを意味します。

  • まず、rollResult と比較する値を記述します。つまり、luckyNumber です。
  • 続けて矢印(->)を記述します。
  • 次に、一致した場合に実行するアクションを追加します。

全体で、「rollResultluckyNumber の場合は、"You win!" メッセージを出力する」という意味になります。

main() コードは次のようになります。

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You win!")
    }
}
  1. 同じパターンを使用して、以下のように考えられる出目(4 を除いた 1~6)の行とメッセージを追加します。完成した main() 関数は次のようになります。
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You won!")
        1 -> println("So sorry! You rolled a 1. Try again!")
        2 -> println("Sadly, you rolled a 2. Try again!")
        3 -> println("Unfortunately, you rolled a 3. Try again!")
        5 -> println("Don't cry! You rolled a 5. Try again!")
        6 -> println("Apologies! You rolled a 6. Try again!")
    }
}
  1. プログラムを実行します。出力されるメッセージは変わっていませんが、コードがコンパクトで読みやすくなっています。

これで、条件に応じてメッセージを出力する方法を 2 つ学習しました。これは、興味深いプログラムを作成するための強力なツールとなります。

5. 解答コード

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You won!")
        1 -> println("So sorry! You rolled a 1. Try again!")
        2 -> println("Sadly, you rolled a 2. Try again!")
        3 -> println("Unfortunately, you rolled a 3. Try again!")
        5 -> println("Don't cry! You rolled a 5. Try again!")
        6 -> println("Apologies! You rolled a 6. Try again!")
   }
}

class Dice(val numSides: Int) {
    fun roll(): Int {
        return (1..numSides).random()
    }
}

6. まとめ

  • 一部の命令を実行するための条件は、if ステートメントを使用して設定します。たとえば、出目がラッキー ナンバーと一致した場合には、勝利メッセージを出力します。
  • Boolean データ型の値は truefalse であり、条件判断に使用できます。
  • 大なり(>)、小なり(<)、等しい(==)などの演算子を使用して値を比較します。
  • 複数の条件を設定するには、一連の else if ステートメントを使用します。たとえば、考えられる出目ごとに異なるメッセージを出力します。
  • 一連の条件の最後に else ステートメントを使用すると、明示的にカバーされていないケースを捕捉できます。6 面サイコロのケースをカバーしている場合、else ステートメントは 8 面サイコロを振って出た 7 と 8 の数を捕捉します。
  • when ステートメントを使用すると、値の比較に基づいてコンパクトな形式でコードを実行できます。

if-else の汎用的な形式:

if (condition-is-true) {
    execute-this-code
} else if (condition-is-true) {
    execute-this-code
} else {
    execute-this-code
}

when ステートメント:

when (variable) {
    matches-value -> execute-this-code
    matches-value -> execute-this-code
    ...
}

7. 詳細

8. 自習用練習問題

次のことを行います。

  1. 面が 8 つになるように myFirstDice を変更し、コードを実行しましょう。どうなるでしょうか。

ヒント: 面数を増やすと、when ステートメントがすべてのケースをカバーできなくなります。そのため、カバーされていないケースについては何も出力されません。

  1. 8 面すべてをカバーできるように when ステートメントを修正してください。これを行うには、追加の数字に対応するケースを追加します。課題: 数字ごとに新しいケースを追加するのではなく、else ステートメントを使用して、明示的にカバーされていないすべてのケースを捕捉してください。

ヒント: 追加の数字ごとに対応するケースを追加することもできます。考えられる出目ごとにメッセージを変えたい場合は、この方法が適しています。または、else ステートメントを使用して、6 よりも大きいすべての面に対して現行のコードでカバーされる同じメッセージを出力することもできます。

  1. 面が 4 つのみになるように myFirstDice を変更しましょう。どうなるでしょうか。

ヒント: サイコロの面数を when ステートメントでカバーされる値よりも小さい値に変更しても、起こり得るすべてのケースがカバーされるため、特に影響はありません。