前ステージの応用編です。allCoordinatesに全マスの座標を入れておき、ある条件に沿うものを配列Aに.append()、そうでないものを配列Bに.append()して、最後に配列Aと配列Bそれぞれについて異なる処理をします。
異なる処理というのは、「陸地ブロックを積む」と「海にする」なので、それぞれ、islandArrayとseaArrayという名前にしてみます。いいかげんcoordinate、coordinates、Coordinateなど似たようなのが入り乱れててわかりづいらいですよね。ので、配列には「Array」とつけてみました。配列を空の状態でつくる時は、将来的にどんな型のオブジェクトが入るかあらかじめ宣言しておく必要があります。今回はどちらもCoordinate型です(4,5行目)。
7行目からのfor〜inループは基本的に前ステージと同じです。Coordinate型オブジェクトcoordinateのメンバー変数であるcolumnとrowをチェックしてある範囲のものだったらislandArrayに追加。そして今回elseブロックでそれ以外の時はseaArrayに入れて行きます。これで全てのコマはislandArrayかseaArrayのどちらかに別れてコピーされたことになります。ちなみに、islandとは島(アイランド)の意味であって、isで始まるからといってBool型を意味してるわけではないです。
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 |
let allCoordinates = world.allPossibleCoordinates // Create two empty arrays of type [Coordinate]. // ([Coordinate]型の空の配列を2つ作る) var islandArray:[Coordinate] = [] var seaArray:[Coordinate] = [] for coordinate in allCoordinates { if (coordinate.column>3 && coordinate.column<8 && coordinate.row>3 && coordinate.row<8) { // Append to island array. // (陸地の配列に追加) islandArray.append(coordinate) } else { // Append to sea array. // (海の配列に追加) seaArray.append(coordinate) } } // For your island array, place blocks. // (陸地の配列の位置にブロックを配置) for island in islandArray { world.place(Block(), at: island) } // For your sea array, place water. // (海の配列の位置に水を配置) for sea in seaArray { world.removeAllBlocks(at: sea) //一旦陸地を取り除き、 world.place(Water(), at: sea) //水を配置 } |
このステージでも実行結果を写真で載せておきます。真ん中に4×4マスの島ができ、後の陸地は全て海に変化してれば正常です。
coordinate、coordinates、Coordinateの区別
上の方で書いた似たような名前の見分け方について触れておきます。これはコードを書く人の好き好きで決められる部分でもあるので必ずではないのですが、一般的にこういうルールで使い分けてる人が多いですよ、という話です。逆にいえばこういうルールで書いておけば誰か他の人がみても理解しやすいでしょう、ということでもあります。
まず最初が大文字になっているものは、一般に型(クラス)を意味しています。実際のプログラミングでは型自体を自分で用意することもありますが、当面Swift Playgroundsの中では最初から用意されているなんらかの型を指していると考えて良いでしょう。
次に、同じ名前でcoordinateと小文字で書いたものは、大文字の型から作られたインスタンスであることが多いです。letやvarでTaiyaki型から作った1つのたい焼きがtaiyakiです。ひとつだけ作る場合はそれでいいですが、複数個の場合はtaiyaki1とtaiyaki2としたりもするかも知れません。
そして複数形coordinatesとなっていたら、Coodinate型のオブジェクトが複数入った配列であると考えられます。配列は中身が複数入るので複数形なのです。わかりやすいでしょ?たくさんあったらtaiyaki
[0]、taiyaki[1]というように[]内の通し番号で呼び分けます。
そしてfor〜in文でループする時は、
1 2 3 |
for taiyaki in taiyakis { taiyaki.an = "ogura" } |
のように、「for 単数形 in 複数形 {}」とし、ループの中では単数形を使う形にするのが直観的でしょう。
例えばwatersみたいに「実際の英語では単複同形なのでsつけるのおかしくね?」というような場合もありますが、まぁあんまり英語としての正しさは二の次で、「配列ならs」をつけるというルールにしてしまった方がわかりやすかったりします。どうしても気持ち悪ければ上の例のように「Array(=配列)」をつけるとか自分で独自のルールを決めても良いと思います。
for
bbb in sea {
world.removeBlock(at: bbb)
//world.removeItems(at: bbb)
world.place(Water(), at: bbb)
}
何故かremoveItemsが動かないのでremoveBlockを使って解決しました。
iPadpro10.5 iOS11.0.3にて実行しています。
// (海の配列の位置に水を配置)
for sea in seaArray {
world.removeItems(at: sea) //一旦陸地を取り除き、
world.place(Water(), at: sea) //水を配置
}
—————————————————————
world.removeAllBlocks(at: sea) これに変更して海ができました。
いつも利用させていただき、大変感謝致しております。
27 world.removeItems(at: sea) //一旦陸地を取り除き は、
27 world.removeBlock(at: sea) //一旦陸地を取り除き
ではないでしょうか。
27行目は
removeAllBlocks
にするとクリアになりました。
(removeItemsだとクリアになりませんでした。)
world.removeItems
の部分がうまくいかず
world.removeAllBlocks
にしたらうまくいきました。
皆さん、コメントありがとうございます。
しばらく放置してありお返事、反映が遅くなりましてすみませんでした。
本コンテンツはSwift3.1版を元に作成しておりましたが、今は4.2版になっており、一部コードは互換性がなくなっているようですね。
とりあえずご指摘のremoveAllBlocksに更新させていただきました。
非常にわかりやすい解説ありがとうございます
Playgrounds内の説明だけではわからないこともここの解説を見て理解できました
ありがとうございます