小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<アルゴリズム>【解答】
こんばんは。ツムさんです。
プログラミングなんてやったことないぜキリッ
という先生のための Swift Playgrounds を使ったセミナーです。
前回は、whileを使って繰り返し回数を明示しない条件を使ったループのさせ方を学びました。前回までの記事はこちらからどうぞ。
小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<簡単なコマンド>【解答】
小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<関数>【解答】
小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<forループ>【解答】
小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<条件分岐コード>【解答】
今回は、Swift Playgroundsコードを学ぼう1の最終回「アルゴリズム」です。
アルゴリズムって何?
辞書的に書くと、
アルゴリズムとは、問題を解決するためにつかわれる一連のルールや指示のこと
です。
たとえば、迷路をクリアするためは「右手の法則」というようなルールに従って迷路を進むとどんな迷路であってもクリアすることが出来ます。
迷路をクリアするという課題に対して「右手の法則」というルールが問題を解決するために使われている「アルゴリズム」にあたります。
当然、「アルゴリズム」が間違っていたりすると、問題をクリアできないことになってしまうわけで、正しい「アルゴリズム(ルール)」を考えて、そのルールを正しく実行できるプログラムを書くことが必要になります。
今までSwift Playgroundsで数多くのステージをクリアしてきました。各ステージには宝石やスイッチが置いてあり、それらをすべて取りながら進むようにByteくんに指示を与えてきたことになります。
Byteくんは、与えられた指示(=ルール)どおりに動き、宝石をとり、スイッチを押します。指示が間違っていれば宝石を取ることはできないし、スイッチを押すこともできません。つまり、ここまでクリアしてきたステージにつき1つ「ステージをクリアするためのアルゴリズム」を考えてプログラムを作ってきたんですね。
世の中のプログラマーと呼ばれる人たちはアルゴリズムを実際のプログラムに書き下すことを仕事にしています。プログラマーの人が指示を出すのはByteくんではなく、高性能なコンピューターだったり、スマホだったりします。
こういわれると、なんだかすごいことをやってきたような感じがしませんか?
右手法
いきなり右手法です。一般的には迷路をクリアするためのアルゴリズムですが、このステージは迷路ではありません。
宝石が3つとスイッチが1つです。これらの位置は変わりません。ただし、宝石とスイッチを遮る壁の奥行が実行する毎に変化します。
こんな感じで壁のマス数が変わります。
変化する壁の数に追従しながらByteくんを動かす必要があるわけですから、forループで回数を指定して繰り返すプログラムではこのステージをクリアすることは難しいですよね。そういう場合はwhileループを使います。
このステージは日本語で書かれた疑似コードが用意されているので、これに従ってプログラムを作ります。ゴールは切れているスイッチです。このスイッチを目指して歩を進めます。まずは「壁を周って進む」ための関数を作りましょう。
ここでは、navigateAroundWallという名前の関数です。右手が行き止まり(壁に手をつけながら)なら1歩進めます。これが右手法と呼ばれる理由です。
もし、右手に壁が無ければ右を向いて1歩進めます。コーナーを曲がる動作になります。
この関数をwhileループから呼び出してあげることで右手を壁につけながら一歩一歩前進するようになります。
でも、ちょっと待ってください。宝石のマスに止まったときはどうすればいいのでしょうか。このマスは袋小路です。右手には壁があるので、Byteくんは前へ進もうとします。しかし、そこは壁(行き止まり)です。
宝石を取るcollectGemのあとのturnRightに注目してください。行き止まりで左ではなく右を向きます。考えてみると、もし左へ向けてしまうと、またしても右手側に壁(行き止まり)があることになってしまいByteくんは正面の壁めがけて突進してしまうのです。ここで右を向くと、もう一度右手には壁がない状態になり、再び右を向きます。つまり丁度180°後ろを向くことができるわけです。
最後はスイッチを押してクリアです。
アルゴリズムを直す
前のステージと似ていますが、周るブロックの種類が増えています。
- 右側と前が壁の場合
- 右側だけ壁の場合
- 右にも前にも壁が無い場合
の3つのケースを考えなければなりません。前のステージは2の条件を使ってif/else文で制御しました。2と2以外の条件という分け方でした。
ここでは上の3つを区別する必要があるので、if/else if/elseを使います。
下のようにifを作ってみました。
右も前も壁の場合(1つ目の宝石マス)は左を向いて進めばよさそうです。すぐに行き止まりですが、再び右も前も壁になるので、もう一度左を向いて進んでいけます。2と3の条件のとき、処理する内容は前のステージと同等です。
宝石を取ったあとの右を向くコマンドは不要になります。なぜなら袋小路に入った場合でも、ifの条件(右も前も壁)に必ず「2度」引っかかるために、回れ左をして袋小路から脱出することができるからです。
クリアしました!
迷路を解く
このステージは1個だけ置いてある宝石を取るとクリアです。ただし、宝石に至るまでの道が迷路のように入り組んでいます。
迷路なので、「右手法」を使って解くことができます。「右手法」は前のステージで作った navigateAroundWall関数がそのまま使えます。
宝石を取るまで右手法で進む必要があるので、ここでもwhileループを使って繰り返します。whileループを抜けたところで宝石を取ればステージをクリアすることができます。
あとちょっとでクリア。。
クリアしました!!
どっちの手を使う?
このステージは難しそうですね。そうでもないって?
一見難しそうに見えるステージですが、まずは「繰り返し処理するパターン」を見つけましょう。どんな繰り返しパターンが見えてくるでしょうか。
ゴールの宝石までは一本道で進めそうです。しかも、スイッチのマスで向きを右や左へ変える必要がありそうですね。
向きを帰る条件はどうなりますか?
右を向く場合と左を向く場合で考えてみると、
右を向く:正面が壁ではない場合
左を向く:正面が壁の場合
で区別できそうです。
まとめると、切れている(OFF)スイッチのマスに止まったら
1.スイッチを押す
2.正面が壁の場合:左を向く
3.正面が壁でない場合:右を向く
となります。2と3はif/elseで書くことができ、下のようなプログラムになります。
クリアです!!
右に行くか、左に行くか
いよいよ最後のステージです。このステージは8個の宝石を取り、6個の切れているスイッチを入れてあげるとクリアです。最後にONのスイッチも置いてありますが、これを押してはダメです。
右へ行ったり、左へ行ったりしつつ、宝石を回収、スイッチを押しながら進めます。
宝石に出くわしたら正面は壁なので右へ進め、スイッチに遭遇したらこっちもやっぱり正面は壁なので左へ向きを変えて進めばよさそうです。
これをifで書いてみたプログラムが下のmoveAndTurn関数です。やっているのはシンプルで行き止まりかつ左が壁なら右を向き、行き止まりかつ右が壁なら左を向く。というだけです。
ONスイッチをゴールの目標にして進みましょう。こういう場合はwhileループが便利です。「ONスイッチのマスに止まらない間」という条件でwhileループを繰り返します。
ループの中では、moveAndTurn関数で1歩進むごとに突き当りかどうかを調べ向きを変えます。関数から戻ってきたあと、宝石のマスなら宝石を取り、切れているスイッチのマスならスイッチを押すという処理を書いています。
クリアしました。
コーディングの達人になったぞ!と叫んでよいそうなので、叫びましょう。
コーディングの達人になったぞぉぉぉぉx!
これでコードを学ぼう1のステージはすべてクリアしました。
次はコードを学ぼう2へ進みます。