小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<条件分岐コード>【解答】
こんばんは。ツムさんです。
プログラミングなんてやったことないぜキリッ
という先生のための Swift Playgrounds を使ったセミナーです。
前回までに、Byteくんを動かすための「コマンド」と、繰り返し使うコマンドを「関数」にまとめることを学びました。また、コマンドを繰り返し実行するためには「forループ」を使うことも勉強しました。
第4回は、条件分岐コードです。
条件分岐とは
条件分岐は、ほとんどのプログラミング言語でサポートされている概念です。英語で書くと if ... else ... という構文を使います。
英語の if の意味そのままに、もし ~ なら ... する。という意味に解釈されます。~の部分には、様々な条件が入ります。たとえば、信号機が青のとき、天気が晴れのとき、道が行き止まりのとき、などなど。
条件に当てはまったときには、if文の中に書いたプログラムが実行されます。
もし 信号機が青 なら、 前へ進む。というような処理は、
if lightIsGreen {
moveForward()
}
というプログラムで実現することができます。
else は、if文と組み合わせて使います。if文の条件に当てはまらなかったときには、else 文の中に書かれたプログラムが実行されます。
if lightIsGreen {
moveForward()
} else {
Stop()
}
この例は、
もし信号が青なら前へ進む。青でなければ止まる。
と解釈されます。
if文をマスターすることで、より柔軟なプログラムが書けるようになります。
スイッチを調べる
このステージは、3つのスイッチが置いてあります。スイッチは実行する度に、OnとOffの状態が切り替わります。ある時は、全部Offだったり、またある時は1個だけOnで残りの2個はOffという具合です。
if文が使えない場合、実行する度にそのスイッチの状態に合うプログラムを作ることになってしまいます。(2番目のスイッチだけ押すというようなプログラムは、2番目のスイッチだけがOffになっているステージにしか正しく作用しません)
ここでは、3つのスイッチをif文を使って、OnかOffかを調べ、Offの場合はスイッチを押すプログラムを作ります。
if文の条件に使うことができるのは、isOnClosedSwitch(スイッチOff) もしくは isOnOpendSwitch(スイッチOn) です。
スイッチを押す必要があるのは、スイッチが切れているとき(Offのとき)だけでよいので、if 文を使って書くと
if isOnClosedSwitch {
toggleSwitch()
}
というプログラムになります。
ステージには3つのスイッチが配置されているので、一歩進む度にifでスイッチの状態を調べて、3回繰り返してゴールを目指します。
一歩進んでifを使って調べる処理を、ここでは関数(moveThenToggle)で作っています。スタートしたら一歩進んでから3回繰り返す処理に入ります。繰り返しの処理は前回学んだforループコマンドを使っています。
スイッチのOn/Offは実行する度に変化するので、何回か「コードを実行する」を試してみてください。スイッチのOn/Offが変化しても、ifにより正しくスイッチの状態をチェックできればオーケーです。
else ifを使う
冒頭に紹介した else を使うステージです。このステージは「コードを実行する」たびに、宝石とスイッチの数が変化します。Byteくんの前の2マスともに宝石が出てきたり、スイッチと宝石が1つずつ出てきたり、毎回ランダムに変化します。
elseはifの条件に合致しなかった場合に実行されるのでした。もし 宝石でなかった場合は、スイッチであるかどうかを調べて、切れている(Off)スイッチであれば、スイッチを押します。
elseを追加する方法は、ifをタップすると下記のようなメニューが出るので、「else if文を追加」を選んでタップします。
一歩進んで宝石かスイッチかを調べる処理を関数(moveThenCheck)で実現しています。ステージは2マス処理したら終了なので、moveThenCheck関数を2度実行します。
クリアしました!
条件分岐コードをループする
途中にワープマスが登場しますが、このステージは一本道なのでひたすら真っすぐ進みながら、宝石とスイッチを処理していきます。宝石とスイッチがどのマスに現れるかは、前のステージと同様、ランダムに変化します。
ランダムに変化するということは、ifを使って宝石かスイッチかをチェックしなければなりません。
ワープマスを含めて何マス進めばゴールできるのか、しっかり数えてforループの繰り返し回数に指定してください。
全部で12マスなので、12回前へ進む必要がありますね。つまり、forループの繰り返し回数は12となります。
forループの中には、
一歩進んでifを使ってOffスイッチ(isOnClosedSwitch)か宝石(isOnGem)かを調べています。
クリアです!!
階段を上がる条件を探す
前2つのステージはifで調べながら前へ進むだけでクリアできましたが、ここでは方向転換が必要です。らせん状の道を進んでいきます。
よく見ると、らせん状の階段の手前には必ず宝石が置いてあることが分かります。この宝石は固定して置いてあります(前回のように現れたり消えたりするものではないです)。ということは、宝石のマスに止まったときには、左へ方向転換して進めば、らせん階段をグルグル登っていくことが出来ますね。
宝石のマスかどうかは if を使って調べることができます。宝石のマスでないときは、一歩前へ進みます。
「宝石のマスでないとき」という条件は、elseを使って表現することができます。
このステージで気をつけたいのは、forループの繰り返し回数です。山頂の宝石までのマスを数えると12マスであることは分かりますが、forループの繰り返し回数を12へ変更すると、ステージをクリアすることが出来ません(山頂にたどり着けずにByteくんは止まってしまいます)
何故でしょうか?
if文の条件に当たった場合は、宝石を取って(collectGem)、左へ向いて(turnLeft)いますが、前進していないから(if文が実行されたときelse文は実行されない)です。
そのため、宝石のマスの数の分、forループの繰り返し回数を増やしてあげないと、Byteくんは山頂にたどり着くことが出来ないというわけです。
forループの繰り返し回数を 12 回でクリアしたい場合は、
elseを使わずに、
for i in 1 ... 12 {
moveForward()
if isOnGem {
collectGem()
turnLeft()
}
}
とすると、クリアすることができます。ただし、ステージの意図(elseを使う)とは異なりますが。。
関数をじょうずに使う
このステージも、宝石とスイッチが現れるマスが変化します。下の例では、宝石は4つ、スイッチは2つですが、全部宝石になったり、スイッチが5つ(宝石が1つ)になったりします。
ただし、宝石とスイッチが現れるマスの位置は変化しません。よく見ると、宝石やスイッチが置かれたマスは、同じ列であれば1マス飛びに登場します。
ということは、2歩進んで宝石かスイッチを調べるという処理を2回繰り返すと一列分を処理することができます。全部で3列あるので、3回繰り返してあげればクリアできそうです。
まず、一番細かい処理として、2マス進んで宝石かスイッチかを調べる関数(collectOrToggle)を作ります。
あとは、collectOrToggle関数を一列につき2回ずつ実行(forループ使用)して隣の列へ移るという処理を繰り返していきます。上のプログラムのturnLeftやmoveForwardは隣の列へ移る処理です。全部で3列(3回)繰り返すとこのステージはクリアです!
囲まれる
このステージでは、ifの新しい条件が登場します。
その名も、
isBlocked
と言います。これは、行き止まり(Blocked)かどうかを調べるための条件です。
if isBlocked { ... }
と書くと、行き止まりかどうかを調べ、行き止まりであれば、括弧の中のコマンドを実行します。
ステージには全部で8つの宝石もしくはスイッチが置かれています。実行のたびにランダムで登場するため、ifを使った確認が必要です。
宝石かスイッチかを確認しながら一歩一歩進めていきますが、もし突き当りに当たったら左へ向きを変えます。
こうして、1周ぐるっと回りながら8つの宝石やスイッチを回収することができます。
クリアできました!
繰り返しを探す
条件分岐の最後のステージです。ここでは、真っすぐ進みながら、枝分かれした道の先の宝石を回収します。
中央の通りの上には、宝石とスイッチが置いてありますが、宝石のマスの右側とスイッチのマスの左側に、それぞれ枝分かれした道が続いています。
ということは、真っすぐ進みながら、宝石かスイッチを調べて、宝石だったら右へ向きを変えて、スイッチだったら左へ向きを変えればいいことが分かります。
パッと見複雑そうなステージですが、動きのパターンを見つけてしまえば、シンプルにプログラムを作ることができます。
まずは、右へ枝分かれしている道を攻略しましょう。ここでは、右へ進んだ場合の処理を関数(solveRightSide)として作っています。右側の小道は2か所登場しますが、どちらも同じ構造なので、全く同じ関数で処理することができます。
「3歩進んで左へ向きを変えて、1歩進んで宝石を取り、後ろへ向きを変えてもとのマスへ戻る。」
で処理できますね。
一方で、左側の小道は、右側の小道と比べて簡単です。
「1マス進んで宝石を取って引き返す」だけです。
関数の名前は solveLeftSideです。
最後に、forループを使って、中央の道を進みながら、宝石のマスに停まったら右の小道を処理する関数(solveRightSide)を呼び出し、スイッチのマスに停まったら左の小道を処理する関数(solveLeftSide)を呼ぶようにします。
無事にクリアしました!