Files
CTFd/CTFd/plugins/dynamic_challenges/decay.py
Kevin Chung 70999b4fa0 Add linear decay function to dynamic challenges (#2347)
* Add linear decay funciton to dynamic value challenges
* Add the ability to choose between decay functions for dynamic value challenges
* Closes #2224 
* Closes #865
2023-06-29 03:44:33 -04:00

76 lines
1.9 KiB
Python

from __future__ import division # Use floating point for math calculations
import math
from CTFd.models import Solves
from CTFd.utils.modes import get_model
def get_solve_count(challenge):
Model = get_model()
solve_count = (
Solves.query.join(Model, Solves.account_id == Model.id)
.filter(
Solves.challenge_id == challenge.id,
Model.hidden == False,
Model.banned == False,
)
.count()
)
return solve_count
def linear(challenge):
solve_count = get_solve_count(challenge)
# If the solve count is 0 we shouldn't manipulate the solve count to
# let the math update back to normal
if solve_count != 0:
# We subtract -1 to allow the first solver to get max point value
solve_count -= 1
value = challenge.initial - (challenge.decay * solve_count)
value = math.ceil(value)
if value < challenge.minimum:
value = challenge.minimum
return value
def logarithmic(challenge):
solve_count = get_solve_count(challenge)
# If the solve count is 0 we shouldn't manipulate the solve count to
# let the math update back to normal
if solve_count != 0:
# We subtract -1 to allow the first solver to get max point value
solve_count -= 1
# Handle situations where admins have entered a 0 decay
# This is invalid as it can cause a division by zero
if challenge.decay == 0:
challenge.decay = 1
# It is important that this calculation takes into account floats.
# Hence this file uses from __future__ import division
value = (
((challenge.minimum - challenge.initial) / (challenge.decay ** 2))
* (solve_count ** 2)
) + challenge.initial
value = math.ceil(value)
if value < challenge.minimum:
value = challenge.minimum
return value
DECAY_FUNCTIONS = {
"linear": linear,
"logarithmic": logarithmic,
}