Yeoram's Project Guide
Project: Workout Weight Calculator Category: Data Science / CLI Last updated: April 18
Note: This guide reflects the latest state of your project repo. It may not match the most up-to-date version if you've worked since.
Where You Are
Clean starting slice: your main.py asks for a 1RM and returns a hypertrophy weight range. Code is short and readable. pyproject.toml is set up.
Your Checkpoint 1 journal asked a great question: "should the input be in main or in a function?" → In a function. That way the math is reusable and testable. main() just orchestrates: ask → call → print. Your existing calculate_hypertrophy_weight() is already in its own function — good.
This week: move your calculators into a weights.py business-logic module, add strength + endurance, and harden the input handling.
Project Structure
Your project splits into two kinds of code:
- Business logic — you handwrite this. The weight-range formulas, rep-range rules, valid-goal definitions. This is the "exercise science" of your tool.
- View / CLI — agent-assisted is fine. Pretty menu printing, number formatting. Nothing about workouts happens in view code.
Target layout by Thursday:
workout-weight-calculator/
├── main.py ← CLI driver (menu, input) — mostly yours, some agent-assisted
├── weights.py ← business logic — handwrite (yours to own)
└── pyproject.toml
Why the split? On demo day you'll be asked "why is the strength range 85–100%?" The answer lives in weights.py as a named constant or a function. The print formatting doesn't make it into the answer.
weights.py should not call input() or print(). It's pure math + data. main.py handles all user interaction.
Phase 1: Move the Calculator Into weights.py
Handwrite this yourself. These formulas are your project. Even the constants (65%, 85%, 100%) are real exercise-science decisions you're making.
Objective
Create weights.py, move your existing hypertrophy function into it, and add strength + endurance.
Instructions
Reference Ranges
| Goal | Weight (% of 1RM) | Reps |
|---|---|---|
| Strength | 85–100% | 3–5 |
| Hypertrophy | 65–85% | 6–12 |
| Endurance | 50–65% | 12–20 |
Hints
Pattern for one calculator:
def calculate_strength_weight(one_rm):
low = one_rm * 0.85
high = one_rm * 1.00
return low, high
Optional but nice — define the rep ranges as constants in weights.py:
GOAL_REPS = {
"strength": "3-5",
"hypertrophy": "6-12",
"endurance": "12-20",
}
Now the rep ranges have a single home — if you change one, you change it once.
Write the endurance function yourself. It mirrors strength exactly.
Optional — get help from your agent:
Skip — these are three small mirror functions you can write yourself.
Phase 3: Show Recommended Reps
Agent-assisted is fine here. Formatted output is print code.
Objective
Your spec says "display recommended weight and reps". The data is already there — just print it.
Instructions
Hints
print(f"\nRecommended weight for {goal_name}: {low:.1f} - {high:.1f} lbs")
print(f"Recommended reps: {reps}")
The .1f keeps one decimal place so you don't see 170.000000001.
Phase 4: Handle Bad Input Without Crashing
Handwrite this yourself. "Keep asking until the user gives valid input" is a common loop pattern. You'll use it again in future projects.
Objective
If the user types "abc" for 1RM, or "5" for the goal choice, the program currently crashes. Add loops that re-ask until the answer is valid.
Instructions
Sample Output
Enter 1, 2, or 3: 9
Please enter 1, 2, or 3.
Enter 1, 2, or 3: 2
Enter your 1RM (max weight): abc
That's not a number. Try again.
Enter your 1RM (max weight): -10
Please enter a positive number.
Enter your 1RM (max weight): 200
Hints
"Ask until valid number" pattern:
def prompt_for_number(message):
while True:
raw = input(message).strip()
try:
n = float(raw)
except ValueError:
print("That's not a number. Try again.")
continue
if n <= 0:
print("Please enter a positive number.")
continue
return n
"Ask until in a set" pattern:
def prompt_for_choice(message, valid):
while True:
choice = input(message).strip()
if choice in valid:
return choice
print(f"Please enter {' or '.join(sorted(valid))}.")
These belong in main.py (they're about input), not weights.py (which is about math).
Optional — get help from your agent:
Walk me through why I need try/except ValueError to convert input to a number. What happens if I just do float(input(...)) with "abc"? Don't change my code — I want to check my understanding.