2

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
...
Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160

2 Answers2

1

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]
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Wouldn't it be more useful to add this as an answer to the duplicate question you undid? – TigerhawkT3 Nov 23 '16 at 21:56
  • Sorry, I didn't mean to do that; but now I can't find the dupe you used... – Daniel Roseman Nov 23 '16 at 21:57
  • You can find it in the list of linked questions in the sidebar to the right (above "Related"), or in [this question's revisions page](http://stackoverflow.com/posts/40774655/revisions). – TigerhawkT3 Nov 23 '16 at 22:00
0

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
Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • here's my next question: our rank system doesn't have a peak points balance; it tops out in rank at Commander, but Commander is actually set at `Commander <= 42,000`. So does that effect the exception handler that you set in that last bit of code? – PhoenixDeFalco Nov 24 '16 at 13:51
  • @PhoenixDeFalco you can do whatever you like in the `except` clause; I've updated my answer to return the highest rank rather than raise an exception. – Zero Piraeus Nov 24 '16 at 17:27
  • i tried your code that you typed, and i get: `Traceback (most recent call last): File "", line 2, in print("%5d %s" % (n, get_rank(n))) NameError: name 'get_rank' is not defined` how do i fix this? – PhoenixDeFalco Nov 25 '16 at 00:54
  • 1
    You need to define the function! Paste the complete block starting 'from bisect import bisect_right ...` into your interpreter. Learning to read tracebacks is an important skill: `name 'get_rank' is not defined` means that you didn't define `get_rank`, so obviously it won't be able to run. – Zero Piraeus Nov 25 '16 at 01:02
  • sorry...thank you for the help, and I will try my best to figure it out...thanks again! Happy thanksgiving! – PhoenixDeFalco Nov 25 '16 at 01:05
  • okay, sorry about this, but i got another traceback, but this one i don't understand at all... `'tuple' object is not callable` I tried to google this, but I really don't understand anything that I found...Could I get one last bit of help on this? – PhoenixDeFalco Nov 25 '16 at 01:13
  • That can only happen if you've redefined something that should be a function to be a tuple instead; maybe you typed `get_rank = `? SO comments are really not good for debugging, but: 1. Exit your Python interpreter and start it again. 2. Copy and paste **exactly** the whole of the first code block above, from `from bisect ...` to `... return RANKS[-1][1]` inclusive. 3. Try typing `get_rank(1234)` and a few other numbers. The second `for n in ...` code block is only meant as a usage example; if you're still having trouble after 1-3, I'm afraid you need to find a Python tutorial. – Zero Piraeus Nov 25 '16 at 01:25