Skip to content

Commit

Permalink
refactor player class
Browse files Browse the repository at this point in the history
  • Loading branch information
wow890209 committed Oct 28, 2023
1 parent 2e18dc1 commit c706aad
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 208 deletions.
5 changes: 5 additions & 0 deletions utopia-gamification/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,10 @@
<artifactId>mongo-gateway</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>tw.waterballsa.utopia</groupId>
<artifactId>utopia-test-kit</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,79 +1,43 @@
package tw.waterballsa.utopia.utopiagamification.quest.domain

import tw.waterballsa.utopia.utopiagamification.quest.extensions.LevelSheet.Companion.calculateLevel
import tw.waterballsa.utopia.utopiagamification.quest.extensions.LevelSheet.Companion.toLevel
import java.time.OffsetDateTime
import java.time.OffsetDateTime.now
import kotlin.ULong.Companion.MIN_VALUE

class Player(
val id: String,
var name: String,
var exp: ULong = MIN_VALUE,
var level: UInt = 1u,
exp: ULong = 0uL,
level: UInt = 1u,
val joinDate: OffsetDateTime = now(),
var latestActivateDate: OffsetDateTime = now(),
var levelUpgradeDate: OffsetDateTime = now(),
val jdaRoles: MutableList<String> = mutableListOf(),
latestActivateDate: OffsetDateTime = now(),
levelUpgradeDate: OffsetDateTime? = null,
val jdaRoles: MutableList<String> = mutableListOf()
) {

init {
calculateLevel()
}
var exp = exp
private set

val currentLevelExpLimit
get() = getLevelExpLimit(level)
var level = level
private set

fun gainExp(rewardExp: ULong) {
exp += rewardExp
calculateLevel()
activate()
}
var levelUpgradeDate = levelUpgradeDate
private set

private fun calculateLevel() {
var explimit = getLevelExpLimit(level)
while (exp >= explimit) {
exp -= explimit
level++
explimit = getLevelExpLimit(level)
levelUpgradeDate = now()
}
}
var latestActivateDate = latestActivateDate
private set

private fun calculateLevel1() {
val newLevel = calculateLevel(exp)
if (newLevel > level) {
fun gainExp(rewardExp: ULong) {
exp += rewardExp
val newLevel = exp.toLevel()
if (newLevel != level) {
level = newLevel
levelUpgradeDate = now()
}
activate()
}

private fun activate() {
latestActivateDate = now()
}
}

private const val EXP_PER_MIN = 10u
private val COEFFICIENT = listOf(1u, 2u, 4u, 8u, 12u, 16u, 32u, 52u, 64u, 84u)
private val UPGRADE_TIME_TABLE = mutableListOf<UInt>()
private fun getCoefficient(level: UInt): UInt {
if (level > 100u) {
return COEFFICIENT.last()
}
return COEFFICIENT[(level.toInt() - 1) / 10]
}

private fun calculateUpgradeTime(level: UInt, table: MutableList<UInt>): UInt {
table.getOrElse(level.toInt()) {
val result = if (level == 0u) {
0u
} else {
calculateUpgradeTime(level - 1u, table) + EXP_PER_MIN * getCoefficient(level)
}
table.add(level.toInt(), result)
}
return table[level.toInt()]
}

private fun getLevelExpLimit(level: UInt): UInt {
return calculateUpgradeTime(level, UPGRADE_TIME_TABLE) * EXP_PER_MIN
}
Original file line number Diff line number Diff line change
@@ -1,54 +1,52 @@
package tw.waterballsa.utopia.utopiagamification.quest.extensions

import tw.waterballsa.utopia.utopiagamification.quest.extensions.LevelSheet.LevelRange.Companion.LEVEL_ONE
import kotlin.ULong.Companion.MIN_VALUE
import java.lang.String.format


class LevelSheet private constructor() {

companion object {
const val EXP_PER_MINUTES = 10u
private const val EXP_PER_MINUTES = 10u
private const val MAX_LEVEL = 100
private val COEFFICIENTS = arrayOf(1u, 2u, 4u, 8u, 12u, 16u, 32u, 52u, 64u, 84u)
private val LEVEL_RANGES = generateSequence(LEVEL_ONE) { it.next() }.take(MAX_LEVEL)
private val LEVEL_TO_LEVEL_RANGE = generateSequence(LEVEL_ONE) { it.next() }.take(MAX_LEVEL).associateBy { it.level }

// exp to level
fun ULong.toLevel() = (LEVEL_TO_LEVEL_RANGE.values.find { it.isLevelUp(this) } ?: LEVEL_ONE).level.toUInt()

fun calculateLevel(exp: ULong) = (LEVEL_RANGES.find { it.isExpGreaterThan(exp) } ?: LEVEL_ONE).level.toUInt()
// level to level range
fun UInt.toLevelRange(): LevelRange = LEVEL_TO_LEVEL_RANGE[toInt()] ?: throw IllegalArgumentException("The given level ($this) not found.")
}

private class LevelRange private constructor(val level: Int = 1, previousLevelRange: LevelRange? = null) {
class LevelRange private constructor(val level: Int = 1, val previous: LevelRange? = null) {

// 升級時間
private val upgradeTime: ULong
val upgradeTime: ULong

// 累積經驗值
private val accExp: ULong
val accExp: ULong

// 當前經驗值上限
private val expLimit: ULong
val expLimit: ULong

companion object {
val LEVEL_ONE = LevelRange()
val LEVEL_ONE = LevelRange(level = 1)
}

init {
// 經驗值係數
val coefficient = COEFFICIENTS[level.coerceAtLeast(1).div(10).coerceAtMost(COEFFICIENTS.size.minus(1))]
upgradeTime = (previousLevelRange?.upgradeTime ?: MIN_VALUE).plus(EXP_PER_MINUTES.times(coefficient))
accExp = (previousLevelRange?.accExp ?: MIN_VALUE).plus(EXP_PER_MINUTES.times(upgradeTime))
expLimit = accExp.minus(previousLevelRange?.accExp ?: MIN_VALUE)
upgradeTime = (previous?.upgradeTime ?: 0u).plus(EXP_PER_MINUTES.times(coefficient))
accExp = (previous?.accExp ?: 0u).plus(EXP_PER_MINUTES.times(upgradeTime))
expLimit = accExp.minus(previous?.accExp ?: 0u)
}

fun next() = LevelRange(level.plus(1), this)

fun isExpGreaterThan(exp: ULong) = accExp > exp
fun isLevelUp(exp: ULong) = accExp > exp

override fun toString(): String {
return String.format(
"level: %3d, upgrade time: %5d, exp limit: %6d, acc exp: %7d",
level,
upgradeTime.toLong(),
expLimit.toLong(),
accExp.toLong()
)
}
override fun toString(): String = format("| level: %3d | upgrade time: %5d | exp limit: %6d | acc exp: %7d | %n${"-".repeat(75)}",
level, upgradeTime.toLong(), expLimit.toLong(), accExp.toLong())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle
import org.springframework.stereotype.Component
import tw.waterballsa.utopia.utopiagamification.quest.domain.Mission
import tw.waterballsa.utopia.utopiagamification.quest.domain.Player
import tw.waterballsa.utopia.utopiagamification.quest.extensions.LevelSheet.Companion.toLevelRange
import tw.waterballsa.utopia.utopiagamification.quest.extensions.LevelSheet.LevelRange.Companion.LEVEL_ONE
import tw.waterballsa.utopia.utopiagamification.quest.extensions.publishToUser
import tw.waterballsa.utopia.utopiagamification.quest.usecase.ClaimMissionRewardUsecase
import tw.waterballsa.utopia.utopiagamification.repositories.PlayerRepository
Expand Down Expand Up @@ -45,11 +48,12 @@ class UtopiaGamificationQuestListener(
val request = ClaimMissionRewardUsecase.Request(player, questId)
val presenter = object : ClaimMissionRewardUsecase.Presenter {
override fun presentPlayerExpNotification(mission: Mission) {

publishMessage(
"""
${player.name} 已獲得 ${mission.quest.reward.exp} exp!!
目前等級:${player.level}
目前經驗值:${player.exp} / ${player.currentLevelExpLimit}
目前經驗值:${player.currentExp()}/${player.level.toLevelRange().expLimit}
""".trimIndent()
)
}
Expand All @@ -67,6 +71,9 @@ class UtopiaGamificationQuestListener(
}
}

private fun Player.currentExp(): ULong =
if(level == LEVEL_ONE.level.toUInt()) exp else exp - level.toLevelRange().previous!!.accExp

private fun ButtonInteractionEvent.splitButtonId(delimiters: String): List<String> {
val result = button.id?.split(delimiters) ?: return emptyList()
if (result.size != 3) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ interface PlayerRepository {

fun findPlayerById(id: String): Player?
fun savePlayer(player: Player): Player

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ data class PlayerDocument(
val level: Int,
val joinDate: OffsetDateTime,
val latestActivateDate: OffsetDateTime,
val levelUpgradeDate: OffsetDateTime,
val levelUpgradeDate: OffsetDateTime?
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package tw.waterballsa.utopia.utopiagmification.quest

import org.assertj.core.api.Assertions.*
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -74,5 +75,15 @@ class UtopiaGamificationQuestTest {
assertFalse(activityMission.isCompleted())
}

@Test
fun `given playerA level 3 and exp 650, when player gain 6000 exp, then level is 11 and exp is 6650`() {
val player = Player("A", "A", 650u, 3u)
val rewardExp = 6000uL
player.gainExp(rewardExp)

assertThat(player.exp).isEqualTo(6650uL)
assertThat(player.level).isEqualTo(11u)
}

private fun Player.acceptQuest(quest: Quest) = Mission(this, quest)
}

0 comments on commit c706aad

Please sign in to comment.