snorklerjoe/CubeServer

View on GitHub
src/CubeServer-common/cubeserver_common/models/multiplier.py

Summary

Maintainability
A
0 mins
Test Coverage
"""Handles any point multipliers that may apply to a team
"""

from abc import ABC
from enum import unique, Enum
from typing import Any

from cubeserver_common.models.utils.modelutils import Encodable
from cubeserver_common.models.utils.dummycodec import DummyCodec
from cubeserver_common.models.utils.enumcodec import EnumCodec
from cubeserver_common.models.team import TeamLevel


class IndivMultiplier(Encodable, ABC):
    """Describes an individual multiplier factor"""

    def __init_subclass__(cls, *, amt_codec=DummyCodec(float)) -> None:
        cls.amt_codec = amt_codec
        return super().__init_subclass__()

    def __init__(self, value: float = 1.0, amt: Any = 0):
        super().__init__()
        self.value = value
        self.amt = amt

    def encode(self) -> dict:
        return {"value": self.value, "amt": self.amt_codec.transform_python(self.amt)}

    @classmethod
    def decode(cls, value: dict):
        i_m = cls.__new__(cls)
        i_m.value = value["value"]
        i_m.amt = cls.amt_codec.transform_bson(value["amt"])
        return i_m

    def __str__(self) -> str:
        if type(self.value) == float:
            return "{:.2f}".format(self.value)
        return str(self.value)


class CostMultiplier(IndivMultiplier):
    """Describes the multiplier associated with excess monetary spending"""

    def __init__(self, level: TeamLevel, amt_spent: float):
        """Calculates the multiplier based on the amount spent as follows:
        For J.V AND Varsity:
            +0.05 for every $1 less than $20
        """
        super().__init__(
            0.05 * (20.00 - amt_spent) if (amt_spent < 20.00) else 1.0, amt_spent
        )


class MassMultiplier(IndivMultiplier):
    """Describes the multiplier associated with mass"""

    def __init__(self, level: TeamLevel, mass: float):
        """Calculates the multiplier based on the cube mass as follows:
        For J.V:
            +0.01 per gram below 400g
        For Varsity:
            +0.01 per gram below 400g
        """
        baseline = 400  # if (level == TeamLevel.JUNIOR_VARSITY) else 400
        super().__init__(
            1.0 + (0.01 * (baseline - mass) if (mass < baseline) else 0.0), mass
        )


@unique
class VolumeUnit(Enum):
    """Enumerates each bounding cube size used for volume determination
    Enum values represent the cube length, in inches"""

    XS = 2
    S = 3
    M = 4
    L = 5
    XL = 7


class VolumeMultiplier(IndivMultiplier, amt_codec=EnumCodec(VolumeUnit, int)):
    """Describes the multiplier associated with different size profiles"""

    def __init__(self, level: TeamLevel, bounding_box: VolumeUnit):
        """Calculates the multiplier based on the amount spent as follows:
        For Varsity:
            See scoring scheme for more info.
        """
        mult = (
            1.00
            if (level == TeamLevel.JUNIOR_VARSITY)
            else ({2: 1.3, 3: 1.2, 4: 1.1, 5: 1.0, 7: 0.8}[bounding_box.value])
        )
        super().__init__(mult, bounding_box)


class Multiplier(Encodable):
    """Describes the total multiplier of a team
    Created so that multiple multiplier factors may exist."""

    def __init__(self, mass_mult: MassMultiplier):
        super().__init__()
        self.mass_mult = mass_mult

    @property
    def amount(self):
        """Calculates the product multiplier"""
        # product = self.cost_mult.value * self.mass_mult.value * self.vol_mult.value
        product = self.mass_mult.value
        return product

    def encode(self) -> dict:
        return {
            # "cost": self.cost_mult.encode(),
            "mass": self.mass_mult.encode()
            # "vol":  self.vol_mult.encode()
        }

    @classmethod
    def decode(cls, value: dict):
        mult = cls(
            # CostMultiplier.decode(value['cost']),
            MassMultiplier.decode(value["mass"])
            # VolumeMultiplier.decode(value['vol'])
        )
        return mult


DEFAULT_MULTIPLIER = Multiplier(
    #            CostMultiplier(TeamLevel.JUNIOR_VARSITY, 0.0),
    MassMultiplier(TeamLevel.JUNIOR_VARSITY, 0.0),
    #            VolumeMultiplier(TeamLevel.JUNIOR_VARSITY, VolumeUnit.M)
)