Skip to content

Instantly share code, notes, and snippets.

@jwm-art-net
Created March 22, 2025 23:27
Show Gist options
  • Save jwm-art-net/7f555bee4f96d406a95d5f7b6c595e1f to your computer and use it in GitHub Desktop.
Save jwm-art-net/7f555bee4f96d406a95d5f7b6c595e1f to your computer and use it in GitHub Desktop.
Simple c program to generate a training plan schedule for learning physical skills, the example is for bicycle trials
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
//#define DEBUG 1
typedef struct item {
const char* str;
struct item* next;
int use_count;
int* g_use_count;
char cat;
} item;
typedef struct list {
item* items;
item* tail;
item* ptr;
int maxstrlen;
char cat;
} list;
item* new_item(const char* str)
{
if (!str)
return 0;
item* i = malloc(sizeof(item));
if (!i)
return 0;
i->str = str;
i->next = 0;
i->use_count = 0;
i->g_use_count = &i->use_count;
i->cat = 0;
return i;
}
item* del_item(item* i)
{
if (!i)
return 0;
item* n = i->next;
#ifdef DEBUG
printf("deleting item: '%s'\n", i->str);
#endif
i->str = 0;
i->next = 0;
i->use_count = 0;
i->g_use_count = 0;
i->cat = 0;
free(i);
return n;
}
const char* str_use_item(item* i)
{
if (!i)
return 0;
(*i->g_use_count)++;
if (i->g_use_count != &i->use_count)
i->use_count++;
return i->str;
}
void list_cleanup(list* l)
{
if (!l)
return;
l->ptr = l->items;
#ifdef DEBUG
printf ("deleting list...\n");
#endif
while (l->ptr) {
l->ptr = del_item(l->ptr);
};
free(l);
return;
}
list* new_empty_list(void)
{
#ifdef DEBUG
printf("new empty list\n");
#endif
list* l = malloc(sizeof(list));
if (!l)
return 0;
l->items = 0;
l->ptr = 0;
l->tail = 0;
l->maxstrlen = 0;
return l;
}
list* new_list(char cat, const char** strings)
{
#ifdef DEBUG
printf("new list '%s'...\n", strings[0]);
#endif
list* l = malloc(sizeof(list));
if (!l)
return 0;
l->items = 0;
l->ptr = 0;
l->tail = 0;
l->maxstrlen = 0;
l->cat = cat;
const char* str = strings[0];
if (!(l->items = new_item(str))) {
free(l);
return 0;
}
l->maxstrlen = strlen(str);
l->tail = l->items;
l->items->cat = cat;
int strix = 0;
int slen = 0;
while((str = strings[++strix])) {
#ifdef DEBUG
printf("adding new item '%s' to list...\n", str);
#endif
item* i = new_item(str);
if (!i) {
#ifdef DEBUG
printf("FAIL: item not added\n");
#endif
list_cleanup(l);
return 0;
}
slen = strlen(str);
if (slen > l->maxstrlen)
l->maxstrlen = slen;
l->tail->next = i;
l->tail = i;
i->cat = cat;
}
return l;
}
item* list_head(list* l)
{
if (!l)
return 0;
l->ptr = l->items;
return l->ptr;
}
item* list_at_head(list* l)
{
if (!l)
return 0;
return (l->ptr == l->items) ? l->ptr : 0;
}
item* list_at_tail(list* l)
{
if (!l)
return 0;
return (l->ptr == l->tail) ? l->ptr : 0;
}
item* list_next(list* l)
{
if (!l)
return 0;
l->ptr = l->ptr->next;
return l->ptr;
}
item* list_loop(list* l)
{
if (!l)
return 0;
if (!l->ptr)
l->ptr = l->items;
else
l->ptr = l->ptr->next;
if (!l->ptr)
l->ptr = l->items;
return l->ptr;
}
item* list_add(list* l, const char* str, char cat)
{
if (!l)
return 0;
if (!l->items) {
if (!(l->items = new_item(str)))
return 0;
l->tail = l->ptr = l->items;
}
else {
if (!(l->tail->next = new_item(str)))
return 0;
l->ptr = l->tail->next;
l->tail = l->ptr;
}
l->tail->cat = cat;
return l->tail;
}
item* list_sort_by_global_use_count(list* l)
{
if (!l)
return 0;
/* steps through list and compares each item with next item */
int changed = 0;
do {
item* i = l->items;
item* p = 0;
item* n = i->next;
int changed = 0;
while(n) {
if (*(i->g_use_count) < *(n->g_use_count)) {
if (p == 0) {
i->next = n->next;
n->next = i;
l->items = n;
}
else {
p->next = n;
i->next = n->next;
n->next = i;
}
changed = 1;
break;
}
else {
p = i;
i = n;
n = i->next;
}
}
if (!n)
break;
} while (1);
return 0;
}
list* lg = 0;
list* global_add_list_no_dup(list* l)
{
if (!lg)
lg = new_empty_list();
if (!lg) {
#ifdef DEBUG
printf("lg = 0\n");
#endif
return 0;
}
if (!l) {
#ifdef DEBUG
printf("l = 0\n");
#endif
return 0;
}
list_head(l);
while (l->ptr) {
list_head(lg);
while (lg->ptr) {
#ifdef DEBUG
//printf("comparing: '%s' with '%s'\n", lg->ptr->str, l->ptr->str);
#endif
if (strcmp(lg->ptr->str, l->ptr->str) == 0)
break;
list_next(lg);
}
if (!lg->ptr) {
#ifdef DEBUG
//printf("adding non duplicate item: '%s'\n", l->ptr->str);
#endif
list_add(lg, l->ptr->str, l->ptr->cat);
}
l->ptr->g_use_count = &lg->ptr->use_count;
list_next(l);
}
}
int main(int argc, char** argv)
{
/*const char* str_w[] = { "skinny",
"small gaps",
"rear wheel pivots",
"small drops n hops up",
"pivot up",
"endo/trackstand/fakie",
"wrong foot rear hops",
0 };*/
const char* str_w1[] = { "long skinny", "skinny corners", "skinny steps", "mini bmx", 0 };
const char* str_w2[] = { "small gaps", "small drops n hops up", "wrong foot rear hops", 0};
const char* str_w3[] = { "rear wheel pivots", "pivot up", "endo/trackstand/fakie", 0};
const char* str_w4[] = { "free/w", "rear wheel pivots", 0 };
//---
const char* str_a1[] = { "side hops", "lunge", "side hops", 0 };
const char* str_a2[] = { "long gaps", "side hops", "precision drops",
"high gaps", "high drops", 0 };
const char* str_a3[] = { "pedal ups", "bunny hops", "pedal ups", 0 };
//---
const char* str_b1[] = { "front hops", "wheel swap", "front hops", 0 };
const char* str_b2[] = { "wheelbase hops",
"high roll ups",
"rolling hops",
"high skinny", 0 };
const char* str_b3[] = { "rotational hops",
"rear wheel twist",
"right angle skinnies",
"rotational hops", 0 };
const char* str_b7[] = { "free/b", "wheel swap", 0 };
//---
const char* strobs[] = { "l-shape 2ph-hw-pallet",
"boulder",
"off-camber hw-pallet",
"flower pot",
"a-beam",
"stubby skinny",
"incline",
"small block",
"plasterers bucket",
"narrow", 0 };
//list* warmup = new_list(str_w);
list* warmup[] = { new_list('w', str_w1), new_list('w', str_w2), new_list('w', str_w3), new_list('w', str_w4), 0 };
list* skills_a[] = { new_list('a', str_a1), new_list('a', str_a2), new_list('a', str_a3), 0 };
list* skills__b[] = { new_list('b', str_b1), new_list('b',str_b2), new_list('b',str_b3), new_list('b',str_b7), 0 };
list* skills_b[] = { skills__b[0], skills__b[1], skills__b[2], skills__b[0], skills__b[1], skills__b[2], skills__b[3], 0 };
list* obstacles = new_list('o', strobs);
skills_b[3] = skills_b[0];
skills_b[4] = skills_b[1];
skills_b[5] = skills_b[2];
int sesh = 1;
int sessions = 56;
int skw = 0;
int ska = 0;
int skb = 0;
//global_add_list_no_dup(warmup);
while (warmup[skw]) global_add_list_no_dup(warmup[skw++]);
while (skills_a[ska]) global_add_list_no_dup(skills_a[ska++]);
while (skills_b[skb]) global_add_list_no_dup(skills_b[skb++]);
int wmaxsl = 0;
int skamaxsl = 0;
int skbmaxsl = 0;
skw = 0;
ska = 0;
skb = 0;
while (warmup[skw]) {
if (warmup[skw]->maxstrlen > wmaxsl)
wmaxsl = warmup[skw]->maxstrlen;
skw++;
}
while (skills_a[ska]) {
if (skills_a[ska]->maxstrlen > skamaxsl)
skamaxsl = skills_a[ska]->maxstrlen;
ska++;
}
while (skills_b[skb]) {
if (skills_b[skb]->maxstrlen > skbmaxsl)
skbmaxsl = skills_b[skb]->maxstrlen;
skb++;
}
char hdr[180];
char fmt[180];
sprintf(hdr, "#%%-2s | %%-%ds | %%-%ds | %%-%ds | %%-%ds\n",
wmaxsl, skamaxsl , skbmaxsl , obstacles->maxstrlen);
sprintf(fmt, "#%%-2d | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s\n",
wmaxsl , skamaxsl , skbmaxsl , obstacles->maxstrlen);
// sprintf(fmt, "#%%-2d | %%-%ds | %%-%ds | %%-%ds | %%-%ds\n",
/*
sprintf(hdr, "#%%2s %%%ds %%%ds %%%ds %%%ds\n",
wmaxsl, skamaxsl , skbmaxsl , obstacles->maxstrlen);
sprintf(fmt, "#%%d,%%s,%%s,%%s,%%s\n");
*/
const char* ul = "---------------";
printf(hdr, " ", "WARM UP", "SKILL A", "SKILL B", "OBSTACLE");
printf(hdr, "--", ul, ul, ul, ul);
skw = 0; ska = 0; skb = 0;
while (sessions-- > 0) {
/* printf(fmt, sesh++, str_use_item(list_loop(warmup)),
str_use_item(list_loop(skills_a[ska++])),
str_use_item(list_loop(skills_b[skb++])),
str_use_item(list_loop(obstacles)));
*/
item* i1 = list_loop(warmup[skw++]);
item* i2 = list_loop(skills_a[ska++]);
item* i3 = list_loop(skills_b[skb++]);
item* i4 = list_loop(obstacles);
const char* s1 = str_use_item(i1);
const char* s2 = str_use_item(i2);
const char* s3 = str_use_item(i3);
const char* s4 = str_use_item(i4);
char t1[10]; sprintf(t1, "| %d", *(i1->g_use_count));
char t2[10]; sprintf(t2, "| %d", *(i2->g_use_count));
char t3[10]; sprintf(t3, "| %d", *(i3->g_use_count));
char t4[10]; sprintf(t4, "| %d", *(i4->g_use_count));
printf(fmt, sesh++, s1, t1, s2, t2, s3, t3, s4, t4);
//printf(fmt, sesh++, s1, s2, s3, s4);
if (warmup[skw] == 0)
skw = 0;
if (skills_a[ska] == 0)
ska = 0;
if (skills_b[skb] == 0)
skb = 0;
}
skw = 0; while (warmup[skw]) list_cleanup(warmup[skw++]);
ska = 0; while (skills_a[ska]) list_cleanup(skills_a[ska++]);
skb = 0; while (skills__b[skb]) list_cleanup(skills__b[skb++]);
list_cleanup(obstacles);
printf("-----------------------------------------------\n");
list_sort_by_global_use_count(lg);
item* i = list_head(lg);
while (i) {
printf("skill: (%c) %-22s use count:%-2d\n", i->cat, i->str, i->use_count);
i = i->next;
}
list_cleanup(lg);
return 0;
}
/* list* new_list_va(int count, ...)
{
va_list args;
list* l = malloc(sizeof(list));
if (!l)
return 0;
l->items = 0;
l->ptr = 0;
l->tail = 0;
va_start(args, count);
const char* str = va_arg(args, const char*);
if (!(l->items = new_item(str))) {
free(l);
return 0;
}
l->tail = l->items;
while((str = va_arg(args, const char*))) {
printf("adding new item '%s' to list...\n", str);
item* i = new_item(str);
if (!i) {
printf("FAIL: item not added\n");
list_cleanup(l);
return 0;
}
l->tail->next = i;
l->tail = i;
}
return l;
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment