DailyChallengeScoreAlgorithm.kt

package delta.codecharacter.server.logic.daily_challenge_score

import delta.codecharacter.dtos.ChallengeTypeDto
import delta.codecharacter.server.config.GameConfiguration
import delta.codecharacter.server.daily_challenge.DailyChallengeEntity
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import java.time.Duration
import java.time.Instant
import kotlin.math.exp

class DailyChallengeScoreAlgorithm(@Autowired private val gameConfiguration: GameConfiguration) :
    ScoreAlgorithm {

    @Value("\${environment.event-start-date}") private lateinit var startDate: String
    private val perfectBasePartConstant = 0.7
    private val perfectTimePartConstant = 0.3
    private val exponentialConstantForBasePart = 150
    private val exponentialConstantForTimePart = 15
    private val secondsInADay = 86400
    private val secondsInAnHour = 3600

    override fun getHoursSinceDailyChallengeLaunched(): Double {
        val givenDateTime = Instant.parse(startDate)
        val nowDateTime = Instant.now()
        val period: Duration = Duration.between(givenDateTime, nowDateTime)

        return (period.toSeconds().toDouble().rem(secondsInADay)) / secondsInAnHour
    }

    override fun getPlayerBaseScore(
        coinsLeftPercent: Double,
        destructionPercent: Double,
        perfectBaseScore: Double,
        challType: ChallengeTypeDto
    ): Double {
        if (challType == ChallengeTypeDto.CODE)
            return ((100.0 - coinsLeftPercent) + (2 * (100 - destructionPercent)) + perfectBaseScore)
        return (coinsLeftPercent + (2 * destructionPercent) + perfectBaseScore)
    }

    override fun getPlayerTimeScore(perfectTimeScore: Double): Double {
        val hours = getHoursSinceDailyChallengeLaunched()
        return perfectTimeScore * exp((-1) * (hours / exponentialConstantForTimePart))
    }

    override fun getDailyChallengeScore(
        playerCoinsUsed: Int,
        playerDestruction: Double,
        dailyChallenge: DailyChallengeEntity
    ): Double {
        val totalCoins = gameConfiguration.gameParameters().numberOfCoins
        val (_, _, _, challType, _, _, perfectScore, numberOfCompletions) = dailyChallenge
        val perfectBasePart =
            perfectBasePartConstant *
                perfectScore *
                exp(((-1) * (numberOfCompletions.toDouble() / exponentialConstantForBasePart)))
        val perfectTimePart = perfectTimePartConstant * perfectScore
        val coinsLeftPercentage = ((totalCoins - playerCoinsUsed.toDouble()) / totalCoins) * 100
        return (
            (
                getPlayerBaseScore(
                    coinsLeftPercentage, playerDestruction, perfectBasePart, challType
                ) +
                    getPlayerTimeScore(perfectTimePart)
                ) * 100.0
            )
            .toInt() / 100.0
    }
}