Created
July 19, 2020 20:46
-
-
Save kdeloach/1d38913883fe355fa131a4757703ca43 to your computer and use it in GitHub Desktop.
Calculate plate orderings for 531 workout
This file contains hidden or 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
bar = 45 | |
plates = [45, 35, 25, 10, 10, 5, 5, 2.5] | |
min_weight = bar | |
max_weight = bar + int(sum(plates) * 2) | |
def calculate_perms(plates): | |
result = set() | |
for i in range(len(plates)): | |
result.add(tuple([plates[i]])) | |
perms = calculate_perms(plates[:i] + plates[i + 1 :]) | |
for tup in perms: | |
result.add(tuple([plates[i]]) + tup) | |
return result | |
# Calculate all possible plate orderings | |
perms = calculate_perms(plates) | |
# Sort each tuple by descending order and filter duplicates to reduce permutation space | |
perms = set([tuple(sorted(tup, key=lambda n: -n)) for tup in perms]) | |
# Group plate orderings by weight (how many different ways can you arrange | |
# the plates to equal some weight) in 5 lbs increments | |
perms_by_weight = {} | |
for weight in range(min_weight, max_weight + 1, 5): | |
perms_by_weight[weight] = [tup for tup in perms if sum(tup) * 2 + bar == weight] | |
# Hack to support lifting empty bar | |
perms_by_weight[bar] = [("-",)] | |
def plate_change_score(a, b): | |
""" | |
Return score of changing from plates a to b based on number of | |
additions and removals. | |
""" | |
# Find largest common prefix | |
prefix = 0 | |
size = min(len(a), len(b)) | |
for i in range(size): | |
if a[i] == b[i]: | |
prefix += 1 | |
else: | |
break | |
# Base score (from adding plates) | |
score = len(b) - prefix | |
# Penalize removing plates | |
score += (len(a) - prefix) * 2 | |
return score | |
def generate_plans(weights, parent_plates=[], score=0): | |
""" | |
Return all possible plate combinations for a progression of weights | |
along with a score. | |
Ex. | |
generate_plans([45]) | |
[ | |
[(45,), 0]], | |
] | |
generate_plans([45, 55]) | |
[ | |
[(45,), (45, 10), 1], | |
[(45,), (45, 5, 5), 2], | |
] | |
""" | |
if not weights: | |
return [[score]] | |
perms = perms_by_weight[weights[0]] | |
result = [] | |
for t1 in perms: | |
new_score = score + plate_change_score(parent_plates, t1) | |
sub_plans = generate_plans(weights[1:], parent_plates=t1, score=new_score) | |
for lst in sub_plans: | |
result.append([t1] + lst) | |
return result | |
def find_best_plan(weights): | |
""" | |
Return highest rank plan. | |
""" | |
plans = generate_plans(weights) | |
plans = sorted(plans, key=lambda lst: lst[-1]) | |
best = plans[0] | |
best.pop(-1) # remove score | |
return best | |
def round_to_nearest(n, increment): | |
return increment * round(n / increment) | |
lifts = { | |
"Squat": {"repmax": 175}, | |
"Bench": {"repmax": 130}, | |
"Deadlift": {"repmax": 211}, | |
"Press": {"repmax": 83}, | |
} | |
for lift in lifts.values(): | |
lift["training_max"] = round(lift["repmax"] * 0.9) | |
for week in range(3): | |
extra_perc = week * 0.05 | |
week_percs = [ | |
0.4, | |
0.5, | |
0.6, | |
0.65 + extra_perc, | |
0.75 + extra_perc, | |
0.85 + extra_perc, | |
0.65 + extra_perc, | |
] | |
for lift_name, lift in lifts.items(): | |
tm = lift["training_max"] | |
weights = [max(bar, round_to_nearest(tm * w, 5)) for w in week_percs] | |
print(f"Week {week + 1} {lift_name}") | |
warmup_plan = find_best_plan(weights[:3]) | |
rep_plan = find_best_plan(weights[3:]) | |
plans = warmup_plan + rep_plan | |
for perc, weight, plates in zip(week_percs, weights, plans): | |
print(f"{perc:0.0%}\t{weight}\t{', '.join(str(n) for n in plates)}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment