From e3ed1a2e0d55e5cbac37648a33e6f2dbca74807a Mon Sep 17 00:00:00 2001 From: Rene Saarsoo Date: Fri, 20 Nov 2020 14:14:24 +0200 Subject: [PATCH] XP calculation for repeated intervals --- src/stats/xp.test.ts | 42 +++++++++++++++++++++++++++++++----------- src/stats/xp.ts | 32 ++++++++++++++++++++------------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/stats/xp.test.ts b/src/stats/xp.test.ts index 3c4819b..8aff3c5 100644 --- a/src/stats/xp.test.ts +++ b/src/stats/xp.test.ts @@ -2,6 +2,7 @@ import { xp } from "./xp"; import { Interval } from "../ast"; import { Duration } from "../Duration"; import { ConstantIntensity, RangeIntensity } from "../Intensity"; +import { RepeatedInterval } from "../detectRepeats"; describe("xp()", () => { describe("ConstantIntensity interval", () => { @@ -65,16 +66,35 @@ describe("xp()", () => { }); }); - // Intervals - // - // 4 x 15s = 1min --> 11 XP - // 4 x 30s = 2min --> 23 XP - // 4 x 60s = 4min --> 47 XP + describe("Repeated interval", () => { + const createTestInterval = (seconds: number): RepeatedInterval => ({ + type: "repeat", + times: 2, + intervals: [ + { + type: "Interval", + duration: new Duration(seconds / 4), + intensity: new ConstantIntensity(80), + comments: [], + }, + { + type: "Interval", + duration: new Duration(seconds / 4), + intensity: new ConstantIntensity(70), + comments: [], + }, + ], + comments: [], + }); - // Other XP - // - // 20 XP per km - - // 221 km - // 6:42 of intervals + [ + [4 * 15, 11], // 1 minute + [4 * 30, 23], // 2 minutes + [4 * 60, 47], // 4 minutes + ].forEach(([seconds, expectedXp]) => { + it(`${seconds}s produces ${expectedXp} XP`, () => { + expect(xp([createTestInterval(seconds)])).toEqual(expectedXp); + }); + }); + }); }); diff --git a/src/stats/xp.ts b/src/stats/xp.ts index 0cff315..e70dd16 100644 --- a/src/stats/xp.ts +++ b/src/stats/xp.ts @@ -1,20 +1,28 @@ import { Interval } from "../ast"; import { sum } from "ramda"; import { RangeIntensity, ConstantIntensity, FreeIntensity } from "../Intensity"; +import { RepeatedInterval } from "../detectRepeats"; +import { totalDuration } from "./totalDuration"; -const intervalXp = ({ intensity, duration }: Interval): number => { - if (intensity instanceof RangeIntensity) { - // 6 XP per minute (1XP for every 10 seconds) - return Math.floor(duration.seconds / 10); - } else if (intensity instanceof ConstantIntensity) { - // 10 XP per minute (1XP for every 5.56 seconds) - return Math.floor(duration.seconds / 5.56); - } else if (intensity instanceof FreeIntensity) { - // 5 XP per minute - return Math.round(duration.seconds / 60) * 5; +const intervalXp = (interval: Interval | RepeatedInterval): number => { + if (interval.type === "repeat") { + // 11 XP per minute (1 XP for every 5.1 seconds) + const duration = totalDuration(interval.intervals).seconds * interval.times; + return Math.floor(duration / 5.1); } else { - throw new Error("Unknown type of intensity"); + if (interval.intensity instanceof RangeIntensity) { + // 6 XP per minute (1XP for every 10 seconds) + return Math.floor(interval.duration.seconds / 10); + } else if (interval.intensity instanceof ConstantIntensity) { + // 10 XP per minute (1XP for every 5.56 seconds) + return Math.floor(interval.duration.seconds / 5.56); + } else if (interval.intensity instanceof FreeIntensity) { + // 5 XP per minute + return Math.round(interval.duration.seconds / 60) * 5; + } else { + throw new Error("Unknown type of intensity"); + } } }; -export const xp = (intervals: Interval[]): number => sum(intervals.map(intervalXp)); +export const xp = (intervals: (Interval | RepeatedInterval)[]): number => sum(intervals.map(intervalXp));