简体   繁体   中英

iOS Swift: Array of Range

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

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})
}

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
}

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")
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM