Created
March 21, 2019 02:42
-
-
Save ericbmerritt/d37d3b6eb8e6f8a0a146388258c7802c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import loglevel from 'loglevel'; | |
import { gaussian, randomBetweenMinAndMax } from './random-utils'; | |
interface IPeriodEntry { | |
calories: number; | |
workout: boolean; | |
} | |
interface ISimEntry { | |
correctnessFactor: number; | |
period: IPeriodEntry[]; | |
} | |
interface IConfig { | |
periodLength: number; | |
fastingDays: number; | |
targetWorkoutDays: number; | |
simulationCount: number; | |
dailyTargetCalories: number; | |
} | |
const selectPeriodDays = ( | |
targetDays: number, | |
periodLength: number | |
): number[] => { | |
const realizedTarget = Math.floor(gaussian(targetDays, targetDays)()); | |
if (realizedTarget < 1) { | |
return []; | |
} else { | |
return Array(realizedTarget) | |
.fill(false) | |
.map(() => randomBetweenMinAndMax(1, periodLength) - 1); | |
} | |
}; | |
const generatePeriodWorkouts = (config: IConfig): number[] => | |
selectPeriodDays(config.targetWorkoutDays, config.periodLength); | |
const generatePeriodFastingDays = (config: IConfig): number[] => | |
selectPeriodDays(config.fastingDays, config.periodLength); | |
const generatePeriodCalories = (config: IConfig): number[] => { | |
// make a standard gaussian variable. | |
const standardDistribution = gaussian( | |
config.dailyTargetCalories, | |
config.dailyTargetCalories | |
); | |
return Array(config.periodLength) | |
.fill(0) | |
.map(() => Math.floor(standardDistribution())); | |
}; | |
const sumPeriodCalories = (week: IPeriodEntry[]): number => | |
week.reduce((acc, current) => acc + current.calories, 0); | |
const sumPeriodWorkouts = (week: IPeriodEntry[]): number => | |
week.reduce((acc, current) => { | |
if (current.workout) { | |
return acc + 1; | |
} else { | |
return acc; | |
} | |
}, 0); | |
const mergeFastingAndWorkouts = ( | |
calories: number[], | |
fastingDays: number[], | |
workoutDays: number[] | |
): IPeriodEntry[] => { | |
return calories.map( | |
(caloriesInstance: number, index: number): IPeriodEntry => { | |
const calIntstanceFastAdjusted = fastingDays.includes(index) | |
? 0 | |
: caloriesInstance; | |
const workout = workoutDays.includes(index); | |
return { calories: calIntstanceFastAdjusted, workout }; | |
} | |
); | |
}; | |
const generatePeriodWithMetadata = ( | |
config: IConfig, | |
periodTarget: number | |
): ISimEntry => { | |
const periodCalories = generatePeriodCalories(config); | |
const fastingDays = generatePeriodFastingDays(config); | |
const periodWorkouts = generatePeriodWorkouts(config); | |
const period = mergeFastingAndWorkouts( | |
periodCalories, | |
fastingDays, | |
periodWorkouts | |
); | |
const workoutDiff = Math.abs( | |
config.targetWorkoutDays - sumPeriodWorkouts(period) | |
); | |
const calorieDiff = Math.abs(periodTarget - sumPeriodCalories(period)); | |
return { | |
correctnessFactor: workoutDiff + calorieDiff, | |
period | |
}; | |
}; | |
const generatePeriodSimulations = (config: IConfig): ISimEntry[] => { | |
const periodTarget = config.dailyTargetCalories * config.periodLength; | |
const periods = []; | |
for (let i = 0; i < config.simulationCount; i++) { | |
periods.push(generatePeriodWithMetadata(config, periodTarget)); | |
} | |
return periods; | |
}; | |
const main = (config: IConfig) => { | |
const sims = generatePeriodSimulations(config); | |
const result = sims.reduce( | |
(p: ISimEntry, c: ISimEntry): ISimEntry => { | |
if (p.correctnessFactor < c.correctnessFactor) { | |
return p; | |
} else { | |
return c; | |
} | |
} | |
); | |
loglevel.error(JSON.stringify(result, null, 2)); | |
}; | |
main({ | |
dailyTargetCalories: 1800, | |
fastingDays: 2, | |
periodLength: 7, | |
simulationCount: 10000, | |
targetWorkoutDays: 5 | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment