Last active
July 27, 2025 12:49
-
-
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
| /* Trials Skills Schedule 2025-07-26 | |
| * Version 2.1 of the schedule | |
| * | |
| * Code : | |
| * https://gist.github.com/jwm-art-net/7f555bee4f96d406a95d5f7b6c595e1f | |
| * | |
| * Text output: | |
| * https://gist.github.com/jwm-art-net/478384456a8782f1b502b6abad31d10c | |
| * | |
| * I created this schedule to help me break out of habits that had | |
| * formed in my trials skill practice. Too often I had a tendency to | |
| * stay in my comfort zone practicing skills I had a degree of | |
| * confidence in, while neglecting the skills I was yet to master. | |
| * The schedule also reduces indecision over what to practice, and is | |
| * a concrete plan I have felt better able to commit to. | |
| * | |
| * SCHEDULE USAGE: | |
| * 1) Start at session #1 and practice each skill in the session! | |
| * | |
| * 2) Set a minimum time to practice each skill in the session. | |
| * I was setting 10 minutes for warm up, and 20 minutes for each skill | |
| * before I added a third skill slot. It's up to you how much time | |
| * you spend, obviously how much depends on your fitness and various | |
| * other factors. | |
| * | |
| * Generally, each skill is performed for the alloted time before | |
| * moving onto the next skill. | |
| * | |
| * 3) The modifier sets a way that one or more of the skills should be | |
| * adapted. Doing this not only adds variety to the way skills are | |
| * practiced, but also helps reduce habits where the same few obstacles | |
| * are used frequently while other obstacles get overlooked. | |
| * | |
| * 4) When and how often you practice a session depends on your | |
| * fitness, and lifestyle. However, at least twice a week, or | |
| * preferably more is recommended. The schedule is not designed around | |
| * a set weekly or monthly practice. It's designed around ensuring a | |
| * range of skills are frequency practiced no matter when you practice. | |
| * | |
| * 5) This schedule I designed for my own personal use without any | |
| * sports training or education beyond what I've self learnt. It has | |
| * no guarantee it will produce progress or be helpful for you! | |
| * | |
| * USAGE NOTES - approach: | |
| * | |
| * The above is the basic approach to using the schedule. However you | |
| * might consider the basic approach to be too strict, limited, | |
| * un-creative, or lacking in freedom. | |
| * | |
| * While still retaining the basic interpretation (practice one skill | |
| * for a set period of time, and then the next, sequentially one after | |
| * another) there are a few things specified in the schedule (to bear | |
| * in mind before going too off-piste) which break things up a little: | |
| * | |
| * 1) The Warm up and Skill C slots have the 'free' skill - it's your | |
| * choice what you do for these. | |
| * | |
| * 2) For the Skill B skill "Comp line" the idea is to set yourself | |
| * a competition trials line - it's compltely up to you which skills | |
| * you use to complete it. Just remember to set difficulty level | |
| * appropriately so you are challenged, but also stand a chance. | |
| * | |
| * 3) The "Line" modifier specifically flips the approach for the | |
| * entire session. When specified, the skills should not be practiced | |
| * one after another for set lengths of time as usual. Instead, similar | |
| * to the Skill B "Comp line" a line of obstacles is set to complete - | |
| * but unlike "Comp line" there's no choice of skills, it's the | |
| * skills specified for the session which must be be used to complete | |
| * the line. The order you use them is up to you however. | |
| * | |
| * USAGE NOTES - time, energy, etc: | |
| * | |
| * I like to set 10 minutes as a minimum time for each part. If I am | |
| * not feeling my best, the session might only last for 40 minutes or | |
| * less, that is perfectly okay. | |
| * | |
| * Often I am more motivated for one part of the session than another. | |
| * I'll spend all my time or energy on the first skill and then lack | |
| * energy or time for the next skill. Nerves might also come into play | |
| * here if I feel at risk during the skill practice. If nerves become | |
| * too agitated then it might be a sign to stop the skill or session | |
| * earlier than expected. Get to know your body. | |
| * | |
| * Injuries or illness might mean missed sessions. When feeling better | |
| * but still not back to normal, then practising only the warm up can | |
| * be a good way of continuing to ride without risking setting yourself | |
| * back again. | |
| * | |
| * Sometimes I go hard on the first skill due to determination and | |
| * might lack time or energy for the rest of the session. No problem. | |
| * | |
| * Other times I simply lack the energy for the full session, even | |
| * with just the minimum of ten minutes for each skill. Nevermind. | |
| * | |
| * Conversely, I might be able to up the times for each skill and have | |
| * a longer session. Judge appropriately! | |
| * | |
| * Combine skills outside of when the "Line" modifier is specified. | |
| * There are no rules saying you can't do this whenever you like, but | |
| * for me personally, while still learning, it's better to more | |
| * frequently focus on just one skill for a set time, before moving | |
| * onto the next skill in the session. This is especially true if the | |
| * skill is physically and mentally demanding. | |
| * | |
| * Tired of it all! Do the minimum! Just get on your bike! | |
| * | |
| * USAGE NOTES - Logging your practice | |
| * | |
| * It can be useful to log your riding in order to see how you've | |
| * progressed. At minimum just note down the skills practiced. If you | |
| * beat any personal bests (ie gap distance, side hop height) be sure | |
| * to write this down also! | |
| * | |
| * BACKGROUND TO CHANGES: | |
| * | |
| * I went through 49 sessions of the first schedule created by my | |
| * small C program. While I have seen improvements in some areas, in | |
| * others (specifically side hops and pedal ups) I had not made | |
| * satisfying progress in the six months the schedule was followed. | |
| * | |
| * Around mid June (currently the end of July) I had thoughts about | |
| * changing the schedule. I made some minor changes, mainly a few | |
| * reclassifications and introductions of obstacles, but I felt too | |
| * committed to the existing schedule and didn't want to ditch it and | |
| * start again just for a few minor modifications. | |
| * | |
| * However now I'm close to 50 sessions (just done #49) I feel better | |
| * positioned to judge how things have gone, and how to improve it | |
| * with some substantial (and some less substantial) changes. | |
| * | |
| * CHANGES: | |
| * The major change is the addition of a third skill slot for each | |
| * session, which has become the new Skill A. | |
| * Due to the dissatisfaction of my side hop and pedal up progress, | |
| * the Skill A slot now consists only of these two skills. Any time I | |
| * did make progress at these skills during a session, it always | |
| * seemed to be lost after a short break. In theory if I alternately | |
| * practice these every single session, progress will be more likely! | |
| * | |
| * I then changed my mind about Skill A every single session, and | |
| * decided to implement a cycle of Skill A practice for 8 sessions | |
| * before having 2 sessions break from it. I just felt it was possibly | |
| * going to be too much to not have a break from it. | |
| * | |
| * Programmatically, each skill slot consist of 3 or 4 groups of | |
| * skills. The slot rotates between each group, and each group rotates | |
| * amongst it's skills each use. Now I've arrived at this second | |
| * version, this method almost seems uneccessary, but it was useful | |
| * for arriving here, as well as having some advantages for increasing | |
| * the frequency of some skills at the cost of over others. | |
| * | |
| * I've cleaned up some of the skills grouping, so for example, in the | |
| * warm up, skinny variations are part of one group, and gap and drop | |
| * variations form groups for Skill B. | |
| * | |
| * Lastly, the "Obstacle" slot has been renamed to the "Modifier" slot. | |
| * I introduced some new "modifiers" but also consolidated some of | |
| * them with existing modifiers. The "Line" modifier (already | |
| * mentioned) is perhaps the most significant as it adapts the way the | |
| * entire session is approached. It came about because I realized it | |
| * was sometimes good fun to combine the skills and practice them | |
| * simultaneously. | |
| * | |
| * CHANGING THE CODE | |
| * If you know how to compile C programs you may be interested in | |
| * changing some of the variables at the start of main(). First up, | |
| * 'sessions' sets the number of sessions generated. Next, two others | |
| * which control output: 'inline_key' (0 for off, 1 for on) will output | |
| * the key before each and every skill (ie "Warm up", "Skill A" etc). | |
| * 'inline_stats' (0 for off, 1 for on) shows a count of how many times | |
| * each skill has been used so far within the schedule, next to the | |
| * skill. | |
| * | |
| * After this, the groups of skills are created. They are simply | |
| * NULL terminated arrays of plain text strings. | |
| * | |
| * Next the groups themselves are grouped into the appropriate arrays | |
| * for warm up, skill a, skill b, skill c, and modifier. During this | |
| * step the plain text arrays are converted into list data structures | |
| * which collect the usage statistics of each skill etc and also help | |
| * simplify the logic of the main loop. The statistic generation | |
| * handles instances of the same string in different groups. | |
| * However statistic generation of the same skill across differing | |
| * slots is undefined. It works, but may cause confusion, which is why | |
| * the "free/w" in Warm up is distinguished from "free/c" in Skill C. | |
| * | |
| * PROGRAM USAGE: | |
| * The program simply outputs text. Redirect the output to a text file. | |
| * The text file can be imported (for example by Libre Office Calc) | |
| * into a spreadsheet by using the pipe symbol '|' as a field | |
| * seperator. Make sure that the comma symbol ',' is not used as a | |
| * field seperator. Adding the colon symbol ':' as a field seperator | |
| * will remove the skill key text into seperate fields to more easily | |
| * make the skills themselves, with the appropriate formatting, more | |
| * prominent than the keys. | |
| * | |
| * After the skills schedule itself, a report of statistics for each | |
| * skill and modifier is output which gives an idea of how often | |
| * certain skills are practiced in relation to each other. This is | |
| * very useful for when you want to taylor the schedule for your | |
| * own particular set of skill strengths and weaknesses. | |
| */ | |
| #include <stdio.h> | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <time.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) | |
| { | |
| int sessions = 50; // number of sessions to generate | |
| // 0 = off, 1 = on | |
| int inline_stats = 0; // show use count within the schedule next to each skill in every session | |
| int inline_key = 1; // show key/slot name next to before each skill ie "Warm up:" "Skill A" etc | |
| int inline_key_pipe = 1; // add a | symbol (used as field seperator) when using the inline_key | |
| int skill_a_sessions = 8; // initiate a break from Skill A after this many sessions. | |
| int skill_a_rest = 2; // how many sessions to rest from Skill A for. | |
| const char* str_w1[] = { "Long skinny", "Skinny corners", "Skinny steps", "High skinny", 0 }; | |
| const char* str_w2[] = { "Small hops, gaps, drops", "Rear to edge", "Endo, trackstand, fakie", 0}; | |
| const char* str_w3[] = { "Rear wheel pivots", "Pivots up", "Wrong foot rear hops", 0}; | |
| const char* str_w4[] = { "Free/w", "Pedal to manual", "Endo, trackstand, fakie", 0}; | |
| //--- | |
| const char* str_a1[] = { "Pedal ups", "Side hops", 0 }; | |
| //--- | |
| const char* str_b1[] = { "Lunge", "Bunny hops", "High roll ups", 0 }; | |
| const char* str_b2[] = { "Long gaps", "High gaps", "Drop gaps", 0 }; | |
| const char* str_b3[] = { "High drops", "Precision drops", "Comp line", 0 }; | |
| //--- | |
| const char* str_c1[] = { "Front hops", "Wheel swap", 0 }; | |
| const char* str_c2[] = { "Wheelbase hops", "Rolling hops", 0 }; | |
| const char* str_c3[] = { "Rotational hops", "Rear wheel twist", 0}; | |
| const char* str_c7[] = { "Free/c", "Wheel swap", 0 }; | |
| //--- | |
| const char* mods[] = { "L-shape", | |
| "Rounded/Natural", | |
| "Off-camber", | |
| "Wall", | |
| "A-beam/Rail/Post", | |
| "Incline", | |
| "Small/Narrow", | |
| "High", | |
| "Bunny hop bar", | |
| "4PH Trapezoid", | |
| "Line", 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), 0 }; | |
| list* skills_b[] = { new_list('b', str_b1), new_list('b', str_b2), new_list('b', str_b3), 0 }; | |
| list* skills__c[] = { new_list('c', str_c1), new_list('c',str_c2), new_list('c',str_c3), new_list('c',str_c7), 0 }; | |
| list* skills_c[] = { skills__c[0], skills__c[1], skills__c[2], skills__c[0], skills__c[1], skills__c[2], skills__c[3], 0 }; | |
| list* modifiers = new_list('m', mods); | |
| time_t ct = time(NULL); | |
| char* const ts = ctime(&ct); | |
| printf("|||||see: https://gist.github.com/jwm-art-net/7f555bee4f96d406a95d5f7b6c595e1f\n"); | |
| printf("|||||generated by %s on %s\n", __FILE_NAME__, ts); | |
| int sesh = 1; | |
| int skw = 0, ska = 0, skb = 0, skc = 0, skm = 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++]); | |
| while (skills_c[skc]) global_add_list_no_dup(skills_c[skc++]); | |
| global_add_list_no_dup(modifiers); | |
| int wmaxsl = 0; | |
| int skamaxsl = 0; | |
| int skbmaxsl = 0; | |
| int skcmaxsl = 0; | |
| skw = ska = skb = skc = skm = 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++; | |
| } | |
| while (skills_c[skc]) { | |
| if (skills_c[skc]->maxstrlen > skcmaxsl) | |
| skcmaxsl = skills_c[skc]->maxstrlen; | |
| skc++; | |
| } | |
| char hdr[1000]; | |
| char fmt[1000]; | |
| const char* keys[] = { "Warm up", "Skill A", "Skill B", "Skill C", "Modifier" }; | |
| char ikey[5][80]; // array of character strings for inline keys | |
| if (inline_key) { | |
| int ik = 0; | |
| for (int ik = 0; ik < 5; ik++) | |
| sprintf(ikey[ik], "%s: %s", keys[ik], inline_key_pipe ? "| " : ""); | |
| } | |
| else { | |
| // not using inline_keys so initialize to zero length character strings | |
| for (int ik = 0; ik < 5; ik++) | |
| ikey[ik][0] = '\0'; | |
| } | |
| if (inline_stats) { | |
| if (!inline_key) | |
| sprintf(hdr, "#%%-2s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s\n", | |
| wmaxsl , skamaxsl, skbmaxsl, skcmaxsl, modifiers->maxstrlen); | |
| sprintf(fmt, "#%%-2d | %s%%-%ds %%-4s | %s%%-%ds %%-4s | %s%%-%ds %%-4s | %s%%-%ds %%-4s | %s%%-%ds %%-4s\n", | |
| ikey[0], wmaxsl , ikey[1], skamaxsl , ikey[2], skbmaxsl , ikey[3], skcmaxsl, ikey[4], modifiers->maxstrlen); | |
| } | |
| else { | |
| if (!inline_key) | |
| sprintf(hdr, "#%%-2s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s | %%-%ds %%-4s\n", | |
| wmaxsl , skamaxsl, skbmaxsl, skcmaxsl, modifiers->maxstrlen); | |
| sprintf(fmt, "#%%-2d | %s%%-%ds | %s%%-%ds | %s%%-%ds | %s%%-%ds | %s%%-%ds\n", | |
| ikey[0], wmaxsl , ikey[1], skamaxsl , ikey[2], skbmaxsl , ikey[3], skcmaxsl, ikey[4], modifiers->maxstrlen); | |
| } | |
| if (!inline_key) { | |
| const char* ul1 = "---------"; | |
| const char* ul2 = "----"; | |
| printf(hdr, " ", keys[0], "", keys[1], "", keys[2], "", keys[3], "", keys[4], ""); | |
| printf(hdr, "--", ul1, ul2, ul1, ul2, ul1, ul2, ul1, ul2, ul1, ul2); | |
| } | |
| skw = ska = skb = skc = 0; | |
| int ska_count = 0; | |
| int ska_r_count = 0; | |
| while (sessions-- > 0) { | |
| item* i1 = list_loop(warmup[skw++]); | |
| item* i2 = 0; | |
| item* i3 = list_loop(skills_b[skb++]); | |
| item* i4 = list_loop(skills_c[skc++]); | |
| item* i5 = list_loop(modifiers); | |
| const char* s1 = str_use_item(i1); | |
| const char* s2; | |
| const char* s3 = str_use_item(i3); | |
| const char* s4 = str_use_item(i4); | |
| const char* s5 = str_use_item(i5); | |
| if (ska_count < skill_a_sessions) { | |
| i2 = list_loop(skills_a[ska++]); | |
| s2 = str_use_item(i2); | |
| ska_count++; | |
| } else { | |
| s2 = " - "; | |
| ska_r_count++; | |
| if (ska_r_count == skill_a_rest) { | |
| ska_count = 0; | |
| ska_r_count = 0; | |
| } | |
| } | |
| if (inline_stats) { | |
| char t1[10]; sprintf(t1, "| %d", *(i1->g_use_count)); | |
| char t2[10] = ""; | |
| if (i2) { | |
| 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)); | |
| char t5[10]; sprintf(t5, "| %d", *(i5->g_use_count)); | |
| printf(fmt, sesh++, s1, t1, s2, t2, s3, t3, s4, t4, s5, t5); | |
| } | |
| else | |
| printf(fmt, sesh++, s1, s2, s3, s4, s5); | |
| if (warmup[skw] == 0) | |
| skw = 0; | |
| if (skills_a[ska] == 0) | |
| ska = 0; | |
| if (skills_b[skb] == 0) | |
| skb = 0; | |
| if (skills_c[skc] == 0) | |
| skc = 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++]); | |
| skc = 0; while (skills__c[skc]) list_cleanup(skills__c[skc++]); | |
| list_cleanup(modifiers); | |
| list_sort_by_global_use_count(lg); | |
| char cats[] = {'w', 'a', 'b', 'c', 'm', 0}; | |
| for (int i = 0; cats[i] != 0; i++) { | |
| printf(" |-------------------\n"); | |
| item* li = list_head(lg); | |
| while (li) { | |
| if (li->cat == cats[i]) | |
| printf(" | skill: (%c) %-24s | use count:%-2d\n", li->cat, li->str, li->use_count); | |
| li = li->next; | |
| } | |
| } | |
| list_cleanup(lg); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment