小学校の先生のためのSwift Playgrounds講座 コードを学ぼう2<変数>【解答】
プログラミングなんてやったことないぜキリッ
という先生のための Swift Playgrounds を使ったセミナーです。
前回までで「コードを学ぼう1」の全ステージをクリアしました。今回から「コードを学ぼう2」へ突入します。
コードを学ぼう2の記念すべき第1回は「変数」です。
変数って何?
変数って、漢字で書くと「変わる数」です。値が変化する「もの」のことを変数と言います。これは数学で言うところの y = x の x を指すことと同じ意味です。
一次関数 y = x の 変数xが取りうる値(値域)が整数に限定される場合、プログラミングにおいては、整数型の変数 x と呼びます。変数にはどういう性質の値を取りうるのかを表す「型」という概念がセットになります。
「型」には整数以外にも、少数や、文字列等があります。一度、整数「型」として用意した変数は、プログラムの途中で他の型の値を取ることはできません。
下の例は、年齢を示す変数 age を定義しています。var は variableの略で 変数であることを表します。ageは変数の名前(xと同じ)です。変数ageに10という整数値を代入(=)していることから、変数ageの値域は整数を取る。ということが宣言されました。
var age = 10
ageの値は、プログラムの途中で変化させることができます。
例えば、
var age = 10
age = age * 10
と書くと、ageの値を10倍してageへ代入(=)するという処理が実行されます。
結果は、勿論 100 ですね。
この変数 age に他の型を代入するとエラーになります。
例えば、
var age = 10
age = "swift playgrounds"
と書いてしまうと、ageは整数型で定義されたにも関わらず、文字列(swift playgrounds)を代入したということでエラーとなってしまいます。エラーが発生しているプログラムは実行することが出来ないので、正しいプログラムに直す必要があります。
コードを学ぼう2の「変数」では、整数型の変数を使ってステージをクリアしていきます。
それでは早速始めましょう!!
記録する
最初のステージは変数の使い方を学びます。ステージはとっても簡単で、目の前に落ちている宝石1個を取ったらクリアです。ただし、宝石を取るだけではなく、宝石の数を記録するための変数を用意して、宝石を取ったら変数の値を増やして「取った宝石の数」を記録するプログラムを作ります。
このステージは、最初から宝石の数を記録するための変数が用意されています。
var gemCounter = value
と書いてあると思います。valueの部分には、変数の初期値(最初の値)を書いておきます。取った宝石の数は、最初は一個も取っていないのですから、ゼロ0ですね。
つまり、変数を定義する最初の一文は、
var gemCounter = 0
と書くことになります。もし、最初から宝石を3持ってスタートするステージの場合は、
var gemCounter = 3
と書きます。
宝石は2歩先に落ちています。プログラム全体はこのようになります。
var gemCounter = 0 ←変数を定義
moveForward()
moveForward() ←2歩進んで
collectGem() ←宝石を取る
gemCounter = 1 ←とった宝石の数を記録(1個とったので、変数に1を代入する)
プログラムを実行してみます。
クリアしました!
変数も使い方をおぼえてしまえば簡単に使えますね。
値を増やす
このステージは階段の上に5個の宝石が並べられています。宝石を取ったら変数(gemCounter)に獲った宝石の数を記録していきます。
宝石は5個(増減しない)あるので、1個宝石を取るたびにgemCunterに正しい値を代入するようにします。
単純に書くと
var gemCounter = 0
moveForward()
collectGem()
gemCounter = 1
moveForward()
collectGem()
gemCounter = 2
moveForward()
collectGem()
gemCounter = 3
moveForward()
collectGem()
gemCounter = 4
moveForward()
collectGem()
gemCounter = 5
と書けますが、同じような処理を繰り返し書いているので、プログラムがとても長くなってしまっています。繰り返し回数があらかじめ分かっているときは forループが使えました。forループを使って書いてみます。
var gemCounter = 0
for i In 1 ... 5 {
moveForward()
collectGem()
genCounter = ????? ←ここをどう書けばいいのか?
}
gemCouncterの代入文をどう書けばいいのでしょうか?
gemCounterの値は、初期値0から1,2,3,4,5と1ずつ増えていきます。変数の値を1ずつ増やしたい場合、
gemCounter = gemCounter + 1
と書くことができます。上の意味は、gemCounterに1と足した値を gemCounterに代入せよ。となります。
gemCounterの初期値はゼロなので、1回目のforループでは、ゼロに1を足した結果の1をgemCounterに代入します。2回目のforループでは、1に1を足した結果の2がgemCounterに代入されることになります。forループは5回繰り返すので、
1回目のforループ:1 = 0 + 1
2回目のforループ:2 = 1 + 1
3回目のforループ:3 = 2 + 1
4回目のforループ:4 = 3 + 1
5回目のforループ:5 = 4 + 1
と計算されることになります。5回目のforループが終わったあと、gemCounterの値は 5になります。宝石を5個とったことを示していますね。
まとめると、プログラムは
var gemCounter = 0
for i In 1 ... 5 {
moveForward()
collectGem()
genCounter = gemCounter + 1
}
となります。プログラムを実行してみます。
クリアしました!
値を増やす
前のステージと同じタイトルですが、ステージのカタチが変わっています。宝石の数も実行するたびに増えたり減ったりします。つまり、ステージをクリアしたときのgemCounterの値は、1にも2にも5にもいろいろな値になるということになります。
コの字型のステージなので、突き当たったら右手に道が続いているか調べて、続いていれば右へ向きを変えます。最後に行き止まりまで進んだらプログラムは終了です。
変数gemCounterの定義は同じです。プログラムの本体は以下のように書けます。
moveAndCheck関数は一歩進んで宝石が落ちていれば宝石を取ってgemCounterの値を1つ増やします。
whileループは、行き止まりまで繰り返し実行したいので、行き止まりでないことチェックするために、「右手が壁になっていてかつ正面が壁ではない」ことを条件にしています。
if文は、正面が壁(行き止まり)だけど、右手に道が続いている場合です。このときは、右を向いて1歩進みます。if文の中のmoveAndCheckは一見すると要らなそうにも見えますが、書いておかないと上手く動きません。
理由は考えてみてください。
上のプログラムを実行してみます。
クリアしました!!
7つの宝石を集める
このステージは、コードを実行している途中で宝石がどんどん増えていきます。宝石が出現するタイミングと位置はランダムです。
Byteくんを前後に行ったり来たりさせながら7つの宝石を集めます。
7つの宝石が集まるまでは何回も行ったり来たりしなければなりません。繰り返し回数が分からないときは、whileループを使うのでしたね。
今までのステージでは、「行き止まりでない間」というような条件を指定してwhileループを使っていました。実はwhileループの条件として変数を使うこともできるのです。
このステージでは7つの宝石を集める間は処理を繰り返したいわけで、その間、変数gemCounterが7以上の値を取ることはありません。
これをプログラムにすると
while gemCounter < 7 {
...
}
と書くことができます。gemCounterが7より小さい(7つ取っていない)間繰り返すという意味になります。whileループの中身は今まで何度も出てきたコードになります。
一歩進んで宝石が落ちていたら宝石を取ってgemCounterを1増やします。if文は行き止まりに突き当たったら回れ右(turnRightを2回)をします。
このプログラムを実行すると7つの宝石が出現するまで、延々と行ったり来たりして、7つ宝石がとれたところでプログラムが終了するのが分かると思います。
3つの宝石と4つのスイッチ
このステージは、決められた数だけ宝石とスイッチを取るとクリアすることができます(宝石を全部とって、スイッチを全部押してもクリアできないので注意です!)
宝石は3つ
スイッチは4つ
がクリアするための条件です。
下の写真には、宝石が8個、スイッチが7個見えていますが、このうち宝石は3つだけとって残りは取らずに、スイッチは4つだけ押して残りは押さないというプログラムを作ります。
また、取った宝石の数を記録する変数の他に、押したスイッチの数を記録する変数も必要になります。変数は2つ必要です。
宝石の数はnumberOfGemに、スイッチの数はnumberOfSwitchに記録していきます。
ステージをクリアするためには、宝石とスイッチの数を合計して7になるまで処理を繰り返す必要があります。
これをwhileループの条件に指定してプログラムを書くと以下のように書けます。
冒頭のwhile numberOfGem + numberOfSwitch < 7が宝石とスイッチの数の合計が7未満の間繰り返すという意味になります。
最初のif-else if文は宝石をとったりスイッチを押すためのコードです。それぞれ対応する変数を1ずつ増やします。
2番目のif文は突き当りの処理です。右側へ道が続く場合は右へ向きを変えて、左側に道が続く場合は左へ向きを変える処理を書いています。
上のプログラムの動きを動画で確認してみましょう。
どうですか?宝石を3つ取ってとスイッチを4つ押したところでクリアできたでしょうか?
値が等しいかどうか調べる
このステージでは新しい言葉が登場します。
定数
です。定数というのは字の通り、「定まった数」です。変数とは違って、一度代入した値から変更することが許されません。
このステージでは、スイッチの数と同じ数だけ宝石を集めます。下の写真では2つのスイッチが見えます。このスイッチは既に押されており、Byteくんもスイッチのある方には歩いていくことはできません。では、どうやってByteくんはスイッチが2つあるということを知るのでしょうか?
スイッチの数は、numberOfSwitchesという変数が教えてくれます。numberOfSwitchesはプログラムの中で初期化されていない点に注意してください。
この変数は、プログラムが勝手に初期化してくれるのです。プログラムがスタートしたときに、スイッチの数が2つなら2に、5つなら5に初期化されます。
そして、numberOfSwitchesの値を使って、定数switchCounterを初期化しているのが次の一文です。
let switchCounter = numberOfSwitches
let は定数を定義するときに使うキーワードです。定数switchCounterの初期値はnumberOfSwitchesから取得します。プログラムスタート時点のスイッチの数が自動的に代入されます。
グルグル回りながら宝石を集める構造なのでByteくんの動作を指示するプログラムはシンプルに書くことが出来ますね。
whileループの条件に気をつけてください。
スイッチと同じ数だけ宝石を集めるということは、言い換えると宝石の数がスイッチの数と等しくない間は繰り返すという意味になります。
等しくない(不等号)の記号は != です。
クリアできました!!
決まった数だけスイッチを入れる
前のステージが、あらかじめ決められた数(定数)と同じ数だけ宝石を集めたのに対して、このステージでは、Byteくんが自分で集めた宝石の数と同じ数のスイッチを押します。多くても少なくてもダメです。
下の写真は宝石が3個落ちています。Byteくんは宝石を全部集めます。3個の宝石が集まりますから、スイッチも同じ数(3個)押さなければいけません。
集めた宝石の数と押したスイッチの数を記録しなければいけませんから、変数は2つ必要です。
Byteくんは、まず宝石が並ぶエリアに入って宝石を集め、ワープマスを使って隣のスイッチエリアへ移動します。
ステージの構造に合わせて、宝石を集めるエリアとスイッチを押すエリアに分けてプログラムを書いてみます。宝石を集めるエリアは、必ずグルっと一周して落ちている宝石を全部あつめなければいけません。つまり、スタート位置から数えてワープマスまで9回(9マス)繰り返します。1歩進みながら宝石が落ちていれば拾ってgemCounterを1ずつ増やすという処理は今まで登場したコードと同じです。ここでは forループを使ってみました。
一方、スイッチエリアに入ったあとは、スイッチの数が宝石の数と等しくなるまで繰り返します。whileループの条件としては、押したスイッチの数が集めた宝石の数より少ない間は繰り返すという意味になるので、小なり記号を使って下のように書けます。
while gemCounter > switchCounter {
...
}
while文の中身は、forループ中身と同様に、一歩進みながらスイッチがあれば押して変数switchCounterの値を1ずつ増やします。
switchCounter += 1
は、
switchCounter = switchCounter + 1
と同じ意味です。上書き方のほうが少しだけタイプ量が減りますよね。
moveAndTurnは自作関数です。
一歩進んで突き当たったら右へ方向を変えます。今まで幾度となく使ってきたコードですね。
どうですか?上手く動きましたか??
決まった数だけ集める
変数の最後のステージです。
このステージは、コードを実行中に次から次へと宝石が出現します。出現する宝石の数はあらかじめ決まっていて、出現するタイミングと位置はランダムに決まります。
Byteくんをワープマスも使いながら行ったり来たりさせながら全ての宝石を集めます。
ランダムに決まる宝石の数は、randomNumberOfGemsという変数を使って知ることができます。randomNumberOfGemsの値はコードを実行したときに最初に決まります。
randomNumberOfGemsの値を定数に代入しておきプログラムの中で使うようにしましょう。
定数はtotalGemsという名前で定義しました。
集めた宝石の数は変数gemCounterです。
繰り返しのための条件は、totalGemsの数と等しい数だけ宝石を集める。です。言い換えると、totalGemsの数より少ない間は繰り返しなさい。ということになりますから、whileループを使って、
while gemCounter < totalGems {
...
}
と書けます。
一歩進みながら宝石を回収していきます。if - else if文は突き当りの場合の方向転換の処理です。右を向くのか、左を向くのか、回れ右をするのか。ですね。
プログラムの動きは動画のほうが分かりやすいので下の動画も見てみてください。
実行中に宝石が次々と出現しているのが見えますか?Byteくんは宝石が出現しなくなるまで集め続けなければならないという過酷な運命を背負っているのです。。
上手く動きましたか?プログラムは何度でもやり直しができるので、動かなくても諦めずに粘り強く取り組んでみてください。
次回は「型」をお届けします。