Simplifying and making calculation logic clearer
This commit is contained in:
+217
-197
@@ -1,4 +1,4 @@
|
|||||||
import { Activity, Attribute, attributes, ActivityPerformance, findNearestPoints, getActivityAttribute, getAttributeActivities, Player, StandardsMap, BaseLevel, Standard } from "./util";
|
import { Activity, Attribute, attributes, ActivityPerformance, findNearestPoints, getActivityAttribute, getAttributeActivities, Player, StandardsMap, Levels, Standard, Metrics, activities } from "./util";
|
||||||
import rawStandards from "./standards.json" assert { type: "json" }
|
import rawStandards from "./standards.json" assert { type: "json" }
|
||||||
|
|
||||||
// SOURCES
|
// SOURCES
|
||||||
@@ -13,236 +13,256 @@ import rawStandards from "./standards.json" assert { type: "json" }
|
|||||||
|
|
||||||
const standards = rawStandards as StandardsMap;
|
const standards = rawStandards as StandardsMap;
|
||||||
|
|
||||||
type BaseLevelValues = Record<BaseLevel, number>
|
type TableData = Record<Activity, {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
}>
|
||||||
// Level utilities (helpers)
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
function findLevel(levels: Record<number, number>, performance: number): number {
|
type LevelCalculatorConfig = {
|
||||||
let resultLevel = 1;
|
compressTo?: number;
|
||||||
let resultLevelDiff = Infinity;
|
expandIters?: number;
|
||||||
|
|
||||||
for (const level in levels) {
|
|
||||||
const diff = Math.abs(performance - levels[level as unknown as number]);
|
|
||||||
if (diff < resultLevelDiff) {
|
|
||||||
resultLevel = +level;
|
|
||||||
resultLevelDiff = diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function compressLevels(
|
export class LevelCalculator {
|
||||||
levels: Record<number, number>,
|
cfg: Required<LevelCalculatorConfig>;
|
||||||
targetLevelsAmount: number,
|
|
||||||
): Record<number, number> {
|
|
||||||
const levelsAmount = Object.keys(levels).length;
|
|
||||||
if (levelsAmount < targetLevelsAmount) {
|
|
||||||
throw new Error(
|
|
||||||
"Target levels amount must be greater than or equal to the current levels amount",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ratio = levelsAmount / targetLevelsAmount;
|
public constructor(cfg: LevelCalculatorConfig = {}) {
|
||||||
const compressedLevels: Record<number, number> = {};
|
this.cfg = {
|
||||||
|
compressTo: cfg.compressTo ?? 100,
|
||||||
for (let i = 0; i < targetLevelsAmount; ++i) {
|
expandIters: cfg.expandIters ?? 5
|
||||||
const ratioIndex = i * ratio;
|
|
||||||
const lowerIndex = Math.floor(ratioIndex);
|
|
||||||
const upperIndex = Math.ceil(ratioIndex);
|
|
||||||
|
|
||||||
const lowerValue = levels[lowerIndex + 1];
|
|
||||||
const upperValue = levels[upperIndex + 1];
|
|
||||||
|
|
||||||
const weight = ratioIndex - lowerIndex;
|
|
||||||
compressedLevels[i + 1] = lowerValue + (upperValue - lowerValue) * weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return compressedLevels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function expandLevels(
|
|
||||||
levels: BaseLevel | Record<number, number>,
|
|
||||||
i: number
|
|
||||||
): Record<number, number> {
|
|
||||||
if (i == 0) {
|
|
||||||
// ensure we always use number keys
|
|
||||||
const newLevels = {};
|
|
||||||
for (let k = 0; k < Object.keys(levels).length; ++k) {
|
|
||||||
newLevels[k + 1] = levels[Object.keys(levels)[k]];
|
|
||||||
}
|
|
||||||
return newLevels;
|
|
||||||
};
|
|
||||||
|
|
||||||
const newLevels = {};
|
|
||||||
let j = 1;
|
|
||||||
for (let k = 0; k < Object.keys(levels).length; ++k) {
|
|
||||||
const currLevel = Object.keys(levels)[k];
|
|
||||||
const nextLevel = Object.keys(levels)[k + 1];
|
|
||||||
|
|
||||||
newLevels[j++] = levels[currLevel];
|
|
||||||
|
|
||||||
if (nextLevel) {
|
|
||||||
newLevels[j++] = (levels[currLevel] + levels[nextLevel]) / 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return expandLevels(newLevels, i - 1);
|
// -------------------------------------------------------------------------------------------------
|
||||||
}
|
// Level utilities (helpers)
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
findLevel(levels: Levels, performance: number): number {
|
||||||
// Standards interpolation (heavy math bits)
|
let resultLevel = 1;
|
||||||
// -------------------------------------------------------------------------------------------------
|
let resultLevelDiff = Infinity;
|
||||||
|
|
||||||
function interpolateStandardsValues(
|
for (const level in levels) {
|
||||||
lower: BaseLevelValues,
|
const diff = Math.abs(performance - levels[level as unknown as number]);
|
||||||
upper: BaseLevelValues,
|
if (diff < resultLevelDiff) {
|
||||||
ratio: number,
|
resultLevel = +level;
|
||||||
): BaseLevelValues {
|
resultLevelDiff = diff;
|
||||||
function lerp(k: BaseLevel): number {
|
}
|
||||||
return (lower[k] as number) + ((upper[k] as number) - (lower[k] as number)) * ratio;
|
}
|
||||||
|
return resultLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
compressLevels(
|
||||||
physicallyActive: lerp("physicallyActive"),
|
levels: Levels,
|
||||||
beginner: lerp("beginner"),
|
targetLevelsAmount: number,
|
||||||
intermediate: lerp("intermediate"),
|
): Levels {
|
||||||
advanced: lerp("advanced"),
|
const levelsAmount = Object.keys(levels).length;
|
||||||
elite: lerp("elite"),
|
if (levelsAmount < targetLevelsAmount) {
|
||||||
};
|
throw new Error(
|
||||||
}
|
"Target levels amount must be greater than or equal to the current levels amount",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function interpolateByBodyWeight(
|
const ratio = levelsAmount / targetLevelsAmount;
|
||||||
targetAge: number,
|
const compressedLevels: Levels = {};
|
||||||
bodyWeightKG: number,
|
|
||||||
standardsArr: Standard[],
|
|
||||||
): BaseLevelValues | null {
|
|
||||||
const ageFilteredStandards = standardsArr.filter((s) => s.metrics.age === targetAge);
|
|
||||||
if (ageFilteredStandards[0].metrics.weight === -1) return ageFilteredStandards[0].levels;
|
|
||||||
|
|
||||||
const weightArray = [...new Set(ageFilteredStandards.map((s) => s.metrics.weight))].sort((a, b) => a - b);
|
for (let i = 0; i < targetLevelsAmount; ++i) {
|
||||||
const { lower, upper } = findNearestPoints(bodyWeightKG, weightArray);
|
const ratioIndex = i * ratio;
|
||||||
|
const lowerIndex = Math.floor(ratioIndex);
|
||||||
|
const upperIndex = Math.ceil(ratioIndex);
|
||||||
|
|
||||||
const weightLower = ageFilteredStandards.find((s) => s.metrics.weight === lower);
|
const lowerValue = levels[lowerIndex + 1];
|
||||||
const weightUpper = ageFilteredStandards.find((s) => s.metrics.weight === upper);
|
const upperValue = levels[upperIndex + 1];
|
||||||
if (!weightLower || !weightUpper) return null;
|
|
||||||
|
|
||||||
let weightRatio = upper === lower ? 1 : (bodyWeightKG - lower) / (upper - lower);
|
const weight = ratioIndex - lowerIndex;
|
||||||
weightRatio = Math.max(0, Math.min(1, weightRatio));
|
compressedLevels[i + 1] = lowerValue + (upperValue - lowerValue) * weight;
|
||||||
|
}
|
||||||
|
|
||||||
return interpolateStandardsValues(weightLower.levels, weightUpper.levels, weightRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
function interpolateActivityLevels(
|
|
||||||
activity: Activity,
|
|
||||||
player: Player,
|
|
||||||
): Record<number, number> {
|
|
||||||
// Filter dataset
|
|
||||||
const filteredStandards = standards[activity]
|
|
||||||
.filter(a => a.metrics.gender === player.gender);
|
|
||||||
if (filteredStandards.length === 0) return {};
|
|
||||||
|
|
||||||
// Age interpolation
|
|
||||||
const ageArray = [...new Set(filteredStandards.map((s) => s.metrics.age))].sort((a, b) => a - b);
|
|
||||||
const { lower: ageLower, upper: ageUpper } = findNearestPoints(player.age, ageArray);
|
|
||||||
|
|
||||||
const lowerValues = interpolateByBodyWeight(ageLower, player.weightKG, filteredStandards);
|
|
||||||
const upperValues = interpolateByBodyWeight(ageUpper, player.weightKG, filteredStandards);
|
|
||||||
if (!lowerValues || !upperValues) return {};
|
|
||||||
|
|
||||||
let ageRatio = ageUpper === ageLower ? 1 : (player.age - ageLower) / (ageUpper - ageLower);
|
|
||||||
ageRatio = Math.max(0, Math.min(1, ageRatio));
|
|
||||||
|
|
||||||
const levels = interpolateStandardsValues(lowerValues, upperValues, ageRatio);
|
|
||||||
|
|
||||||
if (levels) {
|
|
||||||
const expandedLevels = expandLevels(levels, 5);
|
|
||||||
const compressedLevels = compressLevels(expandedLevels, 100);
|
|
||||||
return compressedLevels;
|
return compressedLevels;
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
// Level calculations (public API)
|
|
||||||
// -------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export function calcAttributeLevel(
|
|
||||||
attribute: Attribute,
|
|
||||||
player: Player,
|
|
||||||
activityPerformances: ActivityPerformance[],
|
|
||||||
): number {
|
|
||||||
// must be activities of the given attribute
|
|
||||||
if (activityPerformances.some((bp) => getActivityAttribute(bp.activity) !== attribute)) {
|
|
||||||
throw new Error("Wrong activity performance attribute");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// must perform all of an attributes activities
|
expandLevels(
|
||||||
for (const activity of getAttributeActivities(attribute)) {
|
levels: Levels,
|
||||||
const filteredActivites = activityPerformances.map((bp) => bp.activity);
|
i: number
|
||||||
if (!filteredActivites.includes(activity))
|
): Levels {
|
||||||
return 0;
|
if (i == 0)
|
||||||
|
return levels;
|
||||||
|
|
||||||
|
const newLevels = {};
|
||||||
|
let j = 1;
|
||||||
|
for (let k = 0; k < Object.keys(levels).length; ++k) {
|
||||||
|
const currLevel = Object.keys(levels)[k];
|
||||||
|
const nextLevel = Object.keys(levels)[k + 1];
|
||||||
|
|
||||||
|
newLevels[j++] = levels[currLevel];
|
||||||
|
|
||||||
|
if (nextLevel) {
|
||||||
|
newLevels[j++] = (levels[currLevel] + levels[nextLevel]) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.expandLevels(newLevels, i - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// must have all activties using a valid performance value (> 0)
|
// -------------------------------------------------------------------------------------------------
|
||||||
for (const activityPerformance of activityPerformances) {
|
// Standards interpolation (heavy math bits)
|
||||||
if (activityPerformance.performance <= 0)
|
// -------------------------------------------------------------------------------------------------
|
||||||
return 0
|
|
||||||
|
interpolateLevels(
|
||||||
|
lower: Levels,
|
||||||
|
upper: Levels,
|
||||||
|
ratio: number,
|
||||||
|
): Levels {
|
||||||
|
if (Object.keys(lower).length !== Object.keys(upper).length)
|
||||||
|
throw new Error("Cannot interpolate between varying number of levels");
|
||||||
|
|
||||||
|
function lerp(lvl: number): number {
|
||||||
|
return (lower[lvl] as number) + ((upper[lvl] as number) - (lower[lvl] as number)) * ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
const interpolatedLevels = Object.keys(lower).map(lvl => lerp(+lvl));
|
||||||
|
return interpolatedLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activityLevels = activityPerformances.map((abp) =>
|
interpolateByBodyWeight(
|
||||||
findLevel(interpolateActivityLevels(abp.activity, player), abp.performance),
|
targetAge: number,
|
||||||
);
|
bodyWeightKG: number,
|
||||||
|
standardsArr: Standard[],
|
||||||
|
): Levels | null {
|
||||||
|
const ageFilteredStandards = standardsArr.filter((s) => s.metrics.age === targetAge);
|
||||||
|
if (ageFilteredStandards[0].metrics.weight === -1) return ageFilteredStandards[0].levels;
|
||||||
|
|
||||||
const activityLevelsAvg = Math.round(
|
const weightArray = [...new Set(ageFilteredStandards.map((s) => s.metrics.weight))].sort((a, b) => a - b);
|
||||||
activityLevels.reduce((sum, curr) => sum + curr, 0) / activityLevels.length,
|
const { lower, upper } = findNearestPoints(bodyWeightKG, weightArray);
|
||||||
);
|
|
||||||
|
|
||||||
return activityLevelsAvg;
|
const weightLower = ageFilteredStandards.find((s) => s.metrics.weight === lower);
|
||||||
}
|
const weightUpper = ageFilteredStandards.find((s) => s.metrics.weight === upper);
|
||||||
|
if (!weightLower || !weightUpper) return null;
|
||||||
|
|
||||||
export function calcAllAttributeLevels(
|
let weightRatio = upper === lower ? 1 : (bodyWeightKG - lower) / (upper - lower);
|
||||||
player: Player,
|
weightRatio = Math.max(0, Math.min(1, weightRatio));
|
||||||
activityPerformances: ActivityPerformance[],
|
|
||||||
): Record<Attribute, number> {
|
|
||||||
const attrLevels: Record<Attribute, number> = {
|
|
||||||
[attributes.STRENGTH]: 0,
|
|
||||||
[attributes.POWER]: 0,
|
|
||||||
[attributes.ENDURANCE]: 0,
|
|
||||||
// [attributes.SPEED]: 0,
|
|
||||||
[attributes.AGILITY]: 0,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
for (const value of Object.values(player)) {
|
return this.interpolateLevels(weightLower.levels, weightUpper.levels, weightRatio);
|
||||||
if (!value)
|
|
||||||
return attrLevels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(Object.values(attributes) as Attribute[]).forEach((attribute) => {
|
getInterpolatedActivityStandard(
|
||||||
const attrActivityPerformances = activityPerformances.filter(
|
activity: Activity,
|
||||||
(bp) => getActivityAttribute(bp.activity) === attribute,
|
metrics: Metrics,
|
||||||
|
): Standard {
|
||||||
|
const interpolatedStandard: Standard = {
|
||||||
|
metrics: metrics,
|
||||||
|
levels: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filter dataset
|
||||||
|
const standardsByGender = standards[activity]
|
||||||
|
.filter(a => a.metrics.gender === metrics.gender);
|
||||||
|
if (standardsByGender.length === 0) return interpolatedStandard;
|
||||||
|
|
||||||
|
// Age interpolation
|
||||||
|
const ageArray = [...new Set(standardsByGender.map((s) => s.metrics.age))].sort((a, b) => a - b);
|
||||||
|
const { lower: ageLower, upper: ageUpper } = findNearestPoints(metrics.age, ageArray);
|
||||||
|
|
||||||
|
const lowerValues = this.interpolateByBodyWeight(ageLower, metrics.weight, standardsByGender);
|
||||||
|
const upperValues = this.interpolateByBodyWeight(ageUpper, metrics.weight, standardsByGender);
|
||||||
|
if (!lowerValues || !upperValues) return interpolatedStandard;
|
||||||
|
|
||||||
|
let ageRatio = ageUpper === ageLower ? 1 : (metrics.age - ageLower) / (ageUpper - ageLower);
|
||||||
|
ageRatio = Math.max(0, Math.min(1, ageRatio));
|
||||||
|
|
||||||
|
const levels = this.interpolateLevels(lowerValues, upperValues, ageRatio);
|
||||||
|
const expandedLevels = this.expandLevels(levels, this.cfg.expandIters);
|
||||||
|
const compressedLevels = this.compressLevels(expandedLevels, this.cfg.compressTo);
|
||||||
|
|
||||||
|
interpolatedStandard.levels = compressedLevels;
|
||||||
|
return interpolatedStandard;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// Level calculations (public API)
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// public generateTableData(metrics: Metrics) {
|
||||||
|
// const tableData: Record<Activity, Object> = {};
|
||||||
|
//
|
||||||
|
// for (const activity of Object.values(activities)) {
|
||||||
|
// const activityLevels = this.interpolateActivityLevels(activity, metrics);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public calcAttributeLevel(
|
||||||
|
attribute: Attribute,
|
||||||
|
player: Player,
|
||||||
|
activityPerformances: ActivityPerformance[],
|
||||||
|
): number {
|
||||||
|
// must be activities of the given attribute
|
||||||
|
if (activityPerformances.some((p) => getActivityAttribute(p.activity) !== attribute)) {
|
||||||
|
throw new Error("Wrong activity performance attribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
// must perform all of an attributes activities
|
||||||
|
for (const activity of getAttributeActivities(attribute)) {
|
||||||
|
const filteredActivites = activityPerformances.map((p) => p.activity);
|
||||||
|
if (!filteredActivites.includes(activity))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must have all activties using a valid performance value (> 0)
|
||||||
|
for (const activityPerformance of activityPerformances) {
|
||||||
|
if (activityPerformance.performance <= 0)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const activityLevels = activityPerformances.map((p) => {
|
||||||
|
const interpolatedStandard = this.getInterpolatedActivityStandard(p.activity, player.metrics);
|
||||||
|
return this.findLevel(interpolatedStandard.levels, p.performance);
|
||||||
|
});
|
||||||
|
|
||||||
|
const activityLevelsAvg = Math.round(
|
||||||
|
activityLevels.reduce((sum, curr) => sum + curr, 0) / activityLevels.length,
|
||||||
);
|
);
|
||||||
attrLevels[attribute] = calcAttributeLevel(attribute, player, attrActivityPerformances);
|
|
||||||
});
|
|
||||||
|
|
||||||
return attrLevels;
|
return activityLevelsAvg;
|
||||||
}
|
|
||||||
|
|
||||||
export function calcPlayerLevel(player: Player, activityPerformances: ActivityPerformance[]): number {
|
|
||||||
for (const value of Object.values(player)) {
|
|
||||||
if (!value)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const attrLevels = calcAllAttributeLevels(player, activityPerformances);
|
public calcAllAttributeLevels(
|
||||||
for (const level of Object.values(attrLevels)) {
|
player: Player,
|
||||||
if (!level)
|
activityPerformances: ActivityPerformance[],
|
||||||
return 0;
|
): Record<Attribute, number> {
|
||||||
|
const attrLevels: Record<Attribute, number> = {
|
||||||
|
[attributes.STRENGTH]: 0,
|
||||||
|
[attributes.POWER]: 0,
|
||||||
|
[attributes.ENDURANCE]: 0,
|
||||||
|
// [attributes.SPEED]: 0,
|
||||||
|
[attributes.AGILITY]: 0,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
for (const value of Object.values(player)) {
|
||||||
|
if (!value)
|
||||||
|
return attrLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
(Object.values(attributes) as Attribute[]).forEach((attribute) => {
|
||||||
|
const attrActivityPerformances = activityPerformances.filter(
|
||||||
|
(p) => getActivityAttribute(p.activity) === attribute,
|
||||||
|
);
|
||||||
|
attrLevels[attribute] = this.calcAttributeLevel(attribute, player, attrActivityPerformances);
|
||||||
|
});
|
||||||
|
|
||||||
|
return attrLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
const attrLevelsSum = Object.values(attrLevels).reduce((sum, lvl) => sum + lvl, 0);
|
public calcPlayerLevel(player: Player, activityPerformances: ActivityPerformance[]): number {
|
||||||
return Math.round(attrLevelsSum / Object.keys(attributes).length);
|
for (const value of Object.values(player)) {
|
||||||
}
|
if (!value)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrLevels = this.calcAllAttributeLevels(player, activityPerformances);
|
||||||
|
for (const level of Object.values(attrLevels)) {
|
||||||
|
if (!level)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attrLevelsSum = Object.values(attrLevels).reduce((sum, lvl) => sum + lvl, 0);
|
||||||
|
return Math.round(attrLevelsSum / Object.keys(attributes).length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2070
-2070
File diff suppressed because it is too large
Load Diff
+12
-6
@@ -1,10 +1,12 @@
|
|||||||
import { activities, ActivityPerformance, feetToCm, genders, inchesToCm, lbToKg, minToMs, Player, secToMs } from "./util";
|
import { activities, ActivityPerformance, feetToCm, genders, inchesToCm, lbToKg, minToMs, Player, secToMs } from "./util";
|
||||||
import { calcAllAttributeLevels, calcPlayerLevel } from "./calc.ts";
|
import { LevelCalculator } from "./calc.ts";
|
||||||
|
|
||||||
const player: Player = {
|
const player: Player = {
|
||||||
age: 18,
|
metrics: {
|
||||||
weightKG: lbToKg(200),
|
age: 18,
|
||||||
gender: genders.MALE
|
weight: lbToKg(200),
|
||||||
|
gender: genders.MALE
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const computedPerformances: ActivityPerformance[] = [
|
const computedPerformances: ActivityPerformance[] = [
|
||||||
@@ -38,9 +40,13 @@ const computedPerformances: ActivityPerformance[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
console.log(Bun.argv);
|
||||||
|
// const levelCalculator = new LevelCalculator({ compressTo: +Bun.argv[2], expandIters: +Bun.argv[3] });
|
||||||
|
const levelCalculator = new LevelCalculator();
|
||||||
|
|
||||||
const levels = {
|
const levels = {
|
||||||
attributes: calcAllAttributeLevels(player, computedPerformances),
|
attributes: levelCalculator.calcAllAttributeLevels(player, computedPerformances),
|
||||||
player: calcPlayerLevel(player, computedPerformances)
|
player: levelCalculator.calcPlayerLevel(player, computedPerformances)
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(levels);
|
console.log(levels);
|
||||||
|
|||||||
+4
-11
@@ -16,9 +16,7 @@ export type Attribute = typeof attributes[keyof typeof attributes];
|
|||||||
// -------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
export interface Player {
|
export interface Player {
|
||||||
age: number,
|
metrics: Metrics;
|
||||||
weightKG: number,
|
|
||||||
gender: Gender
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const activities = Object.freeze({
|
export const activities = Object.freeze({
|
||||||
@@ -75,14 +73,9 @@ export interface ActivityPerformance {
|
|||||||
performance: number;
|
performance: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BaseLevel =
|
export type Levels = Record<number, number>
|
||||||
| "physicallyActive"
|
|
||||||
| "beginner"
|
|
||||||
| "intermediate"
|
|
||||||
| "advanced"
|
|
||||||
| "elite";
|
|
||||||
|
|
||||||
interface Metrics {
|
export interface Metrics {
|
||||||
age: number;
|
age: number;
|
||||||
weight: number;
|
weight: number;
|
||||||
gender: Gender;
|
gender: Gender;
|
||||||
@@ -90,7 +83,7 @@ interface Metrics {
|
|||||||
|
|
||||||
export interface Standard {
|
export interface Standard {
|
||||||
metrics: Metrics;
|
metrics: Metrics;
|
||||||
levels: Record<BaseLevel, number>;
|
levels: Levels;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StandardsMap = Record<
|
export type StandardsMap = Record<
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { calcAllAttributeLevels, calcPlayerLevel } from "./calculator/calc.ts";
|
import { LevelCalculator } from "./calculator/calc.ts";
|
||||||
import { ActivityPerformance, Player } from "./calculator/util.ts";
|
import { ActivityPerformance, Player } from "./calculator/util.ts";
|
||||||
import { Printful } from "./commerce/printful.ts"
|
import { Printful } from "./commerce/printful.ts"
|
||||||
import { Webflow } from "./commerce/webflow.ts";
|
import { Webflow } from "./commerce/webflow.ts";
|
||||||
|
|
||||||
interface CalcRequest {
|
interface CalcRequest {
|
||||||
player: Player,
|
player: Player,
|
||||||
performances: ActivityPerformance[]
|
activityPerformances: ActivityPerformance[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClientResponse extends Response {
|
export class ClientResponse extends Response {
|
||||||
@@ -34,12 +34,14 @@ const server = Bun.serve({
|
|||||||
},
|
},
|
||||||
async POST(req) {
|
async POST(req) {
|
||||||
const calcReq: CalcRequest = await req.json();
|
const calcReq: CalcRequest = await req.json();
|
||||||
const { player, performances } = calcReq;
|
const { player, activityPerformances } = calcReq;
|
||||||
|
|
||||||
|
const levelCalculator = new LevelCalculator();
|
||||||
|
|
||||||
return ClientResponse.json({
|
return ClientResponse.json({
|
||||||
levels: {
|
levels: {
|
||||||
attributes: calcAllAttributeLevels(player, performances),
|
attributes: levelCalculator.calcAllAttributeLevels(player, activityPerformances),
|
||||||
player: calcPlayerLevel(player, performances)
|
player: levelCalculator.calcPlayerLevel(player, activityPerformances)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -90,7 +92,8 @@ const server = Bun.serve({
|
|||||||
}
|
}
|
||||||
// DELETE
|
// DELETE
|
||||||
case Printful.Webhook.Event.ProductDeleted: {
|
case Printful.Webhook.Event.ProductDeleted: {
|
||||||
await Webflow.Products.remove(payload.data.sync_product.external_id);
|
const webflowProductId = payload.data.sync_product.external_id;
|
||||||
|
await Webflow.Products.remove(webflowProductId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user