Skip to content

Instantly share code, notes, and snippets.

@carlows
Created March 4, 2023 17:54
Show Gist options
  • Save carlows/e75e48de4a341275b0b76a1a4a1df359 to your computer and use it in GitHub Desktop.
Save carlows/e75e48de4a341275b0b76a1a4a1df359 to your computer and use it in GitHub Desktop.
codewars exercise
class Level
# list of valid levels (skips 0)
@@levels = [*(-8..-1)] + [*(1..8)]
def self.all
@@levels
end
# Always returns a valid level
def self.next(current_level, levels_to_inc = 1)
@@levels[@@levels.index(current_level) + levels_to_inc]
end
def self.diff(level1, level2)
level1_index = @@levels.index(level1)
level2_index = @@levels.index(level2)
(level1_index - level2_index).abs
end
def self.last_level?(level)
@@levels.index(level) == @@levels.size - 1
end
end
class User
attr_accessor :rank, :progress
def initialize(rank = -8, progress = 0)
self.rank = rank
self.progress = progress
end
def inc_progress(activity_rank)
validate_rank(activity_rank)
return if rank == 8
if rank == activity_rank
self.progress += 3
end
if rank == Level.next(activity_rank)
self.progress += 1
end
if rank < activity_rank
diff = Level.diff(rank, activity_rank)
self.progress += 10 * diff * diff
end
recalculate_rank()
end
private
def recalculate_rank()
remaining = progress % 100
levels_to_increment = progress / 100
if progress >= 100
self.rank = Level.next(rank, levels_to_increment)
end
Level.last_level?(rank) ? self.progress = 0 : self.progress = remaining
end
def validate_rank(rank)
return true if Level.all.include?(rank)
raise "invalid rank"
end
end
# From Ruby 3.0, RSpec is used under the hood.
# See https://rspec.info/
def assert(user, expected_rank, expected_progress)
Test.assert_equals(user.rank, expected_rank, "rank")
Test.assert_equals(user.progress, expected_progress, "progress")
end
describe "Level" do
it "should return the next level" do
Test.assert_equals(Level.next(-8), -7)
Test.assert_equals(Level.next(-1), 1)
Test.assert_equals(Level.next(8), nil)
end
it "should return the next level using the amount of levels to increment" do
Test.assert_equals(Level.next(-8, 6), -2)
Test.assert_equals(Level.next(-2, 2), 1)
end
it "should return the level difference" do
Test.assert_equals(Level.diff(-8, -7), 1)
Test.assert_equals(Level.diff(-5, -4), 1)
Test.assert_equals(Level.diff(-4, -5), 1)
Test.assert_equals(Level.diff(-5, -5), 0)
Test.assert_equals(Level.diff(-1, 1), 1)
Test.assert_equals(Level.diff(1, -1), 1)
end
end
describe "User" do
it "should initialize a user with rank -8 and progress 0" do
user = User.new
Test.assert_equals(user.progress, 0)
Test.assert_equals(user.rank, -8)
end
it "should raise an error when activity rank is invalid" do
user = User.new
Test.expect_error { user.inc_progress(-9) }
Test.expect_error { user.inc_progress(-15) }
Test.expect_error { user.inc_progress(9) }
Test.expect_error { user.inc_progress(100) }
Test.expect_error { user.inc_progress(0) }
end
it "should increment progress by 3 points when activity is ranked the same as the user" do
user = User.new
user.inc_progress(-8)
assert(user, -8, 3)
end
it "should increment the rank when progress reaches 100 and keeps remaining progress" do
user = User.new(-8, 97)
user.inc_progress(-8)
assert(user, -7, 0)
user = User.new(-1, 97)
user.inc_progress(-1)
assert(user, 1, 0)
end
it "should cap maximum rank at 8" do
user = User.new(7, 97)
user.inc_progress(7)
assert(user, 8, 0)
user.inc_progress(8)
assert(user, 8, 0)
end
it "should keep the remaining progress when ranking up" do
user = User.new(-8, 99)
user.inc_progress(-8)
assert(user, -7, 2)
end
it "should increment progress by 1 when activity is 1 level less than rank" do
user = User.new(5, 97)
user.inc_progress(4)
assert(user, 5, 98)
user = User.new(5, 99)
user.inc_progress(4)
assert(user, 6, 0)
end
it "should increment points using formula 10 * d * d when activity is a higher rank than current user rank" do
user = User.new(-8, 0)
user.inc_progress(-7)
assert(user, -8, 10)
user = User.new(-8, 0)
user.inc_progress(-6)
assert(user, -8, 40)
user = User.new(-8, 0)
user.inc_progress(-5)
assert(user, -8, 90)
user = User.new(-8, 0)
user.inc_progress(-4)
assert(user, -7, 60)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment