UNPKG

ski-din-calculator

Version:

Calculate a skier's DIN binding release value based on height, weight, age, skill level, and boot sole length

152 lines (151 loc) 6.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateDIN = calculateDIN; exports.lookupDIN = lookupDIN; const din_lookup_1 = require("./din-lookup"); const errors_1 = require("./errors"); /** * Calculates the DIN binding release value for a skier based on their physical characteristics and skiing style. * * @param skierHeightCm - Skier's height in centimeters (1-250) * @param skierWeightKg - Skier's weight in kilograms (1-150) * @param skierAge - Skier's age in years (3-100) * @param skierType - Skiing style: 1 (Cautious), 2 (Moderate), 3 (Aggressive) * @param bootSoleLengthMm - Boot sole length in millimeters (200-360) * @returns DIN calculation result or null if no matching entry found * @throws {InvalidHeightError} When height is outside valid range * @throws {InvalidWeightError} When weight is outside valid range * @throws {InvalidAgeError} When age is outside valid range * @throws {InvalidSkierTypeError} When skier type is not 1, 2, or 3 * @throws {InvalidBootSoleLengthError} When boot sole length is outside valid range */ function calculateDIN(skierHeightCm, skierWeightKg, skierAge, skierType, bootSoleLengthMm) { // Input validation if (skierHeightCm <= 0 || skierHeightCm > 250) { throw new errors_1.InvalidHeightError(skierHeightCm); } if (skierWeightKg <= 0 || skierWeightKg > 150) { throw new errors_1.InvalidWeightError(skierWeightKg); } if (skierAge < 3 || skierAge > 100) { throw new errors_1.InvalidAgeError(skierAge); } if (skierType < 1 || skierType > 3) { throw new errors_1.InvalidSkierTypeError(skierType); } if (bootSoleLengthMm < 200 || bootSoleLengthMm > 360) { throw new errors_1.InvalidBootSoleLengthError(bootSoleLengthMm); } // 1. Determine skier code based on height and weight const weightCode = getWeightCode(skierWeightKg); const heightCode = getHeightCode(skierHeightCm, skierWeightKg); // Weight code determined: weightCode = ${weightCode} for ${skierWeightKg}kg // Take the lower of the weightCode and heightCode for DIN chart lookup (closest to the top of the chart) let skierCode = Math.min(weightCode, heightCode); // Ensure the skier code is at least 1 skierCode = adjustSkierCodeForAgeAndSkill(skierAge, skierType, skierCode); // Ensure the adjusted skier code does not go below 1 skierCode = Math.max(1, skierCode); // 4. Get DIN value using the lookup table return lookupDIN(skierCode, bootSoleLengthMm); } // Adjusts skier code based on age and skill level function adjustSkierCodeForAgeAndSkill(skierAge, skierType, skierCode) { let adjustedSkierCode = skierCode; // Adjust for skill level (beginner reduces the code, aggressive increases it) if (skierType === 2) { adjustedSkierCode += 1; // Beginner } else if (skierType === 3) { adjustedSkierCode += 2; // Advanced/Expert (more aggressive) } // Adjust for age if (skierAge < 10 || skierAge > 50) { adjustedSkierCode -= 1; } // Return the adjusted skier code, ensuring it does not drop below 1 return Math.max(1, adjustedSkierCode); } // Helper function to get weight code based on skier weight function getWeightCode(weightKg) { if (weightKg < 13) return 1; // Skier Code A if (weightKg <= 17) return 2; // Skier Code B if (weightKg <= 21) return 3; // Skier Code C if (weightKg <= 25) return 4; // Skier Code D if (weightKg <= 30) return 5; // Skier Code E if (weightKg <= 35) return 6; // Skier Code F if (weightKg <= 41) return 7; // Skier Code G if (weightKg <= 48) return 8; // Skier Code H if (weightKg <= 57) return 9; // Skier Code I if (weightKg <= 66) return 10; // Skier Code J if (weightKg <= 78) return 11; // Skier Code K if (weightKg <= 94) return 12; // Skier Code L and above return 13; } // Helper function to get height code based on skier height (only applicable for skier codes H to M) // Helper function to get height code based on skier height (only applicable for skier codes H to M) function getHeightCode(heightCm, weightKg) { // Only apply height logic if weight exceeds 41 kg if (weightKg > 41) { if (heightCm <= 148) return 8; // Skier Code H (for ≤ 4'10") if (heightCm <= 157) return 9; // Skier Code I if (heightCm <= 166) return 10; // Skier Code J if (heightCm <= 178) return 11; // Skier Code K if (heightCm <= 194) return 12; // Skier Code L if (heightCm >= 195) return 13; // Skier Code M } return 50; // If weight is less than 41 kg, height is not considered, so return an invalid height code } /** * Looks up DIN value based on skier code and boot sole length. * * @param skierCode - Numeric skier code (1-16) * @param bootSoleLengthMm - Boot sole length in millimeters * @returns DIN result or null if no matching entry found */ function lookupDIN(skierCode, bootSoleLengthMm) { // Convert skierCode from number to its corresponding letter const skierCodeLetter = convertToLetterSkierCode(skierCode); // Find matching entry in the lookup table const matchingEntry = din_lookup_1.dinLookupTable.find(entry => entry.skierCode === skierCodeLetter && bootSoleLengthMm >= entry.bootSoleRange[0] && bootSoleLengthMm <= entry.bootSoleRange[1]); // If no matching entry is found, return null or throw an error as needed if (!matchingEntry) { return null; } // Return the DIN value and additional information directly from the lookup table return { skierCode: matchingEntry.skierCode, dinValue: matchingEntry.dinValue, twistRange: matchingEntry.twistRange, forwardLeanRange: matchingEntry.forwardLeanRange, torqueRange: matchingEntry.twistRange, // Using twistRange as torqueRange for now originalSkierCode: skierCode, safetyWarning: matchingEntry.dinValue > 10 ? "Consult an expert for aggressive skiing conditions" : "", suggestedRecheckInterval: "Recheck annually or after weight change of 10%" }; } // Convert numeric skier code to a letter-based skier code function convertToLetterSkierCode(skierCode) { const skierCodes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P']; return skierCodes[Math.max(0, skierCode - 1)]; // Ensures we stay within bounds of the skierCodes array }