Reputation: 1999
I'm learning Swift and tried to program the game "Bullseye" from Ryan Wenderlich by my own before watching the videos.
I needed to give the user points depending on how close to the target number he was. I tried to calculate the difference and than check the range and give the user the points, This is what I did with If-else (Couldn't do it with switch case):
private func calculateUserScore() -> Int {
let diff = abs(randomNumber - Int(bullsEyeSlider.value))
if diff == 0 {
return PointsAward.bullseye.rawValue
} else if diff < 10 {
return PointsAward.almostBullseye.rawValue
} else if diff < 30 {
return PointsAward.close.rawValue
}
return 0 // User is not getting points.
}
Is there a way to do it more elegantly or with Switch-Case?
I couldn't just do diff == 0
for example in the case in switch case as xCode give me an error message.
Upvotes: 43
Views: 38019
Reputation: 1145
In case that you need to check if a value is bigger than any number or between 2 values use it is possible to use where
instead of if
looks a bit cleaner this will work
func isOutdated(days: Int) -> Outdated {
var outdatedStatus = Outdated.none
switch days {
case _ where days < 5:
outdatedStatus = .tooLow
case 5...10:
outdatedStatus = .low
case 11...20:
outdatedStatus = .high
case _ where days > 20:
outdatedStatus = .expired
default:
outdatedStatus = .none
}
return outdatedStatus
}
After the release of the new capabilities of Swift 5.9 this could be changed to something simpler:
func isOutdated(days: Int) -> Outdated {
switch days {
case _ where days < 5:
.tooLow
case 5...10:
.low
case 11...20:
.high
case _ where days > 20:
.expired
default:
.none
}
}
Upvotes: 17
Reputation: 2336
You can return the values you want accordingly:
switch diff {
case 0:
print("Bull Eye")
case 1..<10:
print("Almost Bull Eye")
case 10..<30:
print("Close")
default:
print("Too Far")
}
Upvotes: 9
Reputation: 171
In my case the compiler took CGFloat as a closed range of double, so I had to explicitly tell compiler that I am checking CGFloat range.
var progress: CGFloat!
switch CGFloat(progress) {
case 0 ... 0.25:
barColor = .red
case 0.25 ... 0.5:
barColor = .yellow
default:
break
}
Upvotes: 1
Reputation: 11242
This should work.
private func calculateUserScore() -> Int {
let diff = abs(randomNumber - Int(bullsEyeSlider.value))
switch diff {
case 0:
return PointsAward.bullseye.rawValue
case 1..<10:
return PointsAward.almostBullseye.rawValue
case 10..<30:
return PointsAward.close.rawValue
default:
return 0
}
}
It's there in the The Swift Programming Language book under Control Flow -> Interval Matching.
Upvotes: 82
Reputation: 5679
You have to use range-operators as case in switch-statement:
a...b
// It have range from a to b, means b is included as well
a..<b
// It have range from a to b-1, means b is not included
private func calculateUserScore() -> Int {
let diff = abs(randomNumber - Int(bullsEyeSlider.value))
switch diff {
case 0: return PointsAward.bullseye.rawValue
case 1..<10: return PointsAward.almostBullseye.rawValue
case 10..<30: return PointsAward.close.rawValue
default: return 0
}
}
Upvotes: 4
Reputation: 266
Only for you:
enum PointsAward: Int {
case close
case almostBullseye
case bullseye
}
private func calculateUserStory() -> Int {
let bullsEyeSliderValue = 9
let randomNumber = 100
let diff = abs(randomNumber - Int(bullsEyeSliderValue))
switch diff {
case 0:
return PointsAward.bullseye.rawValue
case 0..<10:
return PointsAward.almostBullseye.rawValue
case 0..<30:
return PointsAward.close.rawValue
default: return 0
}
}
Upvotes: 7