58 lines
3.7 KiB
Python
58 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate immutable C data from the canonical session-generation policy."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from validate_session_generation_policy import validate
|
|
|
|
|
|
def c_string(value: str) -> str:
|
|
escaped = value.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
|
|
return f'"{escaped}"'
|
|
|
|
|
|
def main() -> None:
|
|
policy_path, catalog_dir, output_path = map(Path, sys.argv[1:4])
|
|
root = validate(policy_path, catalog_dir)
|
|
lines = [
|
|
"/* Generated from session-generation-policy-v1.json; do not edit. */",
|
|
'#include "trainlog/session_generation_policy_internal.h"',
|
|
"static const TrainlogSessionGenerationGoalPolicy goal_policies[] = {",
|
|
]
|
|
for goal in ("general", "strength", "hypertrophy", "endurance"):
|
|
row = root["goals"][goal]
|
|
lines.append(" {%s,%d,%d,%d,%d,%d,%d,%d,%d,%d}," % (
|
|
c_string(goal), row["sets"], row["repetitions"], row["rest_seconds"],
|
|
*row["sets_range"], *row["repetitions_range"], *row["rest_seconds_range"]))
|
|
lines += ["};", "static const int duration_presets_minutes[] = {" +
|
|
",".join(str(value) for value in root["duration"]["presets_minutes"]) + "};",
|
|
"static const TrainlogSessionGenerationZoneExpansion zone_expansions[] = {"]
|
|
for zone_id, expanded in root["zone_expansion"].items():
|
|
lines.append(" {%s,%s}," % (c_string(zone_id), c_string("\n".join(expanded))))
|
|
lines += ["};", "const TrainlogSessionGenerationPolicy trainlog_session_generation_policy_v1 = {",
|
|
f" {root['load']['lookback_seconds']},",
|
|
f" {root['exposure']['short_window_seconds']}, {root['exposure']['long_window_seconds']},",
|
|
f" {root['selection']['recency']['same_exercise_window_seconds']}, {root['selection']['recency']['same_pattern_window_seconds']},",
|
|
f" {root['selection']['max_exercises']}, {root['duration']['custom_min_minutes']}, {root['duration']['custom_max_minutes']},",
|
|
" duration_presets_minutes, sizeof(duration_presets_minutes)/sizeof(duration_presets_minutes[0]),",
|
|
f" {root['duration']['preparation_seconds']}, {root['duration']['setup_and_transition_seconds_per_exercise']}, {root['duration']['estimated_seconds_per_repetition']},",
|
|
f" {root['exposure']['recent_primary_sets_24h_threshold']}, {root['exposure']['recent_secondary_sets_24h_threshold']},",
|
|
f" {root['exposure']['repeated_primary_sets_72h_threshold']}, {root['exposure']['repeated_secondary_sets_72h_threshold']},",
|
|
" {" + ",".join(str(root["selection"]["score"][key]) for key in (
|
|
"requested_primary_zone", "requested_secondary_zone_only", "new_primary_zone", "new_pattern",
|
|
"qualifying_working_load_history", "preferred_exercise", "recent_same_exercise", "recent_same_pattern",
|
|
"recent_primary_threshold_on_candidate_primary", "recent_secondary_threshold_on_candidate_primary",
|
|
"repeated_primary_threshold_on_candidate_primary", "repeated_secondary_threshold_on_candidate_primary",
|
|
"any_exposure_flag_on_candidate_secondary_zones")) + "},",
|
|
" " + ",".join(c_string("\n".join(root["selection"][key])) for key in (
|
|
"upper_push_patterns", "upper_pull_patterns", "lower_extension_patterns", "lower_flexion_patterns")) + ",",
|
|
" zone_expansions, sizeof(zone_expansions)/sizeof(zone_expansions[0]),",
|
|
" goal_policies, sizeof(goal_policies)/sizeof(goal_policies[0])", "};"]
|
|
output_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|