3

I am comparing values in a GKNoise field and then setting tiles into a tileMap based on the level of noise

This if-statement is comparing the values by rounding up to the nearest tenth, is there a better way to write it?

if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -1.0 {
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.9 {
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.8 {
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.7 {
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.6 {
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.5 {
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.4 {
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.3 {
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.2 {
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == -0.1 {
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.0 {
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.1 {
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.2 {
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.3 {
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.4 {
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.5 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.6 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.7 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.8 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 0.9 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}
if round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) == 1.0 {
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
}

It seems a little drawn out and not very efficient.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
E. Huckabee
  • 1,788
  • 1
  • 13
  • 29
  • I don't have knowledge of GKNoise, but have you tried to do it with struct? – Apogee Nov 16 '17 at 12:08
  • its a simple comparison if-statement and I was just wondering if there was a better way to do this. – E. Huckabee Nov 16 '17 at 12:12
  • Are you trying to refactor the if statements to have a more compact code or are you trying to refactor `round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows))))` ? In other words, *in fine*, is your question related to GKNoise or not ? – standousset Nov 16 '17 at 12:12
  • my question is not related to GKNoise at all i just want to know if there is a more effective way to compare a double to another double – E. Huckabee Nov 16 '17 at 12:13
  • 1
    Of course `round(...)` can never be equal to -0.9, -0.8, ... 0.9 – Martin R Nov 16 '17 at 12:24
  • `round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)) / 10) * 10)` I left out a crucial mathematical calculation i had in my original code – E. Huckabee Nov 16 '17 at 12:29
  • I think you meant to do `round(MasterNoise.value(atPosition: vector_float2( Float(columns),Float(rows) ) * 10)) / 10` – Knight0fDragon Nov 16 '17 at 15:12

4 Answers4

5

One relatively simple improvement is to compute round outside the conditional, use a variable to store the decision of which title group to use, and convert the chain to if-then-else. This would let you use <= and => in place of ==:

let rounded = round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows))))
var tileGroup : SKTileGroup = nil
if rounded <= -0.6 {
    tileGroup = titleGroup4
} else if rounded <= -0.1 {
    tileGroup = titleGroup3
} else if rounded <= 0.4 {
    tileGroup = titleGroup2
} else if rounded <= 1.0 {
    tileGroup = titleGroup1
}
tileMap.setTileGroup(tileGroup, forColumn: columns, row: rows)
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
5

Your could use a switch and interval matching

switch round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) {
case -1.0...(-0.6):
    tileMap.setTileGroup(tileGroup4, forColumn: columns, row: rows)
case -0.5...(-0.1):
    tileMap.setTileGroup(tileGroup3, forColumn: columns, row: rows)
case 0.0...0.4:
    tileMap.setTileGroup(tileGroup2, forColumn: columns, row: rows)
case 0.5...1.0:
    tileMap.setTileGroup(tileGroup1, forColumn: columns, row: rows)
default:
    break
}
jeanggi90
  • 741
  • 9
  • 24
4

My answer goes a bit further than your question, however I personally feel this code would help clean up your code the best.

You can group if statements (from the looks of your code) like this:

let noise = round(MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows))))
let tileGroup1Array = [1.0, 0.9, 0.8, 0.7, 0.6, 0.5]
let tileGroup2Array = [0.4, 0.3, 0.2, 0.1, 0.0]
let tileGroup3Array = [-0.1, -0.2, -0.3, -0.4, -0.5]
let tileGroup4Array = [-0.6, -0.7, -0.8, -0.9, -1.0]

Then you can check:

if(tileGroup1Array.contains(noise)) { ... } else if(tileGroup2Array.contains(noise){ ... })
jbehrens94
  • 2,356
  • 6
  • 31
  • 59
  • the tileGroups are declared `tileGroup1 = SKTileGroup(tileDefinition: stone1)` – E. Huckabee Nov 16 '17 at 12:16
  • Ah, nice catch! You could name the variables anything descriptive and clear to complete it. – jbehrens94 Nov 16 '17 at 12:17
  • thank you very much for your answer but the switch statements give me the most flexibility so i might go with those – E. Huckabee Nov 16 '17 at 12:19
  • 1
    I don't feel that's true per sé, but hey, whatever floats your boat :) I'm giving my answer because I think it does more right to Swift and the array methods, it's much more readable when you glance at this solution than having to figure out the switch statement. – jbehrens94 Nov 16 '17 at 12:20
  • You might want to change `if tileGroup1Array.contains(noise)` to `if tileGroup1Array.contains(Double(noise))` as the if-statement is expecting a double in the arguement P.S. I went with your answer as it is the best and most flexible answer – E. Huckabee Nov 16 '17 at 12:26
  • Good idea, when I tested my code, I actually used `let noise = 0.3` instead of the type in your post. :) Thanks for marking my answer as your answer! – jbehrens94 Nov 16 '17 at 12:28
  • 1
    your welcome! thank you for providing an answer so quickly – E. Huckabee Nov 16 '17 at 12:29
  • 3
    This is error-prone because 0.1, 0.2, ... are not represented exactly as Float/Double (compare https://stackoverflow.com/q/588004). Better compute `round(10 * value)` and compare against 1, 2, ... – Martin R Nov 16 '17 at 12:32
  • That's not really an issue with my answer, I feel, but more of a suggestion in general to the TS. – jbehrens94 Nov 16 '17 at 12:54
  • This won't work, round would yield 1, 0. or -1, which means all the answers and the question is wrong unfortunately. – Knight0fDragon Nov 16 '17 at 15:10
  • @Knight0fDragon My comment above yours already specifies that. – jbehrens94 Nov 16 '17 at 15:53
  • @Knight0fDragon And to add to my last comment here, the TS already mentions this in the comments beneath the question. – jbehrens94 Nov 16 '17 at 15:55
  • @jbehrens94, The comment was hidden in the question, I upvoted MartinR's comment so that it is no longer hidden, as for your comment above mine.... no it does not, the comment above mine addresses a different issue entirely. You can't compare 0.1 to 0.1 with floats because the the values behind it may not be 0.1, it may be 0.1000000001 on the left and 0.0999999999 on the right (Not exact values just an easy understanding of what can happen with a decimal value in a float) – Knight0fDragon Nov 16 '17 at 16:00
  • Then you are right, @Knight0fDragon! Excuse me :) Please do feel free to edit my answer, because I'm about to go home from work ;) – jbehrens94 Nov 16 '17 at 16:02
1

Just for fun:

No if / switch statement needed at all

let noise = MasterNoise.value(atPosition: vector_float2(Float(columns),Float(rows)))) + 1
let index = Int(round(noise * 10)) / 5
let tileGroup = [tileGroup4,tileGroup3,tileGroup2,tileGroup1,tileGroup1]
tileMap.setTileGroup(tileGroup[index], forColumn: columns, row: rows)
Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44