Calculator updates
This commit is contained in:
+63
-33
@@ -1,4 +1,4 @@
|
||||
import { activities, Activity, Attribute, attributes, BenchmarkPerformance, findNearestPoints, Gender, getActivityAttribute, kgToLb, Levels, msToTime, StandardsItem } from "./util";
|
||||
import { Activity, Attribute, attributes, BenchmarkPerformance, findNearestPoints, Gender, getActivityAttribute, getAttributeActivities, kgToLb, Levels, msToTime, Player, StandardsItem } from "./util";
|
||||
import rawStandards from "./standards.json" assert { type: "json" }
|
||||
|
||||
const standards = rawStandards as StandardsItem[];
|
||||
@@ -35,10 +35,24 @@ export const calcAttributeLevel = (
|
||||
attribute: Attribute,
|
||||
benchmarkPerformances: BenchmarkPerformance[],
|
||||
): number => {
|
||||
// must be activities of the given attribute
|
||||
if (benchmarkPerformances.some((bp) => getActivityAttribute(bp.activity) !== attribute)) {
|
||||
throw new Error("Wrong benchmark performance attribute");
|
||||
}
|
||||
|
||||
// must perform all of an attributes activities
|
||||
for (const activity of getAttributeActivities(attribute)) {
|
||||
const benchmarkActivites = benchmarkPerformances.map((bp) => bp.activity);
|
||||
if (!benchmarkActivites.includes(activity))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// must have all benchmarks using a valid performance value (> 0)
|
||||
for (const benchmarkPerformance of benchmarkPerformances) {
|
||||
if (benchmarkPerformance.performance <= 0)
|
||||
return 0
|
||||
}
|
||||
|
||||
const benchmarkLevels = benchmarkPerformances.map((abp) =>
|
||||
calcBenchmarkLevel(abp.performance, abp.levels),
|
||||
);
|
||||
@@ -51,16 +65,22 @@ export const calcAttributeLevel = (
|
||||
};
|
||||
|
||||
export const calcAttributeLevels = (
|
||||
player: Player,
|
||||
benchmarkPerformances: BenchmarkPerformance[],
|
||||
): Record<Attribute, number> => {
|
||||
const attrLevels: Record<Attribute, number> = {
|
||||
[attributes.STRENGTH]: 1,
|
||||
[attributes.POWER]: 1,
|
||||
[attributes.ENDURANCE]: 1,
|
||||
[attributes.SPEED]: 1,
|
||||
[attributes.AGILITY]: 1,
|
||||
[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 attrBenchmarkPerformances = benchmarkPerformances.filter(
|
||||
(bp) => getActivityAttribute(bp.activity) === attribute,
|
||||
@@ -71,8 +91,18 @@ export const calcAttributeLevels = (
|
||||
return attrLevels;
|
||||
};
|
||||
|
||||
export const calcPlayerLevel = (benchmarkPerformances: BenchmarkPerformance[]): number => {
|
||||
const attrLevels = calcAttributeLevels(benchmarkPerformances);
|
||||
export const calcPlayerLevel = (player: Player, benchmarkPerformances: BenchmarkPerformance[]): number => {
|
||||
for (const value of Object.values(player)) {
|
||||
if (!value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const attrLevels = calcAttributeLevels(player, benchmarkPerformances);
|
||||
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);
|
||||
};
|
||||
@@ -80,31 +110,31 @@ export const calcPlayerLevel = (benchmarkPerformances: BenchmarkPerformance[]):
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Presentation helpers
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
export const formatLevelValues = (
|
||||
levels: Record<number, number>,
|
||||
activity: Activity,
|
||||
): Record<number, string> => {
|
||||
const timedActivities: Activity[] = [activities.RUN, activities.DASH, activities.CONE_DRILL];
|
||||
|
||||
const formattedLevels: Record<number, string> = {};
|
||||
for (const level in levels) {
|
||||
const lvl = +level as number;
|
||||
let displayValue = "";
|
||||
if (timedActivities.includes(activity)) {
|
||||
displayValue = msToTime(levels[lvl]);
|
||||
} else if (activity === activities.TREADMILL_DASH) {
|
||||
displayValue = `${(levels[lvl] * 1000).toFixed(2)} m/s`;
|
||||
} else if (activity === activities.BROAD_JUMP) {
|
||||
displayValue = `${(levels[lvl] * 0.0328084).toFixed(2)} ft.`;
|
||||
} else {
|
||||
displayValue = kgToLb(levels[lvl]).toFixed(0);
|
||||
}
|
||||
|
||||
formattedLevels[lvl] = displayValue;
|
||||
}
|
||||
|
||||
return formattedLevels;
|
||||
};
|
||||
// export const formatLevelValues = (
|
||||
// levels: Record<number, number>,
|
||||
// activity: Activity,
|
||||
// ): Record<number, string> => {
|
||||
// const timedActivities: Activity[] = [activities.RUN, activities.DASH, activities.CONE_DRILL];
|
||||
//
|
||||
// const formattedLevels: Record<number, string> = {};
|
||||
// for (const level in levels) {
|
||||
// const lvl = +level as number;
|
||||
// let displayValue = "";
|
||||
// if (timedActivities.includes(activity)) {
|
||||
// displayValue = msToTime(levels[lvl]);
|
||||
// } else if (activity === activities.TREADMILL_DASH) {
|
||||
// displayValue = `${(levels[lvl] * 1000).toFixed(2)} m/s`;
|
||||
// } else if (activity === activities.BROAD_JUMP) {
|
||||
// displayValue = `${(levels[lvl] * 0.0328084).toFixed(2)} ft.`;
|
||||
// } else {
|
||||
// displayValue = kgToLb(levels[lvl]).toFixed(0);
|
||||
// }
|
||||
//
|
||||
// formattedLevels[lvl] = displayValue;
|
||||
// }
|
||||
//
|
||||
// return formattedLevels;
|
||||
// };
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Level utilities
|
||||
|
||||
+39
-22
@@ -1,6 +1,26 @@
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Attributes
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
export const attributes = Object.freeze({
|
||||
STRENGTH: "Strength",
|
||||
POWER: "Power",
|
||||
ENDURANCE: "Endurance",
|
||||
// SPEED: "Speed",
|
||||
AGILITY: "Agility",
|
||||
} as const);
|
||||
export type Attribute = typeof attributes[keyof typeof attributes];
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Enumerations & basic value objects
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
export interface Player {
|
||||
age: number,
|
||||
weightKG: number,
|
||||
gender: Gender
|
||||
}
|
||||
|
||||
export const activities = Object.freeze({
|
||||
BACK_SQUAT: "Back Squat",
|
||||
DEADLIFT: "Deadlift",
|
||||
@@ -14,30 +34,10 @@ export const activities = Object.freeze({
|
||||
|
||||
export type Activity = typeof activities[keyof typeof activities];
|
||||
|
||||
export const genders = Object.freeze({
|
||||
MALE: "male",
|
||||
FEMALE: "female",
|
||||
} as const);
|
||||
export type Gender = typeof genders[keyof typeof genders];
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Attributes
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
export const attributes = Object.freeze({
|
||||
STRENGTH: "Strength",
|
||||
POWER: "Power",
|
||||
ENDURANCE: "Endurance",
|
||||
SPEED: "Speed",
|
||||
AGILITY: "Agility",
|
||||
} as const);
|
||||
export type Attribute = typeof attributes[keyof typeof attributes];
|
||||
|
||||
export const getActivityAttribute = (activity: Activity): Attribute => {
|
||||
const activityAttrMap: Record<Activity, Attribute> = {
|
||||
[activities.RUN]: attributes.ENDURANCE,
|
||||
[activities.TREADMILL_DASH]: attributes.SPEED,
|
||||
[activities.DASH]: attributes.SPEED,
|
||||
// [activities.TREADMILL_DASH]: attributes.SPEED,
|
||||
// [activities.DASH]: attributes.SPEED,
|
||||
[activities.DEADLIFT]: attributes.STRENGTH,
|
||||
[activities.BACK_SQUAT]: attributes.STRENGTH,
|
||||
[activities.BENCH_PRESS]: attributes.STRENGTH,
|
||||
@@ -45,11 +45,28 @@ export const getActivityAttribute = (activity: Activity): Attribute => {
|
||||
[activities.CONE_DRILL]: attributes.AGILITY,
|
||||
} as const;
|
||||
|
||||
export const getActivityAttribute = (activity: Activity): Attribute => {
|
||||
const attribute = activityAttrMap[activity];
|
||||
if (!attribute) throw new Error(`${activity} does not have an associated attribute`);
|
||||
return attribute;
|
||||
};
|
||||
|
||||
export const getAttributeActivities = (attribute: Attribute): Activity[] => {
|
||||
const activities: Activity[] = [];
|
||||
for (const activity in activityAttrMap) {
|
||||
if (activityAttrMap[activity] === attribute) {
|
||||
activities.push(activity as Activity);
|
||||
}
|
||||
}
|
||||
return activities;
|
||||
}
|
||||
|
||||
export const genders = Object.freeze({
|
||||
MALE: "male",
|
||||
FEMALE: "female",
|
||||
} as const);
|
||||
export type Gender = typeof genders[keyof typeof genders];
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// Data model interfaces
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { calcAttributeLevels, calcPlayerLevel, computeLevels } from "./calculator/calc.ts";
|
||||
import { Activity, BenchmarkPerformance, Gender } from "./calculator/util.ts";
|
||||
import { Activity, BenchmarkPerformance, Player } from "./calculator/util.ts";
|
||||
import { productRecords } from "./commerce/product-records.ts";
|
||||
import { Printful } from "./commerce/printful.ts"
|
||||
import { Webflow } from "./commerce/webflow.ts";
|
||||
|
||||
interface CalcRequest {
|
||||
player: {
|
||||
age: number,
|
||||
weightKG: number,
|
||||
gender: Gender
|
||||
}
|
||||
player: Player,
|
||||
performances: {
|
||||
activity: Activity,
|
||||
performance: number,
|
||||
@@ -59,8 +55,8 @@ const server = Bun.serve({
|
||||
|
||||
return ClientResponse.json({
|
||||
levels: {
|
||||
attributes: calcAttributeLevels(computedPerformances),
|
||||
player: calcPlayerLevel(computedPerformances)
|
||||
attributes: calcAttributeLevels(player, computedPerformances),
|
||||
player: calcPlayerLevel(player, computedPerformances)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user