Trainerflow Docs trainerflow.com
Examples › An assessment

Examples

An assessment

A program that gets to know the athlete first, with a questionnaire and a short test, and then picks the training that suits them.

So far our programs have known everything up front: the exercises, the weights, the number of sessions. A trainer meeting someone new would not work like that. They would first ask a few questions, maybe watch the person move, and only then decide what to do. In this example we will write a program that does the same.

This is what we are building:

Step What happens
Questions The athlete tells us their age, body weight and how active they are.
Goal We ask what they want from the next four weeks: to get stronger or to build endurance.
Test As many bodyweight squats as they can do with good form.
Training Four weeks, three sessions a week, of squats and push-ups, chosen from the answers.

Athletes who are not very active, or who could not do 20 squats in the test, start with bodyweight squats. Everyone else squats with a dumbbell, at a weight worked out from their body weight. The goal decides the reps.

Process

Imports

import "coach/common/rest.cl"
import "coach/athlete.cl" as athlete
import "coach/strength/squat.cl"
import "coach/strength/push.cl"

The athlete library has ready-made inputs that describe the athlete: age, height, weight, bmi, activity_level and a few more. Notice the as athlete at the end of its import. Both the athlete library and the strength libraries declare an input called weight: one is the athlete’s body weight, the other the weight on the bar. Importing with an alias keeps them apart, because the athlete’s one is now called athlete.weight. You can read more about this on the imports page.

Questions

Our first halt is a short questionnaire. An exec does not have to specify anything; it can be nothing but measures:

exec questions() {
    @title = "About you"
    measure athlete.age, athlete.weight, athlete.activity_level
}

let about = questions()

The athlete sees one screen titled “About you” with three fields. When they continue, the answers come back in the exec’s feedback, which we keep in about. From now on about.weight is their body weight, say 80|kg|, and about.activity_level how active they are.

activity_level is a number input with a list of values to choose from, from “Sedentary” to “Extra active”. The athlete picks one from the list, and the program receives its position in the list, starting from 0. So about.activity_level < 2 means “sedentary or lightly active”.

Goal

For the goal there is no ready-made input, so we declare our own, with two values to choose from:

input:number goal [
    title: "What do you want from the next four weeks?",
    constraint: [values: ["Get stronger", "Build endurance"]]
]

let wants = ask goal

This time we use ask instead of measure. The difference is in when the answer arrives. measure belongs to an exec: the athlete reports it after doing whatever the exec specified. ask is a halt of its own: the program stops right there, shows a single question and continues with the answer, which ask hands back directly. wants is 0 for “Get stronger” and 1 for “Build endurance”.

Test

Next, the athlete does as many squats as they can. The squat library has bodyweight_squat, and we use its comments spec to tell the athlete what to do. We don’t prescribe any reps, but we do measure them:

let test = bodyweight_squat(
    [comments: "As many good reps as you can, then stop"],
    [reps: true],
    [location: "Squat test"]
)

test.reps is the number they managed.

The decision

With the questionnaire, the goal and the test in hand, the decision fits in two lines:

let beginner = about.activity_level < 2 || test.reps < 20
let reps = wants == 0 ? 6 : 15

|| means “or”, and ? : picks the first value when the condition holds and the second when it doesn’t. Fewer, heavier reps to get stronger; more, lighter ones to build endurance.

The athlete has done enough for one day, so we rest before the training starts:

rest(1|day|)

Training

A session is three sets of squats and three sets of push-ups. Which squat, and how heavy, depends on what we found out:

group session(week) {
    repeat i:3 {
        if (beginner) {
            bodyweight_squat([reps: reps + week], [reps: true], [location: true, set: i, sets: 3])
        } else {
            let load = round(about.weight * 0.3, 2.5|kg|) + (week - 1) * 2.5|kg|
            goblet_squat([weight: load, reps: reps], [reps: true, weight: true], [location: true, set: i, sets: 3])
        }
    }
    repeat i:3 {
        push_up([reps: beginner ? 5 + week : 10 + week], [reps: true], [location: true, set: i, sets: 3])
    }
}

Beginners add a rep every week. Everyone else starts the goblet squat at 30% of their body weight, rounded to 2.5 kg, and adds 2.5 kg a week: an 80 kg athlete squats 25 kg in the first week, 27.5 kg in the second and so on. The push-ups grow by a rep a week for everyone.

All that’s left is the schedule, three sessions a week for four weeks:

group main() {
    @title = "Start here"
    repeat week:4 {
        repeat day:3 {
            session(week)
            rest(day == 3 ? 3|day| : 2|day|)
        }
    }
}

main()

The whole program

import "coach/common/rest.cl"
import "coach/athlete.cl" as athlete
import "coach/strength/squat.cl"
import "coach/strength/push.cl"

input:number goal [
    title: "What do you want from the next four weeks?",
    constraint: [values: ["Get stronger", "Build endurance"]]
]

exec questions() {
    @title = "About you"
    measure athlete.age, athlete.weight, athlete.activity_level
}

let about = questions()
let wants = ask goal

let test = bodyweight_squat(
    [comments: "As many good reps as you can, then stop"],
    [reps: true],
    [location: "Squat test"]
)

let beginner = about.activity_level < 2 || test.reps < 20
let reps = wants == 0 ? 6 : 15

rest(1|day|)

group session(week) {
    repeat i:3 {
        if (beginner) {
            bodyweight_squat([reps: reps + week], [reps: true], [location: true, set: i, sets: 3])
        } else {
            let load = round(about.weight * 0.3, 2.5|kg|) + (week - 1) * 2.5|kg|
            goblet_squat([weight: load, reps: reps], [reps: true, weight: true], [location: true, set: i, sets: 3])
        }
    }
    repeat i:3 {
        push_up([reps: beginner ? 5 + week : 10 + week], [reps: true], [location: true, set: i, sets: 3])
    }
}

group main() {
    @title = "Start here"
    repeat week:4 {
        repeat day:3 {
            session(week)
            rest(day == 3 ? 3|day| : 2|day|)
        }
    }
}

main()

Try it

Run the program in the simulator a few times with different answers:

  • Say you are very active, weigh 80 kg, want to get stronger and manage 30 squats. Training starts with goblet squats of 6 reps at 25 kg.
  • Step back to the test with Back and enter 12 squats instead. The program takes the other path: bodyweight squats of 7 reps, and push-ups of 6.
  • Step back once more to the goal and pick “Build endurance” to see the reps go up.

Being able to step back and answer differently is the quickest way to check every path through a program like this one.