型 1.ワープをオフにする

この節から「ドット表記」という考え方が登場。Aというインスタンス(物体やキャラクターの個体)のBというプロパティ(性質や状態を表す枠)をCという値にする、という指示を

みたいに書きます。この時「.(ドット)」は助詞の「の」みたいなニュアンスです。.がいつでもこういう意味をもつわけではないですが、うしろに「=(イコール)」があって何かを代入してるっぽかったらそういうことだと思えば良いでしょう。
解説文に出ている例の

はgreenPortalというインスタンスの、isActive(オンかどうか)というプロパティをtrue(オン)にするという意味ですね。「isナンチャラ」はこれまでisOnGemなどがそうだったようにtrue(真)かfalse(偽)のどちらかの値しか許されないことを示しています。中には、

みたいにtrue/false以外の値を入れたり取り出したりできる場合もあります。あるインスタンスがどんなプロパティ枠をもっていて、そこのどんな種類の値を出し入れできるかは、インスタンスの元となっている設計図であらかじめ決まっています。同じ設計図から作られたインスタンスなら同じプロパティを扱えます。逆に、

とかやってもエラーになるでしょう。宝石にはisActiveというプロパティがそもそもないからです。この辺りは先々でまた出てくると思いますが、現状知っておくといいのは、.を入力した後の予測変換で思った候補が出て来ない時は、そもそもそのインスタンスに対しては思っているプロパティを使えない→違うインスタンスを選んでたり、綴りを間違っていないかチェックしてみる、ということです。

余談が長くなりましたが、このステージの正解例です。
最初にドット表記でgreenPortalをオフにできれば、あとはそう難しいステージではないと思います。
連続で散歩進む場面がとても多いので、funcを使ってmove3()という関数を作って見ました。そして「真ん中のワープゾーンを基点に先端まで行ってスイッチを入れて戻って来て横を向く」を1まとまりにしてforで繰り返しています。これをfuncにするのももちろんアリです。

変数8. 決まった数だけ集める

プログラム冒頭でrandomNumberOfGemsというところで宝石回収ノルマ数が決められ、変数totalGemsにセットされます。そこはそういうものだと割りきって、ともかくtotalGems個だけ宝石を集めるまで繰り返すループを組みます。
例によってナビゲーション処理と宝石処理をわけて考えます。宝石処理はいつも通り、isOnGemなら回収してカウンターに1を追加するだけです。
ナビゲーションですが、今回は右に曲がる場合、左に曲がる場合、そして振り返る場合があります。ワープゾーンを加味して考えるとこのステージは1本道で、規定の宝石を集めるまでずっと行ったり来たりを繰り返すわけです。
まずいずれの場合にせよ前方が行き止まっている場合になるので、一番外側にisBlockedを条件に置きます。これで後のここのif文に「&& isBlocked」を書く手間が省け、コードがスッキリします。さらにコースをじっくり観察すると、前方が行き止まりで、かつ、

  • 両側も行き止まりなら振り返る
  • 左が行き止まりなら右へ
  • 右が行き止まりなら左へ

という考え方ができそうです。これをelse文でつなぐと、前条件に漏れた場合だけ判定することになります。例えば最初の2つをもしelseを使わないで、

と書くと、isBlockedLeftかつisBlockedRightだった時には、両方ともtrueになり、turnRightが3回実行されてしまいます。elseを使わないで、それぞれが重複してtrueにならないようにするには、と書きます。これでも正しいのですが、条件式が長くなりがちです。なので、下の正解例ではelseを使って「前の条件に漏れていて、かつ」という形にしています。すると最後はelseだけになっているわけですが、この理由を納得いくまで考えてみてください。

変数7. 決まった数だけスイッチを入れる

ここでもまずナビゲーション処理を先に考えましょう。
開始位置から見て左側が宝石ゾーン、右側がスイッチゾーンです。一件面倒くさそうな配置ですが、ワープゾーンがあるので、右へ右へと曲がっていけば宝石ゾーン→スイッチゾーンを通過できることに気付きます。
そこで、宝石ゾーンとスイッチゾーンで共通となる前進処理をfunc文でgo()という関数にまとめます。内容は「行き止まったら右に曲がりつつ前進」というものです。
続いて、宝石ゾーンの処理です。宝石ゾーンの終わりは厳密には判定できません。宝石の数は不定ですし、一周したとかワープゾーンに載ったなんてことを判定する方法もありません。そこで、「最初に閉スイッチに載った」ら宝石ゾーンは終了として、ループを抜けて次に進むことにしました。
続くスイッチゾーンのwhileループでは、いよいよ取った宝石数とこれから開けていくスイッチ数を比較しながらの繰り返ししなります。この時点でgemCounterはある程度の数字が入っているはずです。一方switchCounterはまだ0で、ループを経て増えていきます。switchCounterの方が少ないうちはループを続け、同じかそれ以上になったらループを抜けます(抜けた後になにもコードがないので、終了となります)。

今回別にgo()関数を作って共通部分をまとめることは要求されていません。ただこのように別々のゾーンの処理の中に同じことをやればいいんだなって気付いた部分があったら、funcで関数にまとめて、それぞれから1行で呼び出せるようにしておくと、コード全体が短く、見通しやすくなります。またその部分に手直しが必要になった時に、1カ所直すだけでそれを呼び出す全ての部分に反映されるので手間が省けるのでオススメです。

変数6. 値が等しいかどうかを調べる

橋をまたいでこっち側とあっち側それぞれ3×3のスペースを見比べ、あちら側の開スイッチの数だけこちら側で宝石を取れという指示です。
開スイッチの数は、最初からnumberOfSwitchesというコマンドが調べてくれることになっており、その結果がswitchCounterに代入されます。ここはそういうものだと思って流してください。これと、自分でカウントした宝石数を比較してループを繰り返します。
こちら側の3×3ゾーンは真ん中には立ち入れず外周を周回していけば、時折宝石が湧いて出るので、それを取っていけばOKです。

変数 5. 3つの宝石と4つのスイッチ

 やることがたくさんあるので頭が混乱しそうですが、以下の三つの作業に分割して考えてみましょう。

  1. 角を適切に曲がりつつ前進
  2. 宝石をみつけたら3つまで取りつつカウント
  3. 閉スイッチを見つけたら4つまで開けつつカウント

 ワープゾーンに惑わされずにコースを眺めると、宝石ゾーンが先、スイッチゾーンが後に続いていることがわかります。そこで、一番外側のループは「閉スイッチ4つを開け終わるまで」として、その繰り返しの中で宝石があれば3つまで取るというアプローチで考えてみます(もちろん他にも方法はあります)。
変数toggleは最初0で段々増えていきますので、「4未満ならば(<4)」という条件式でwhileループを組みます。toggleが3の時はループを実行します。4ならしません。ループを実行中に1増える可能性があるので、もし「4以下ならば」(<=4)にしてしまうと、toggleが4の時にもループが実行され最大で5になってしまう場合があるので、今回は「4未満」が適しています。 ナビゲーション処理としては、右に曲がるべき時と左に曲がるべき時があります。全ての角はどちらか一方にしか曲がれないようなので、isBlockLeftやisBlockRightを活用して反対側に曲がるようにします。また前方が行き止まりであることは共通条件なので、二重ifにして外に出して、

のように書く方法もあります。  宝石処理、スイッチ処理はいままで何度も出てきた通りですが、処理をするのとセットでカウンターに1を足すのを忘れずに。

14行目と15行目、21行目と22行目は、それぞれ二重のif文ですが、&&を使ってまとめることもできます。是非チャレンジしてみてください。