PhoenixDeFalco
PhoenixDeFalco

Reputation: 25

Look up a string based on a number in a range

I'm trying to create a rank system for my gaming group, similar in nature to Supercell's Trophy System in their Clash of Clans and Clash Royale games for android/iOS systems.

I have the layout of the ranks all figured out, and we already have a point system in place that works ... I just need to now program in the actual ranks.

The ranks work very simply: The individual's point balance falls within specific values, and the rank corresponding to that value is the person's rank. I created a simple table to show what I mean ... here's an excerpt of what it looks like:

Rank: Balance Range
Private: 0-500
Private I: 501-1000
Private II: 1001-1500
Private III: 1501-2500
Corporal: 2501-3000
...

So here's the simple rank system layout, it goes all the way up to Commander at 42,000 points. My question is this: How do I associate the Rank with the point value, without having to type out all the lines of code like this?

0 <= Private <= 500
501 <= PrivateI <= 1000
...

Upvotes: 2

Views: 137

Answers (2)

schesis
schesis

Reputation: 59168

A slight improvement to Daniel Roseman's bisect solution to would be to use a single list of 2-tuples:

from bisect import bisect_right

RANKS = [
    # max balance, rank
    (500, 'Private'),
    (1000, 'Private I'),
    (1500, 'Private II'),
    (2500, 'Private III'),
    (3000, 'Corporal'),
    # ...
    (42000, 'Commander')
]

def get_rank(balance):
    index = bisect_right(RANKS, (balance, ''))
    try:
        return RANKS[index][1]
    except IndexError:
        return RANKS[-1][1]

The advantages here are that it's easier to read at a glance, and less prone to mistakes when editing your code to introduce new ranks, tweak limits, etc.

It also returns the highest rank when supplied a points balance higher than any accounted for in RANKS (as specified in your comment), rather than raising an exception.

Example:

>>> for n in range(0,42001,500):
...     print("%5d  %s" % (n, get_rank(n)))
...     print("%5d  %s" % (n + 1, get_rank(n + 1)))
... 
    0  Private
    1  Private
  500  Private
  501  Private I
 1000  Private I
 1001  Private II
 1500  Private II
 1501  Private III
 2000  Private III
 2001  Private III
 2500  Private III
 2501  Corporal
 3000  Corporal
 # ...
 42000  Commander
 42001  Commander

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599796

You can use bisect for this.

from bisect import bisect
def get_rank(score):
    points = [500, 1000, 1500, 2500, 3000]
    ranks = ["Private", "Private I", "Private II", "Private III", "Corporal"]
    div = bisect(points, score)
    return ranks[div]

Upvotes: 1

Related Questions