

Swift playground で学び直しをしております。  
「コードを学ぼう3」のタイトルの課題に行き詰まり、  
ネットで回答を知りましたが、なぜこれで正解になるのかがわかりませんでした。  
特に、最後のforループと、内包されているif文が理解できません。

以下のコードを実行すると、画面をタッチした箇所および画面を4つに分割した4象限の  
X軸とy軸対称の位置に動物の画像が現れます。  
（例えば、画面右上をタッチするとパンダの絵が、タッチした箇所・右下・左上・左下の  
4箇所に現れる）指をスライドすると次々に違う動物が現れ、万華鏡のような効果となります。

最後のforループと、内包されているif文につきまして、  
Forループの意味は「右上・右下・左上・左下にキャラクターを配置する」ということでしょうか。  
特にif文の示す意味が理解できないのですが、  
`Scene.place()`内の`Graphics[i]`の`i`とは`for i in`や`if
i`の`i`と同じものを指しているのでしょうか？だとすると、動物キャラクター数列の0番目から3番目までを4回表示する  
だけでは？と思ってしまうのですが、、、。  
また、ためしに`graphics[i]`の[]内を全部[2]や[1]にすると、画面のどこをタッチしても、  
動物キャラクターが左下に集まってしまいます。なぜこうなるのでしょうか？

[code]

    let animals = [ imageLiteral(resourceName: "horse@2x.png"),  imageLiteral(resourceName: "elephant@2x.png"),  imageLiteral(resourceName: "panda@2x.png"),  imageLiteral(resourceName: "pig@2x.png"),  imageLiteral(resourceName: "frog@2x.png"),  imageLiteral(resourceName: "snail@2x.png")]
    
    var lastPlacePosition = Point(x: 0, y: 0)
    
    func addImage(touch: Touch) {
    
        // Space out the graphics.
        let placeDistance = touch.position.distance(from: lastPlacePosition)
        if placeDistance < /*#-editable-code*/80/*#-end-editable-code*/ { return }
        lastPlacePosition = touch.position
    
        // カラの数列graphicsを作る
        var graphics: [Graphic] = []
    
        // animals数列から動物をランダムにピックアップ
        let chosenImage = animals.randomItem
    
        // ピックアップした動物をgraphics数列に3つ入れる
        for i in 0 ..< 4 {
            let graphic = Graphic(image: chosenImage)
            graphics.append(graphic)
        }
    
        // 画面をタッチした絶対座標を求める
        let x = abs(touch.position.x)
        let y = abs(touch.position.y)
    
        // 右上・右下・左上・左下の座標を決める
        let position1 = Point(x: x, y: y)
        let position2 = Point(x: -x, y: y)
        let position3 = Point(x: x, y: -y)
        let position4 = Point(x: -x, y: -y)
    
        //このforループの意味がわからない
        for i in 0 ..< 4 {
            if i == 0 {
                scene.place(graphics[i], at: position1)
            } else if i == 1 {
                scene.place(graphics[i], at: position2)
            } else if i == 2 {
                scene.place(graphics[i], at: position3)
            } else if i == 3 {
                scene.place(graphics[i], at: position4)
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2019-04-27T10:17:00.913
54520
2019-04-27T14:02:52.140
2019-04-27T14:02:52.140
27795
24718
question
swift
Swift playground 課題「対称な星」の回答について


**_だとすると、動物キャラクター数列の0番目から3番目までを4回表示する  
だけでは？と思ってしまうのですが、、、。_**

その通りですね。(ただ「0番目から3番目までを4回表示する」と言うと「各4回」の意味に取られかねませんから「0番目から3番目までをそれぞれ1回表示する」とかなんとか、誤解の余地のない表現にした方が良いでしょう。それと「数列」ではなく「配列」ですね。)

ご掲載のコード(ネットで見つけたコードを転載する場合、転載元のリンクを記載された方が良いでしょう)の最後の部分、無理して`for`文を使う意味がないですね。

私なら、`// 右上・右下・左上・左下の座標を決める`以下の部分はこう書くでしょう。

[code]

    scene.place(graphics[0], at: Point(x: x, y: y))
    scene.place(graphics[1], at: Point(x: -x, y: y))
    scene.place(graphics[2], at: Point(x: x, y: -y))
    scene.place(graphics[3], at: Point(x: -x, y: -y))
    
[/code]

ただ、

> Forループの意味は「右上・右下・左上・左下にキャラクターを配置する」ということでしょうか。 特にif文の示す意味が理解できないのですが、  
>  Scene.place()内のGraphics[i]のiとは、「for i in」や「if i」のiと同じものを指しているのでしょうか？

何てことを疑問に思うようでは、まだ基本がきちんと理解できていないように思います。理解がおぼろげなままで変なコードを見つけてしまったので、その辺りが露呈してしまったと言うところでしょうか。十分理解されておられれば、「このコードは変なことをしている」と言うのがすぐに分かったはずです。

* * *

著者としては、直前に`for`文を使う練習があったので、ここでも「`for`文を使わないといけない」と言う思い込みがあったのでしょうが、無理に`for`文を使っておいて、その中の`if`文で1回1回を場合分けすることで、かえって複雑なコードにしてしまっているので、本末転倒というか無駄を面倒で上書きしているという感じです。

どうしても`for`文を使いたければ、例えばこうするのはありかもしれません。

[code]

    let positions = [
        Point(x: x, y: y),
        Point(x: -x, y: y),
        Point(x: x, y: -y),
        Point(x: -x, y: -y)
    ]
    
    for i in 0 ..< 4 {
        scene.place(graphics[i], at: positions[i])
    }
    
[/code]

* * *

**_ためしにgraphics[i]の[]内を全部[2]や[1]にすると、画面のどこをタッチしても、  
動物キャラクターが左下に集まってしまいます。なぜこうなるのでしょうか？_**

「集まってしまう」と言うのは、指を動かして`addImage(touch:)`が何度も呼ばれるとそう感じるのでしょうが、指を動かさずにすぐ離して`addImage(touch:)`が1回だけ呼ばれるようにして、動作の違いを確かめると良いでしょう。

[code]

    scene.place(graphics[2], at: position1) //`graphics[2]`が`position1`(右上)に置かれる
    scene.place(graphics[2], at: position2) //`graphics[2]`が`position2`(左上)に移動する
    scene.place(graphics[2], at: position3) //`graphics[2]`が`position3`(右下)に移動する
    scene.place(graphics[2], at: position4) //`graphics[2]`が`position4`(左下)に移動する
    
[/code]

これは`Graphic`というクラスがどんな動作をするように設計されているのかによるのですが、`place(_:at:)`と言うメソッドは、スタンプのように画面上にポンポンと画像のコピーを置くのではなく、ビデオゲームのキャラクタのように1度に2箇所には存在できないようになっています。つまり全く同じインスタンスに`place(_:at:)`を続けて呼ぶと、画面に映される暇もなく、最後の位置に移動してしまうのです。

指を動かす間に`addImage(touch:)`は何度も呼ばれることになり、一度呼ばれるたびに`Graphic`の新しいインスタンスを作るので、前回の`addImage(touch:)`で置かれたものが移動することはありません。

この辺りはクラスとインスタンスの関係が十分理解できていないとわかりにくいかもしれません。

* * *

手元のSwift
Playgroundsで該当の課題を実行したところ「このページは作成ページなので回答というものありません」と言う意味の表示が出ました。あなたが見つけられたコードも唯一無二の正解というわけではありません。

ネット上で見つかる情報には、間違っているもの・必ずしもベストとは言えないものがあること、そう言ったものが検索の上位にくることもあること、なんかを改めて認識するには良い機会だったでしょう。


CC BY-SA 4.0
2019-04-27T13:39:42.590
54526
2019-04-27T13:39:42.590
13972
54520
answer