Switch streak bonus to capped per-day ramp
- 스트릭 보너스를 마일스톤 계단(+2/+5/+10/+20)에서 min(스트릭 일수, 15) 일별 점증 구조로 교체 - 적중일 기본 적립 대비 보너스 비중을 30~50%까지 높여 스트릭 유지 유인 강화 (포인트 경제 리서치 결론 반영) - 상한 15로 시즌 이월 장기 스트릭의 이득을 초반 램프업 생략(~105pt) 수준으로 제한 — 이월은 의도적 허용 - judgmentService 테스트의 포인트 기대값을 새 공식으로 갱신
This commit is contained in:
parent
da8ecf6d4f
commit
a38d7ade28
@ -33,14 +33,19 @@ export function judgeByCounts(correct: number, t: Thresholds): DailyJudgment {
|
|||||||
return "fail";
|
return "fail";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 스트릭 유지·증가 시 지급되는 보너스 포인트 상한.
|
||||||
|
* 상한이 있어야 시즌을 넘겨 이월된 장기 스트릭의 이득이
|
||||||
|
* "초반 램프업 생략" 수준(최대 ~105pt)으로 제한된다 — 이월은 의도적으로 허용.
|
||||||
|
*/
|
||||||
|
export const STREAK_BONUS_CAP = 15;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 스트릭 유지·증가 시 지급되는 보너스 포인트.
|
* 스트릭 유지·증가 시 지급되는 보너스 포인트.
|
||||||
* 스트릭이 길수록 가산폭이 커지도록 완만한 계단 함수.
|
* 스트릭 일수만큼 매일 가산하되 [STREAK_BONUS_CAP]에서 멈추는 일별 점증 구조 —
|
||||||
|
* 기본 적립(적중 수 × 10) 대비 30~50%까지 커져 스트릭을 지킬 유인을 만든다.
|
||||||
*/
|
*/
|
||||||
export function streakBonus(streakAfter: number): number {
|
export function streakBonus(streakAfter: number): number {
|
||||||
if (streakAfter >= 30) return 20;
|
if (streakAfter <= 0) return 0;
|
||||||
if (streakAfter >= 14) return 10;
|
return Math.min(streakAfter, STREAK_BONUS_CAP);
|
||||||
if (streakAfter >= 7) return 5;
|
|
||||||
if (streakAfter >= 3) return 2;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,7 +135,7 @@ describe("judgmentService (Firestore emulator)", () => {
|
|||||||
expect(hist.streakAfter).toBe(1);
|
expect(hist.streakAfter).toBe(1);
|
||||||
expect(user.currentStreak).toBe(1);
|
expect(user.currentStreak).toBe(1);
|
||||||
expect(user.highestStreak).toBe(1);
|
expect(user.highestStreak).toBe(1);
|
||||||
expect(user.tierPoints).toBe(50); // 5 * 10, streak 1이라 보너스 0
|
expect(user.tierPoints).toBe(51); // 5 * 10 + 스트릭 보너스 min(1, 15)
|
||||||
expect(user.lastJudgedDate).toBe(TUE);
|
expect(user.lastJudgedDate).toBe(TUE);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ describe("judgmentService (Firestore emulator)", () => {
|
|||||||
|
|
||||||
expect(hist.judgment).toBe("success");
|
expect(hist.judgment).toBe("success");
|
||||||
expect(user.currentStreak).toBe(1);
|
expect(user.currentStreak).toBe(1);
|
||||||
expect(user.tierPoints).toBe(30);
|
expect(user.tierPoints).toBe(31); // 3 * 10 + 스트릭 보너스 1
|
||||||
});
|
});
|
||||||
|
|
||||||
it("5경기·2적중은 fail, 스트릭 0 유지, 포인트 불변", async () => {
|
it("5경기·2적중은 fail, 스트릭 0 유지, 포인트 불변", async () => {
|
||||||
@ -382,7 +382,7 @@ describe("judgmentService (Firestore emulator)", () => {
|
|||||||
|
|
||||||
const user = await readUser();
|
const user = await readUser();
|
||||||
expect(user.currentStreak).toBe(1);
|
expect(user.currentStreak).toBe(1);
|
||||||
expect(user.tierPoints).toBe(50);
|
expect(user.tierPoints).toBe(51);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user