|
| 1 | +# 51fda2d95d6efda45e00004e |
| 2 | +# |
| 3 | +# Write a class called User that is used to calculate the amount that a user |
| 4 | +# will progress through a ranking system similar to the one Codewars uses. |
| 5 | +# |
| 6 | +# Business Rules: |
| 7 | +# |
| 8 | +# A user starts at rank -8 and can progress all the way to 8. |
| 9 | +# There is no 0 (zero) rank. The next rank after -1 is 1. |
| 10 | +# Users will complete activities. These activities also have ranks. |
| 11 | +# Each time the user completes a ranked activity the users rank progress is |
| 12 | +# updated based off of the activity's rank |
| 13 | +# The progress earned from the completed activity is relative to what the |
| 14 | +# user's current rank is compared to the rank of the activity |
| 15 | +# A user's rank progress starts off at zero, each time the progress reaches |
| 16 | +# 100 the user's rank is upgraded to the next level |
| 17 | +# Any remaining progress earned while in the previous rank will be applied |
| 18 | +# towards the next rank's progress (we don't throw any progress away). |
| 19 | +# The exception is if there is no other rank left to progress towards |
| 20 | +# (Once you reach rank 8 there is no more progression). A user cannot progress |
| 21 | +# beyond rank 8. |
| 22 | +# The only acceptable range of rank values is |
| 23 | +# -8,-7,-6,-5,-4,-3,-2,-1,1,2,3,4,5,6,7,8. Any other value should raise an error. |
| 24 | +# The progress is scored like so: |
| 25 | +# |
| 26 | +# Completing an activity that is ranked the same as that of the user's will be |
| 27 | +# worth 3 points |
| 28 | +# Completing an activity that is ranked one ranking lower than the user's will |
| 29 | +# be worth 1 point |
| 30 | +# Any activities completed that are ranking 2 levels or more lower than the |
| 31 | +# user's ranking will be ignored |
| 32 | +# Completing an activity ranked higher than the current user's rank will |
| 33 | +# accelerate the rank progression. The greater the difference between rankings |
| 34 | +# the more the progression will be increased. The formula is 10 * d * d where |
| 35 | +# d equals the difference in ranking between the activity and the user. |
| 36 | +# |
| 37 | +# Logic Examples: |
| 38 | +# If a user ranked -8 completes an activity ranked -7 |
| 39 | +# they will receive 10 progress |
| 40 | +# If a user ranked -8 completes an activity ranked -6 |
| 41 | +# they will receive 40 progress |
| 42 | +# If a user ranked -8 completes an activity ranked -5 |
| 43 | +# they will receive 90 progress |
| 44 | +# If a user ranked -8 completes an activity ranked -4 |
| 45 | +# they will receive 160 progress, resulting in the user being upgraded to |
| 46 | +# rank -7 and having earned 60 progress towards their next rank |
| 47 | +# If a user ranked -1 completes an activity ranked 1 |
| 48 | +# they will receive 10 progress (remember, zero rank is ignored) |
| 49 | +# |
| 50 | +# Code Usage Examples: |
| 51 | +# user = User() |
| 52 | +# user.rank # => -8 |
| 53 | +# user.progress # => 0 |
| 54 | +# user.inc_progress(-7) |
| 55 | +# user.progress # => 10 |
| 56 | +# user.inc_progress(-5) # will add 90 progress |
| 57 | +# user.progress # => 0 # progress is now zero |
| 58 | +# user.rank # => -7 # rank was upgraded to -7 |
| 59 | +# |
| 60 | +# Note: Codewars no longer uses this algorithm for its own ranking system. |
| 61 | +# It uses a pure Math based solution that gives consistent results no matter |
| 62 | +# what order a set of ranked activities are completed at. |
| 63 | + |
| 64 | +from unittest import TestCase |
| 65 | + |
| 66 | +ranks = list(range(-8, 0)) + list(range(1, 9)) |
| 67 | + |
| 68 | +class User: |
| 69 | + |
| 70 | + # Using a getter take abstraction of the no 0 rank rule |
| 71 | + def get_rank(self): |
| 72 | + return ranks[self.rank_index] |
| 73 | + rank = property(get_rank) |
| 74 | + |
| 75 | + def __init__(self): |
| 76 | + self.rank_index = 0 |
| 77 | + self.progress = 0 |
| 78 | + |
| 79 | + def get_progress_points(self, new_rank_index): |
| 80 | + rank_diff = new_rank_index - self.rank_index |
| 81 | + print("rank_diff: {}, new_index: {}, current_index: {}".format(rank_diff, new_rank_index, self.rank_index)) |
| 82 | + if rank_diff <= -2: |
| 83 | + return 0 |
| 84 | + elif rank_diff == -1: |
| 85 | + return 1 |
| 86 | + elif rank_diff == 0: |
| 87 | + return 3 |
| 88 | + else: |
| 89 | + return 10 * rank_diff * rank_diff |
| 90 | + |
| 91 | + def level_up(self): |
| 92 | + self.progress -= 100 |
| 93 | + self.rank_index += 1 |
| 94 | + if self.rank == 8: |
| 95 | + self.progress = 0 |
| 96 | + |
| 97 | + def inc_progress(self, rank): |
| 98 | + print("u: {}, ex: {}".format(self.rank, rank)) |
| 99 | + new_rank_index = ranks.index(rank) |
| 100 | + print("new_rank is {} ({})".format(new_rank_index, ranks[new_rank_index])) |
| 101 | + self.progress += self.get_progress_points(new_rank_index) |
| 102 | + print("before level flushing: {}".format(self.progress)) |
| 103 | + while self.progress >= 100: |
| 104 | + self.level_up() |
| 105 | + print("levelup - new progress: {} - new rank: {}".format(self.progress, self.rank)) |
| 106 | + |
| 107 | + |
| 108 | +class Test4CodewarsStyleRankingSystem(TestCase): |
| 109 | + def test_1(self): |
| 110 | + user = User() |
| 111 | + self.assertEqual(user.rank, -8) |
| 112 | + self.assertEqual(user.progress, 0) |
| 113 | + user.inc_progress(-7) |
| 114 | + self.assertEqual(user.progress, 10) |
| 115 | + user.inc_progress(-5) |
| 116 | + self.assertEqual(user.progress, 0) |
| 117 | + self.assertEqual(user.rank, -7) |
0 commit comments