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: 出目がラッキー ナンバーでない場合は、再挑戦メッセージを表示します。
このロジックをコードに追加するには、if
、else
、when
などの特殊な Kotlin キーワードを使用します。
例をいくつか見てみましょう。
if
ステートメントを使用して、満たされる条件を設定する
- 下記のコードを確認して、出力がどうなるかを考えてみてください。
fun main() {
val num = 5
if (num > 4) {
println("The variable is greater than 4")
}
}
- コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認します。
The variable is greater than 4
このプログラムの判断プロセスは次のとおりです。
- 変数
num
を作成し、5.
に設定します。 - 「
num
は 4 より大きい」が true の場合、"The variable is greater than 4"
を出力します。 - それ以外の場合は何もしません。
上記の例では、num
が 5 に設定されています。if
ステートメントは、変数が 4 より大きいかどうかを比較します。これは true なので、次に中かっこ内の命令を実行し、メッセージを出力します。
if
ステートメントの一般的な形式は次のとおりです。
if
キーワードで始めます。- 次に、一組のかっこ
()
を続けます。かっこの中に条件を記述します。条件は、true
またはfalse
のいずれかになるものにします。たとえば、ある数値が別の数値より大きいかどうかなどです。 - その後に、一組の中かっこ
{}
を続けます。中かっこ内には、条件がtrue
の場合に実行するコードを記述します。
if (condition-is-true) { execute-this-code }
if
ステートメントを使用して、満たされない条件を設定する
- 次のように、
num
の値を 3 に変更します。このコードを実行するとどうなるでしょうか。
fun main() {
val num = 3
if (num > 4) {
println("The variable is greater than 4")
}
}
- コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して空の出力を確認します。
num
を 3 に設定すると、num
の値が 4 未満のため、何も出力されません。num
が 4 より大きいという条件が false
であるため、中かっこ間のコードは実行されず、何も出力されません。
else
を使用して、条件が満たされない場合の代替処理を作成する
条件が満たされない場合に何もしないのではなく、ユーザーに代替処理を提供することもできます。これは通常の英会話の表現と同様に、else
ステートメントで実現できます。
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")
}
}
- コードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認します。
The variable is less than 4
num
の値が 3 の場合、num
が 4 以下となるため、プログラムはelse
ステートメントに関連付けられたメッセージ「The variable is less than 4
」を出力します。num
を 5 に変更して、プログラムを再実行します。「num
が 4 より大きい」が true となり、プログラムは "The variable is greater than 4
" を出力します。num
を 4 に変更して、プログラムを実行します。4 は 4 以下であるため、プログラムは "The variable is less than 4
" を出力します。
"The variable is less than 4
" は、コードで設定した条件の出力としては正しいですが、4 は 4 未満ではないため、出力されたメッセージの内容は正確ではありません。この問題を解決するために、3 つ目の可能性(num
が 4 の場合)をチェックして、この条件が true の場合に正しいメッセージを出力する別の条件を追加することもできます。
else
と if
を組み合わせて代替条件を追加する
条件は複数指定できます。たとえば、次のように 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
ステートメントが追加されています。
- 上記のコードをコピーして Kotlin プログラム エディタに貼り付け、プログラムを実行して出力を確認してください。
The variable is equal to 4
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()
}
}
出目がラッキー ナンバーかどうかを確認する
最初にラッキー ナンバーを作成し、サイコロの出目をラッキー ナンバーと比較します。
main()
のprintln()
ステートメントを削除します。main()
にluckyNumber
というval
を追加し、値を 4 に設定します。コードの内容は次のようになります。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
}
- その下に
if
ステートメントを追加し、かっこ()
内に、rollResult
がluckyNumber
に等しい(==
)かどうかをチェックする条件を記述します。中かっこ{}
の間にコードを追加できるように、スペースを残しておきます。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
if (rollResult == luckyNumber) {
}
}
- 中かっこ
{}
内に、"You win!"
と出力するprintln
ステートメントを追加します。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
if (rollResult == luckyNumber) {
println("You win!")
}
}
- プログラムを実行します。出目がラッキー ナンバーと合致して勝利メッセージが出力されるまで、数回実行する必要があるかもしれません。
You win!
出目がラッキー ナンバーと合致しないときの応答を提供する
負けたときにプログラムから何も反応がないと、ユーザーはプログラムが壊れていると思うかもしれません。ユーザーが何かアクションを行うときには、常に応答を提供することをおすすめします。Lucky Dice Roller プログラムでは、else
ステートメントを使って負けを伝えます。
"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!")
}
}
- プログラムを実行すると、結果にかかわらず常にメッセージが表示されます。
これで、ユーザーは自分の勝敗を確認できるようになりましたが、その理由についてはわからないままです。アクションの結果がわかるように、常にユーザーに情報を提供するようにしてください。たとえば、ローンを申請するプログラムの場合、「お客様の信用格付けが低いため、承認されませんでした」と伝えた方が、「あいにくローンを提供できません。もう一度お試しください」と伝えるよりも多くの情報を提供できます。Lucky Dice Roller の場合は、ユーザーが負けたときに、出目に応じて異なるメッセージを表示できます。これを実現するには、複数の else if
ステートメントを使用します。
- 複数の
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!")
}
}
上記のコードでは、次の条件を使用しています。
rollResult
がluckyNumber
かどうかを確認します。rollResult
がluckyNumber
の場合、勝利メッセージを出力します。- それ以外の場合は、
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
で始め、その後にかっこ ()
を続けます。かっこ内にテストする値を指定します。その後に波かっこ {}
を続け、その中にさまざまな条件で実行するコードを記述します。
- プログラムの
main()
で、最初のif
ステートメントから、最後のelse
ステートメントを閉じている中かっこ}
までのコードを選択し、削除します。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
}
main()
のluckyNumber
宣言の下に、when
ステートメントを作成します。when
は出目の結果と比較してテストする必要があるため、()
の間にrollResult
を記述します。中かっこ{}
を、以下のようにスペースを空けて追加します。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
when (rollResult) {
}
}
前と同様に、まず、rollResult
が luckyNumber
と同じかどうかをテストします。
when
ステートメントの中かっこ{}
内に、rollResult
をluckyNumber
と比較してテストするステートメントを追加します。それらが同じ場合は、勝利メッセージを出力します。ステートメントは次のようになります。
luckyNumber -> println("You win!")
これは次のことを意味します。
- まず、
rollResult
と比較する値を記述します。つまり、luckyNumber
です。 - 続けて矢印(
->
)を記述します。 - 次に、一致した場合に実行するアクションを追加します。
全体で、「rollResult
が luckyNumber
の場合は、"You win!"
メッセージを出力する」という意味になります。
main()
コードは次のようになります。
fun main() {
val myFirstDice = Dice(6)
val rollResult = myFirstDice.roll()
val luckyNumber = 4
when (rollResult) {
luckyNumber -> println("You win!")
}
}
- 同じパターンを使用して、以下のように考えられる出目(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!")
}
}
- プログラムを実行します。出力されるメッセージは変わっていませんが、コードがコンパクトで読みやすくなっています。
これで、条件に応じてメッセージを出力する方法を 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
データ型の値はtrue
とfalse
であり、条件判断に使用できます。- 大なり(
>
)、小なり(<
)、等しい(==
)などの演算子を使用して値を比較します。 - 複数の条件を設定するには、一連の
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. 自習用練習問題
次のことを行います。
- 面が 8 つになるように
myFirstDice
を変更し、コードを実行しましょう。どうなるでしょうか。
ヒント: 面数を増やすと、when
ステートメントがすべてのケースをカバーできなくなります。そのため、カバーされていないケースについては何も出力されません。
- 8 面すべてをカバーできるように
when
ステートメントを修正してください。これを行うには、追加の数字に対応するケースを追加します。課題: 数字ごとに新しいケースを追加するのではなく、else
ステートメントを使用して、明示的にカバーされていないすべてのケースを捕捉してください。
ヒント: 追加の数字ごとに対応するケースを追加することもできます。考えられる出目ごとにメッセージを変えたい場合は、この方法が適しています。または、else
ステートメントを使用して、6 よりも大きいすべての面に対して現行のコードでカバーされる同じメッセージを出力することもできます。
- 面が 4 つのみになるように
myFirstDice
を変更しましょう。どうなるでしょうか。
ヒント: サイコロの面数を when
ステートメントでカバーされる値よりも小さい値に変更しても、起こり得るすべてのケースがカバーされるため、特に影響はありません。