Created
March 22, 2025 23:27
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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