#include "display.c" int get_date_index(creneau* edt, int len_creneau, date d) { // could be done in log(n), I know // yields the 1st occurence of d in edt int x = -1; for(int i = 0; i < len_creneau; i++) { x = date_dist(d, edt[i].date); if(x >= 0) { return i; } } return -1; } array get_all_date_index(creneau* edt, int len_edt, date d) { array arr; arr.a = malloc(sizeof(int)*8); arr.memlen = 8; arr.len = 0; int x = -1; int halt = 0; for(int i = 0; i < len_edt-halt; i++) { x = date_dist(d, edt[i].date); if(x == 0) { arr.a[arr.len] = i; arr.len++; } else if(x > 0) { halt = len_edt; } } return arr; } int get_next_friday(creneau* edt, int len_creneau, date d) { // could be done in log(n), I know again int x = -1; for(int i = 0; i < len_creneau; i++) { x = date_dist(d, edt[i].date); //printf("%d\n", x); if(x >= 0 && (i == len_creneau-1 || date_dist(d, edt[i+1].date) - x > 1)) { return i; } } return -1; } int get_fst_offset(creneau* edt, date d) { return (date_dist(edt[0].date, d)); } bool is_allowed_MP2I(creneau* edt, int len_edt, int grp, date end) { /* conditions (AND) : 1) Alternate between physics and english 2) Pattern for math colles is exactly 3-1-3-1-... 3) Between 1 and 2 colles per week and per group (exclusing special colles such as Info) 4) Special colles (aka INFO) at least 1 every 6 weeks */ int end_id = get_next_friday(edt, len_edt, end); // index of first date that is later than end if(end_id == -1) { return true; } //printf("EndId : %d\n", end_id); // 1) PC/AGL alternance int agl = 0; int pc = 0; char has_to_be = 'n'; // 'n' = not set, 'a' = AGL and 'p' = PC for(int i = end_id-1; i >= 0; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { //printf("Checking AGL/PC...\n"); // currently pointed date is the last friday of the week // since we are going down, friday <==> reset variables and check for conflicts if(agl + pc != 1) { printf("Missing english or physics colle at index %d for group %d (found %d)\n", i, grp, agl+pc); return false; } else if(has_to_be == 'p' && pc != 1) { printf("Wrong number of physics colle at index %d for group %d\n", i, grp); return false; } else if(has_to_be == 'a' && agl != 1) { printf("Wrong number of english colle at index %d for group %d\n", i, grp); return false; } if(has_to_be == 'n') { if(agl == 1) { has_to_be = 'p'; } else { has_to_be = 'a'; } } else if(has_to_be == 'p') { has_to_be = 'a'; } else { has_to_be = 'p'; } agl = 0; pc = 0; } if(edt[i].group == grp && edt[i].mat == ENGLISH) { agl += 1; } if(edt[i].group == grp && edt[i].mat == PHYSICS) { pc += 1; } } // 2) Math colles int math = 0; int last_no_math = -1; for(int i = end_id-1; i >= 0; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { if(math != 0 && math != 1) { printf("Invalid number of math colles at index %d for group %d\n", i, grp); return false; } else if(math == 0) { if(last_no_math != -1 && last_no_math != 3) { printf("Invalid rotation of math colles at index %d for group %d\n", i, grp); return false; } last_no_math = 0; } else if(last_no_math > 3) { printf("Too many math colles at index %d for group %d\n", i, grp); return false; } else { if(last_no_math != -1) { last_no_math += 1; } } math = 0; } if(edt[i].group == grp && edt[i].mat == MATH) { math += 1; } } // 3) Count int n_colles = 0; for(int i = end_id-1; i >= 0; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { if(n_colles != 1 && n_colles != 2) { printf("Invalid number of colles at index %d for group %d (found %d)\n", i, grp, n_colles); return false; } n_colles= 0; } if(edt[i].group == grp) { n_colles++; } } // 4) Info int inf = 0; int last_no_inf = -1; for(int i = end_id-1; i >= 0; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { if(inf != 0 && inf != 1) { printf("Invalid number of info colles at index %d for group %d\n", i, grp); return false; } else if(inf == 0) { last_no_inf = 0; } else if(last_no_inf > 5) { printf("Too few info colles at index %d for group %d\n", i, grp); return false; } else { if(last_no_inf != -1) { last_no_inf += 1; } } inf = 0; } if(edt[i].group == grp && edt[i].mat == INFO) { inf += 1; } } return true; } /* for(int i = end_id-1; i >= 0; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { // Check week } // Detect colles } */ int heuristique_MP2I(creneau* edt,int len_edt, int grp, date end) { /* A - Both colles end at 7PM : -10 B - Having the same colleur two weeks in a row : -45 C - Having the same colleur at a 3w interval : -25 D - Having the same colleur at a 4w interval : -10 E - Two colles the same day : -20 F - Same date over 2 weeks : -20 */ int end_id = get_next_friday(edt, len_edt, end); // index of first date that is later than end if(end_id == -1) { return 0; } int score = 0; int halt = 0; int remaining = 2; creneau* temp = malloc(sizeof(creneau)*16); int len_temp = 0; //printf("EndId : %d\n", end_id); // A - Colles 7PM (-10) // Check for current week only bool _7pm_1 = false; bool _7pm_2 = false; for(int i = end_id-1; i >= 0+halt; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { score -= 10*(_7pm_1 && _7pm_2); halt = end_id-1; } if(edt[i].group == grp && edt[i].date.hour == 18) { //printf("E\n"); _7pm_2 = _7pm_1; _7pm_1 = true; } } halt = 0; len_temp = 0; // B, C and D : same colleur 2/3/4times in a row (-45) // 4-week check remaining = 4; for(int i = end_id-1; i >= 0+halt; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { remaining -= 1; if(remaining == 0 || i == 0) { bool b = false; int dist = 0; for(int j = 0; j < len_temp; j++) { for(int k = j+1; k < len_temp; k++) { b = str_equal(temp[j].name, temp[k].name); if(b && !(str_equal(temp[j].name, ""))) { dist = date_dist(temp[k].date, temp[j].date); if(dist < 7) { score -= 45; } else if(dist < 14) { score -= 20; } else if(dist < 21) { score -= 10; } } } } halt = end_id-1; } } if(edt[i].group == grp) { temp[len_temp] = edt[i]; len_temp++; } } halt = 0; len_temp = 0; // E - 2 colles the same day (-20) // single-week check for(int i = end_id-1; i >= 0+halt; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { if(len_temp >= 2) { score -= 20*(temp[0].date.day == temp[1].date.day); } halt = end_id-1; } if(edt[i].group == grp) { temp[len_temp] = edt[i]; len_temp++; } } halt = 0; len_temp = 0; // F - Same over 2 weeks (-10) // 2-week check remaining = 2; for(int i = end_id-1; i >= 0+halt; i--) { if(i == 0 || (date_dist(edt[0].date, edt[i].date)%7 == 4 && date_dist(edt[0].date, edt[i+1].date)%7 != 4)) { remaining -= 1; if(remaining == 0 || i == 0) { int dist = 0; for(int j = 0; j < len_temp; j++) { for(int k = j+1; k < len_temp; k++) { dist = date_dist(temp[k].date, temp[j].date); if(dist == 7 && temp[k].date.hour == temp[j].date.hour) { score -= 20; } } } halt = end_id-1; } } if(edt[i].group == grp) { temp[len_temp] = edt[i]; len_temp++; } } halt = 0; len_temp = 0; free(temp); return score; } bool is_equal_date(date d1, date d2) { return (d1.hour == d2.hour && d1.day == d2.day && d2.month == d1.month && d2.year == d1.year); } // typedef struct colleur {char* name; int namelen; topic mat; date* disp; int n_disp;} colleur; colleur* get_colleurs(colleur* cl, int len_cl, date d, int* how_many) { colleur* res = malloc(sizeof(colleur)*20); // max. 3 colles per creneau //printf("X\n"); int ptr = 0; //printf("[]\n"); for(int i = 0; i < len_cl; i++) { for(int j = 0; j < cl[i].n_disp; j++) { if(is_equal_date(cl[i].disp[j], d)) { //printf("%s\n", cl[i].name); if(ptr >= 20) { printf("warning : too many colleurs detected for a creneau\n"); *how_many = 0; return res; } res[ptr] = cl[i]; ptr++; j = cl[i].n_disp; } } } *how_many = ptr; return res; } void aux(int* weeks_len, creneau* edt, int len_edt, colleur* chads, int n_chads, int n_groups, int n_weeks, int current_grp, int current_week, int current_offset, int starting_group, bool is_first) { // append colles for specified week and group //usleep(100000); if(current_week > n_weeks) { printf("Done\n"); assert(0); } else { int n_available_i = 0; int n_available_j = 0; colleur* available_i = malloc(sizeof(colleur)); colleur* available_j = malloc(sizeof(colleur)); int picked_i = 0; int picked_j = 0; bool is_valid_i = false; bool is_valid_j = false; int succ = current_grp+1; if(succ == n_groups+1) { succ = 1; } printf("Colles for week %d, group %d\n", current_week, current_grp); //for(int i = 0; i < weeks_len[current_week]; i++) { // loop for 1st colle for(int i = 0; i < 16; i++) { // loop for 1st colle //printf("+1\n"); //printf("i(%d -> %d)i\n", current_grp, current_offset+i); //printf(" "); //printf("[%d]\n", current_offset+i); //printf("I\n"); if(edt[current_offset+i].group == 0) { free(available_i); //get_colleurs(colleur* cl, int len_cl, date d, int* how_many) { available_i = get_colleurs(chads, n_chads, edt[current_offset+i].date, &n_available_i); if(n_available_i != 0) { // choose someone available picked_i = rand()%n_available_i; // add the 1st colle edt[current_offset+i].group = current_grp; str_copy(available_i[picked_i].name, available_i[picked_i].namelen, edt[current_offset+i].name); edt[current_offset+i].mat = available_i[picked_i].mat; is_valid_i = is_allowed_MP2I(edt, len_edt, current_grp, edt[current_offset+i].date); } else { is_valid_i = false; } if(is_valid_i) { // /!\ DONT FORGET THE RECURSIVE CALL HERE (in case a group has only 1 colle that week) //aux(weeks_len, edt, chads, n_chads, n_groups, n_weeks, current_grp, current_week, current_offset, starting_group, is_first); if(succ == starting_group) { //printf("---------------------------------------------------------\n"); aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, succ, current_week+1, current_offset+weeks_len[current_week-1], succ, true); } else { if(current_grp == n_groups) { aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, current_week, current_offset, starting_group, false); } else { aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp+1, current_week, current_offset, starting_group, is_first); } } } for(int j = 0; j < 16; j++) { // loop for 1st colle //printf("j(%d -> %d)j\n", current_grp, current_offset+j); //printf(" "); //printf("[%d]\n", current_offset+i); //printf("I\n"); if(edt[current_offset+j].group == 0) { free(available_j); //get_colleurs(colleur* cl, int len_cl, date d, int* how_many) { available_j = get_colleurs(chads, n_chads, edt[current_offset+j].date, &n_available_j); if(n_available_j != 0) { // choose someone available picked_j = rand()%n_available_j; // add the 1st colle edt[current_offset+j].group = current_grp; str_copy(available_j[picked_j].name, available_j[picked_j].namelen, edt[current_offset+j].name); edt[current_offset+j].mat = available_i[picked_j].mat; is_valid_j = is_allowed_MP2I(edt, len_edt, current_grp, edt[current_offset+j].date); } else { is_valid_j = false; } if(is_valid_j) { // THE RECURSIVE CALL //aux(weeks_len, edt, chads, n_chads, n_groups, n_weeks, current_grp, current_week, current_offset, starting_group, is_first); if(succ == starting_group) { //printf("---------------------------------------------------------\n"); aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, succ, current_week+1, current_offset+weeks_len[current_week-1], succ, true); } else { if(current_grp == n_groups) { aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, current_week, current_offset, starting_group, false); } else { aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp+1, current_week, current_offset, starting_group, is_first); } } } if(n_available_j != 0) { // remove 2nd colle in case it's blocked edt[current_offset+j].group = 0; edt[current_offset+j].name[0] = '\0'; edt[current_offset+j].mat = NOTHING; } } else { //printf("Occupied 2nd colle\n"); } } if(n_available_i != 0) { // remove 1st colle in case it's blocked edt[current_offset+i].group = 0; edt[current_offset+i].name[0] = '\0'; edt[current_offset+i].mat = NOTHING; } } else { //printf("Occupied 1st colle\n"); } } free(available_i); free(available_j); } //printf("[terminated : group %d with week %d]\n", current_grp, current_week); } void print_arr(int* arr, int len) { printf("["); for(int i = 0; i < len; i++) { printf("%d ", arr[i]); } printf("]\n"); } void generate_colles_v1(creneau* edt, int len_edt, colleur* chads, int n_chads, int n_groups, int n_weeks) { // Fill edt with a colloscope // The final function int* weeks_len = malloc(sizeof(int)*n_weeks); int ptr = 0; int current = 1; for(int k = 1; k < len_edt; k++) { if(date_dist(edt[k-1].date, edt[k].date) > 1 || k == len_edt-1) { weeks_len[ptr] = current + (k == len_edt - 1); current = 0; ptr++; } current++; } weeks_len[3] = 16; print_arr(weeks_len, n_weeks); aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, 1, 0, 1, true); //aux(weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, current_week, current_offset, starting_group, false); free(weeks_len); printf("It's over\n"); }