DEV Community

Colin Fay
Colin Fay

Posted on • Originally published at colinfay.me on

Use R & GitHub as a Workout planner

Over the years, I’ve been trying a bunch a different applications and methods to stay motivated to workout. But every time it’s the same: at some point the application is great but limited if you do not pay, or the workouts are repetitive, or simply I can’t get into the habit of using the application.

What if there were a solution that is free, where exercises can be generated at random so that it’s not too repetitive, and that I can fit into my “natural workflow” when it come to creating and keeping track oftasks?

So here’s a new idea: what if I can use R to generate random workout, and then use GitHub issues as a tracker and checklist?

Note: obviously I’m neither a profesional athlete (in case you haven’t met me before), nor a professional trainer, so in case this needs to be said, please use these for recreational workouts, and with care (and of course at your own risk).

Random workouts

First of all, I need a workout database, with the following elements:

  • type of workout (bodyweight/kettlebells/abs/dumbbells/resistanceband…)
  • the description
  • a value to track the timing or number of repetitions
  • the unit of this value
  • a complexity factor so that I can plan harder workouts when I feel like it
  • something to say if it’s “outside friendly”: for example I can’t do jumping rope inside, nor some kettlebell movements

For now that I will just be doing it manually, maybe at some point I will scrape an online resource, but that’s an idea for another blogpost. The idea is to come with this kind of table:

tibble::tribble(
  ~type, ~description, ~val, ~unit, ~complexity, ~inside,
  "Jumping rope", "Jumping Rope", 100, "jump", 1, FALSE,
  "Bodyweight", "Plank", 45, "seconds", 1, TRUE 
)


# A tibble: 2 x 6
  type description val unit complexity inside
  <chr> <chr> <dbl> <chr> <dbl> <lgl> 
1 Jumping rope Jumping Rope 100 jump 1 FALSE 
2 Bodyweight Plank 45 seconds 1 TRUE  

Enter fullscreen mode Exit fullscreen mode

Given that I want to add manual exercises (the one I know how to do, and like to do), I’ll do this manually in a CSV file.

worrkout::wk


# A tibble: 27 x 7
   type description val unit complexity inside pics                  
   <chr> <chr> <dbl> <chr> <dbl> <lgl> <chr>                 
 1 Jumpin "Jumping Rope" 100 jump 1 FALSE https://mir-s3-cdn-cf
 2 Bodywe "Plank" 45 seconds 1 TRUE https://thumbs.gfycat
 3 Bodywe "Squat" 16 x 1 TRUE https://thumbs.gfycat
 4 Bodywe "Lunge" 16 x / ea 1 TRUE https://media0.giphy.
 5 Bodywe "Single-Leg B… 16 x / ea… 1 TRUE https://thumbs.gfycat…
 6 Bodywe… "Glute Bridge" 16 x / ea… 1 TRUE https://thumbs.gfycat…
 7 Bodywe… "Plyo Lunge" 16 x / ea… 1 TRUE https://media.giphy.c…
 8 Bodywe… "Mountain Cli 16 x / ea 1 TRUE https://media1.tenor.
 9 Kettle "Russian Twis… 16 x 1 TRUE https://thumbs.gfycat…
10 Bodywe… "Leg Lift" 16 x 1 TRUE https://thumbs.gfycat
# … with 17 more rows

Enter fullscreen mode Exit fullscreen mode

Then, I’ll need a function to sample some of the exercises, repeat twice (I like to do two cycles of the same series of exercises), then create the text for the issue.

This text for the issue should look like this:

+ [] KettleBell - Russian Twist (16 x)

<div align = 'center'><img src ='url' width = '400px'> </img></div>

Enter fullscreen mode Exit fullscreen mode

So that way, I can check the ToDos, and also see a gif of the movement(well, some gif are more for fun ;) )

generate_workout <- function(
  n_workout,
  complexity = 1, 
  outside = FALSE
){
  # Read the dataset, and remove its NA
  wk <- worrkout::wk
  wk <- tidyr::drop_na(wk, 1:6)

  # We want `n_workout`, which is 2 cycles of exercises
  wk <- dplyr::sample_n(wk, floor(n_workout / 2)) 
  wk <- dplyr::bind_rows(wk, wk)

  # If we want to get more difficulty
  wk$complexity <- wk$complexity * complexity

  # Generate the output
 body <- sprintf(
    "+ [] %s - %s (%s %s) \n\n <div align = 'center'><img src ='%s' width = '400px'> </img></div>",
    wk$type,
    wk$description,
    wk$val,
    wk$unit,
    wk$pics
  )
  paste0(body, collapse = "\n\n")
}
cat(generate_workout(4))


+ [] KettleBell - KettleBell clean and press (16 x / each side) 

 <div align = 'center'><img src ='https://media.giphy.com/media/128vrPxCk9JQ6k/giphy.gif' width = '400px'> </img></div>

+ [] Bodyweight - Bicycle Crunch (16 x / each side) 

 <div align = 'center'><img src ='https://thumbs.gfycat.com/CheapMadeupLeafhopper-size_restricted.gif' width = '400px'> </img></div>

+ [] KettleBell - KettleBell clean and press (16 x / each side) 

 <div align = 'center'><img src ='https://media.giphy.com/media/128vrPxCk9JQ6k/giphy.gif' width = '400px'> </img></div>

+ [] Bodyweight - Bicycle Crunch (16 x / each side) 

 <div align = 'center'><img src ='https://thumbs.gfycat.com/CheapMadeupLeafhopper-size_restricted.gif' width = '400px'> </img></div>

Enter fullscreen mode Exit fullscreen mode

Let’s now push this to Github:

res <- gh::gh(
  "POST /repos/:owner/:repo/issues",
  owner = "ColinFay",
  repo = "workouts",
  title = sprintf(
    "Workout - %s", 
    Sys.Date()
  ), 
  assignee = "ColinFay", 
  body = generate_workout(16)
)
browseURL(res$html_url)

Enter fullscreen mode Exit fullscreen mode

And, tadaaa 🎉.

Please reuse these functions just for fun and recreational workouts.

Find them at github.com/ColinFay/worrkout

Top comments (0)