一見すると4カ所の隙間をふさいで長方形のステージにしてしまえば、あとは規定宝石数集めるまでグルグルまわればいい気がしますが、ワープがあるのでそうもいきません。
私は2箇所だけつないで、4ブロックが真っ直ぐ並ぶ島が4つ、という状態にしました。実はこれでワープを通ると長い一本道と同じことになるのです。あとは、そこをひたすら往復して宝石を集めていけばいつか必要数集めて終わることができます。つまりポイントは、「行き止まりになったら振り返る」「宝石があったら取る」「規定数宝石を集めるまで繰り返す」ということになります。
なお、集めなければならない宝石の数totalGemsはコードを実行する度に変化します。不完全なコードでも、totalGemsがたまたま2とか少ない数だと上手くクリアできてしいまう場合があります。何度か実行してどんな数になってもクリアできることを確認しましょう(その時々の集めないといけない数は実行した時に空の左上のところに出ます)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
let totalGems = tandomNumberOfGems //集める宝石の数 //キャラクターを作成して配置 let ch = Character() world.place(ch, facing: south, atColumn: 0, row: 1) //取った宝石を数えるカウント用変数 var getGem = 0 //2カ所にブロックを置く world.place(Block(), atColumn: 0, row: 2) world.place(Block(), atColumn: 3, row: 3) //ここから本編 //集めた宝石の数getGemが、所定の数totalGemsより少ない限り繰り返す while getGem < totalGems { //宝石があったらゲット(カウント変数で数える) if ch.isOnGem { ch.collectGem() getGem += 1 } //行き止まりなら更に3つのケースに分岐して方向転換処理 if ch.isBlocked { //左右とも行き止まりの時は振り返る if ch.isBlockedRight && ch.isBlockedLeft { ch.turnRight() ch.turnRight() //右または左のみが行き止まりの時(ワープを出た時用)は横を向く } else if ch.isBlockedRight { ch.turnLeft() } else { ch.turnRight() } } //方向転換処理が済んだら、または必要ない時は前進 ch.moveForward() } |
ちなみにワープポータルの上にブロック置いて塞いでやれば冒頭に書いたように大きな長方形ステージにできるんじゃないかと思ったんですが、どうもワープポータルは積み上がったブロックの上に出現してしまうようですね。
また最初からあるワープポータルは呼び名がわからないので、.isActive = falseでオフにすることもできなそうです。
方向転換処理のところは、
1 2 3 4 5 6 7 8 9 10 |
//左右とも行き止まりの時は振り返る if ch.isBlocked && ch.isBlockedRight && ch.isBlockedLeft { ch.turnRight() ch.turnRight() //右または左のみが行き止まりの時(ワープを出た時用)は横を向く } else if ch.isBlocked && ch.isBlockedRight { ch.turnLeft() } else if ch.isBlocked && ch.isBlockedLeft { ch.turnRight() } |
とも書けるでしょう。ただし3つのif全てに isBlocked & がついているので、これを外側の大きなif文として囲ってネストにしています。こうすると、個々のif文の条件式が1項減って見やすくなる気がしませんか?また、今回は正面だけが行き止まりというパターンはないので、外側のif文で正面が行き止まり(isBlocked)を条件とした後、残る可能性は「両側行き止まり」「右が行き止まり」「左が行き止まり」だけになります。なので、最後はelse ifにする必要もなく、32行目はただのelseで済ますことができます。