1

I have a Player class that stores a rating property of type Int:

class Player {
    typealias Rating: Int
    var rating: Rating = 0
}

I then have various Range instances that specify the level that a given player is at:

private let level1Range = 0 ..< 100
private let level2Range = 100 ..< 500

I can then switch on the player rating property to obtain the level that the player is at:

switch rating {
case level1Range:
    print("On Level 1")
case level2Range:
    print("On Level 2")
default:
    break
} 

I want to be able to say what the next level is and how far away the player is from that next level.

I'm not sure of the best way to go out this problem. I started by making an array:

private var ratingRanges: [Range] {
    return [level1Range, level2Range]
}

But I get the error:

Reference to generic type 'Range' requires arguments in <...> Insert '<<#Bound: Comparable#>>'

If this worked, I guess I could then find the first non-zero value:

ratingRanges.first(where: { $0.min() - self.rating > 0 })

in order to locate the next range.

Or is there a more efficient method to achieve this?

Thanks for any help

3 Answers 3

3

You need to provide the generic placeholder type of the Range:

private var ratingRanges: [Range<Rating>] {
    return [level1Range, level2Range]
}

Or simpler, with automatic type inference, as a (lazy) stored property:

private lazy var ratingRanges = [level1Range, level2Range]

Determining the next range can then be done as

func nextRange() -> Range<Rating>? {
    return ratingRanges.first(where: { $0.lowerBound > rating})
}
Sign up to request clarification or add additional context in comments.

Comments

1

My solution is to create Level enum:

    enum Level: Int {
    case level1 = 1
    case level2

    init?(rating: Int) {
        switch rating {
        case Level.level1.range:
            self = .level1
        case Level.level2.range:
            self = .level2
        default:
            return nil
        }
    }

    var range: CountableRange<Int> {
        switch self {
        case .level1:
            return level1Range
        case .level2:
            return level2Range
        }
    }
}

And then all you need to do is to add following methods to your Player class:

func nextLevel() -> Level? {
    guard let currentLevel = Level(rating: rating) else {
        return nil
    }
    guard let nextLevel = Level(rawValue: currentLevel.rawValue + 1) else {
        return nil
    }
    return nextLevel
}

func distanceTo(level: Level) -> Int {
    let levelLowerBound = level.range.lowerBound
    return levelLowerBound - rating
}

1 Comment

Thanks for this suggestion, it does look a little more involved than the accepted answer though.
0

May you should to keep the maximum value of range only. For example, instead of

private let level1Range = 0 ..< 100
private let level2Range = 100 ..< 500

you can use

private let level1MaxRating = 100
private let level2MaxRating = 500

and compare with

switch rating {
case 0...level1MaxRating:
    print("level 1")
case (level1MaxRating+1)...level2MaxRating:
    print("level 2")
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.