> Source URL: /unit-3/project-paths/yeoram-k/yeoram-k-2026-04-18.guide
# 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

- [ ] Create `weights.py` at the project root
- [ ] Move `calculate_hypertrophy_weight(one_rm)` from `main.py` into it
- [ ] Add `calculate_strength_weight(one_rm)` — 85–100% of 1RM
- [ ] Add `calculate_endurance_weight(one_rm)` — 50–65% of 1RM
- [ ] Keep each function small and focused — math only, no printing

### 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:**

```python
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`:**

```python
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 2: Goal-Selection Menu

> **Mixed phase.** The *decision* about what counts as a valid choice (1/2/3) is yours. The *print formatting* is just library code.

### Objective

Let the user pick a goal, then call the matching calculator.

### Instructions

- [ ] In `main()`, print a menu of goals before asking for 1RM
- [ ] Read the user's choice
- [ ] Based on the choice, call the matching function from `weights.py`
- [ ] Print the result

### Sample Output

```
Workout Weight Calculator

What is your goal?
  1. Strength (max effort, low reps)
  2. Hypertrophy (muscle building)
  3. Endurance (high reps)
Enter 1, 2, or 3: 2

Enter your 1RM (max weight): 200
Recommended weight for Hypertrophy: 130.0 - 170.0 lbs
Recommended reps: 6-12
```

### Hints

**Read the menu choice:**

```python
print("What is your goal?")
print("  1. Strength (max effort, low reps)")
print("  2. Hypertrophy (muscle building)")
print("  3. Endurance (high reps)")
choice = input("Enter 1, 2, or 3: ").strip()
```

**Dispatch with if/elif (business logic — yours):**

```python
from weights import (
    calculate_strength_weight,
    calculate_hypertrophy_weight,
    calculate_endurance_weight,
    GOAL_REPS,
)

if choice == "1":
    low, high = calculate_strength_weight(one_rm)
    goal_name = "Strength"
    reps = GOAL_REPS["strength"]
elif choice == "2":
    low, high = calculate_hypertrophy_weight(one_rm)
    goal_name = "Hypertrophy"
    reps = GOAL_REPS["hypertrophy"]
elif choice == "3":
    low, high = calculate_endurance_weight(one_rm)
    goal_name = "Endurance"
    reps = GOAL_REPS["endurance"]
```

> **Optional — get help from your agent:**
>
> ```text
> My dispatch block has three if/elif branches that look similar.
> Walk me through whether I should simplify with a dict lookup instead.
> Show me both versions. Don't change my code yet.
> ```

---

## 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

- [ ] Add one print line for the rep range
- [ ] Format the weight numbers to 1 decimal place

### Hints

```python
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

- [ ] Wrap the 1RM input in a loop that only accepts a positive number
- [ ] Wrap the goal choice in a loop that only accepts `1`, `2`, or `3`
- [ ] Consider moving these to helper functions in `main.py` — e.g. `prompt_for_number(message)` and `prompt_for_choice(message, valid)`

### 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:**

```python
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:**

```python
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:**
>
> ```text
> 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.
> ```

---

## Checkpoint 2 Readiness

By Thursday April 23 at 3pm:

- [ ] `weights.py` exists with three calculator functions + `GOAL_REPS`
- [ ] `weights.py` does **not** call `input()` or `print()`
- [ ] User picks a goal from a menu at the start
- [ ] Output shows weight range AND rep range
- [ ] Bad input (non-numbers, invalid choice) doesn't crash
- [ ] Checkpoint 2 entry in `project.journal.md`
- [ ] Committed and pushed

## Helpful Resources

- [Checkpoint 2 Instructions](../../projects/final-project-checkpoint-2.project.md)
- [Lecture 1: The MVP](../../lectures/01-the-mvp/01-the-mvp.lecture.md)
- [Data Science Setup Guide](../../resources/data-science-setup.guide.md)


---

## Backlinks

The following sources link to this document:

- [April 18 -- Checkpoint 2 (Working MVP)](/unit-3/project-paths/yeoram-k/yeoram-k.path.llm.md)
