Spaces:
Running on Zero
Running on Zero
Download app/services/xp_rules.py from cipher-attacks/Dbu-central-bot: direct link, hf CLI and curl.
- Browser
- Download file 1.89 kB
-
https://huggingface.co/spaces/cipher-attacks/Dbu-central-bot/resolve/main/app/services/xp_rules.py
- Command line
-
hf download hf://spaces/cipher-attacks/Dbu-central-bot/app/services/xp_rules.py
-
curl -L -o xp_rules.py https://huggingface.co/spaces/cipher-attacks/Dbu-central-bot/resolve/main/app/services/xp_rules.py
1.89 kB
| """The XP economy. Pure data + functions: easy to read, tune and test. | |
| Design goals | |
| * Consistency beats bursts (daily cap, active-days requirement for prizes). | |
| * Referrals only pay in full when the invited student becomes a REAL active user. | |
| * Nothing here can be farmed with a script: caps, idempotent events, delayed rewards. | |
| """ | |
| from typing import Optional | |
| DAILY_CAP = 25 # max XP/day from the automatic sources below | |
| CAPPED_KINDS = frozenset({"checkin", "download", "referral_join"}) | |
| PER_KIND_DAILY = {"download": 3, "referral_join": 5} # max events per day | |
| REFERRAL_JOIN_XP = 5 # invitee joined the channel + passed the gate | |
| REFERRAL_QUALIFIED_XP = 30 # invitee later proved active (see QUALIFY_* below) | |
| REFERRAL_QUALIFIED_PER_WEEK = 5 # paid referrals counted per week | |
| QUALIFY_MIN_ACTIVE_DAYS = 3 | |
| QUALIFY_WINDOW_DAYS = 14 | |
| VELOCITY_LIMIT_24H = 8 # more invitees than this in 24h from one inviter = suspicious | |
| MIN_TRUST = 70 | |
| STREAK_MILESTONES = {7: 10, 14: 25, 30: 60, 60: 120} | |
| LEVEL_THRESHOLDS = (0, 25, 75, 150, 275, 450, 700, 1050, 1550, 2300) # level n needs >= [n-1] | |
| MAX_LEVEL = len(LEVEL_THRESHOLDS) | |
| def checkin_xp(streak: int) -> int: | |
| """3 XP on day 1, +1 per extra streak day, up to 7.""" | |
| return 3 + min(max(streak - 1, 0), 4) | |
| def level_for(points: int) -> tuple[int, Optional[int]]: | |
| """-> (level, XP still needed for the next level, or None at max level).""" | |
| level = 1 | |
| for i, threshold in enumerate(LEVEL_THRESHOLDS, start=1): | |
| if points >= threshold: | |
| level = i | |
| if level >= MAX_LEVEL: | |
| return level, None | |
| return level, LEVEL_THRESHOLDS[level] - points | |
| def next_streak(last_active_iso: Optional[str], today_iso: str, current: int, yesterday_iso: str) -> int: | |
| if last_active_iso == today_iso: | |
| return current | |
| if last_active_iso == yesterday_iso: | |
| return current + 1 | |
| return 1 | |