diff --git a/algorithm.c b/algorithm.c deleted file mode 100644 index ce05418..0000000 --- a/algorithm.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* - * Colloscope - A program that generates a colloscope for French 'classes prépas' - * Copyright (C) 2024 Alexandre Aboujaib - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include -#include - -#include "logger.h" -#include "structure.h" -#include "algorithm.h" - -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); -} - -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)); -} - -/* Feuilles mortes (--> ligne WYSI (727)) : - -bool is_allowed_MP2I(creneau* edt, int len_edt, int grp, date end) { - bool debug = false; - - conditions (AND) : - * 0) Only 1 colle at a time - * 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) { - stats[4]++; - return true; - } - - int offs = get_date_index(edt, len_edt, end); - - //printf("EndId : %d\n", end_id); - // 0) - int id = 1; - while(id >= 0 && id < len_edt && is_equal_date(edt[offs+id].date, end)) { - if(str_equal(edt[offs+id].name, edt[offs].name)) { - if(debug) { - printf("Unable to duplicate colleur %s\n", edt[offs].name); - } - stats[0]++; - return false; - } - id++; - } - id = -1; - while(id >= 0 && id < len_edt && is_equal_date(edt[offs+id].date, end)) { - if(str_equal(edt[offs+id].name, edt[offs].name)) { - if(debug) { - printf("Unable to duplicate colleur %s\n", edt[offs].name); - } - stats[0]++; - return false; - } - 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--) { - //for(int i = -1; i >= 0; i--) { - if(i != end_id-1 && (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) { - if(debug) { - printf("Invalid number of english/physics colle at index %d for group %d (found %d)\n", i, grp, agl+pc); - } - stats[1]++; - return false; - } else if(has_to_be == 'p' && pc != 1) { - if(debug) { - printf("Wrong number of physics colle at index %d for group %d\n", i, grp); - } - stats[1]++; - return false; - } else if(has_to_be == 'a' && agl != 1) { - if(debug) { - printf("Wrong number of english colle at index %d for group %d\n", i, grp); - } - stats[1]++; - 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 - // version 2 - - int math = 0; - int abort_2 = 0; - for(int i = end_id-1; i >= 0+abort_2*(end_id); 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)) { - abort_2 = 1; - if(n_colles[grp-1] == 3) { - if(math != 0) { - if(debug) { - printf("Invalid number of math colles at index %d for group %d (found %d)\n", i, grp, math); - } - stats[2]++; - return false; - } - } else { - if(math != 1) { - if(debug) { - printf("Invalid number of math colles at index %d for group %d (found %d)\n", i, grp, math); - } - stats[2]++; - return false; - } - } - } - if(edt[i].group == grp && edt[i].mat == MATH) { - math += 1; - } - } - - int t = 0; - int math = 0; - int last_no_math = -1; - bool not_seen_empty = 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)) { - //if(i == 0 || i%16 == 15) { - t++; - if(math != 1 && math != 0) { - if(debug) { - printf("Invalid number of math colles at index %d for group %d (found %d)\n", i, grp, math); - } - stats[2]++; - return false; - } else if(math == 0) { - if(!not_seen_empty && last_no_math != -1 && last_no_math != 3) { - if(debug) { - printf("Invalid rotation of math colles at index %d for group %d\n", i, grp); - } - //rintf("--> %d <--\n", t); - stats[2]++; - return false; - } - last_no_math = 0; - not_seen_empty = false; - } else { - if(last_no_math > 3) { - if(debug) { - printf("Too many math colles at index %d for group %d\n", i, grp); - } - stats[2]++; - return false; - } - if(last_no_math == -1) { - last_no_math++; - } - last_no_math++; - } - math = 0; - } - if(edt[i].group == grp && edt[i].mat == MATH) { - math += 1; - } - } - if(last_no_math > 3) { - if(debug) { - printf("Too many math colles at index %d for group %d\n", 0, grp); - } - stats[2]++; - return false; - } - - // 3) Count - int ncolles = 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(ncolles != 1 && ncolles != 2) { - //if(ncolles != n_colles[grp-1]) { - if(debug) { - printf("Invalid number of colles at index %d for group %d (found %d)\n", i, grp, ncolles); - } - stats[3]++; - return false; - } - ncolles= 0; - } - if(edt[i].group == grp) { - ncolles++; - } - } - - // 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) { - if(debug) { - printf("Invalid number of info colles at index %d for group %d\n", i, grp); - } - stats[4]++; - return false; - } else if(inf == 0) { - last_no_inf = 0; - } else if(last_no_inf > 5) { - if(debug) { - printf("Too few info colles at index %d for group %d\n", i, grp); - } - stats[4]++; - 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; -} -*/ -// 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)*30); // max. 3 colles per creneau - //printf("X\n"); - int ptr = 0; - 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 >= 30) { - warn("Too many colleurs detected for a creneau\n"); - } - res[ptr] = cl[i]; - ptr++; - j = cl[i].n_disp; - } - } - } - *how_many = ptr; - return res; -} - -void swap(int* arr, int i, int j) { - if(i != j) { - arr[i] += arr[j]; - arr[j] = arr[i] - arr[j]; - arr[i] -= arr[j]; - } -} - -void generate_random_perm(int* arr, int len) { - // generate a random perm of int between 0 and len-1 - for(int i = 0; i < len; i++) { - arr[i] = i; - } - for(int i = 0; i < len; i++) { - swap(arr, i, rand()%len); - } -} - -void print_arr(int* arr, int len) { - printf("["); - for(int i = 0; i < len; i++) { - printf("%d ", arr[i]); - } - printf("]\n"); -} - -/* -void shiftright_ncolles(int n_grps) { - for(int i = 0; i < n_grps; i++) { - n_colles[i] = (n_colles[i]+1)%4; - } -} - -void shiftleft_ncolles(int n_grps) { - for(int i = 0; i < n_grps; i++) { - if(n_colles[i] == 0) { - n_colles[i] = 3; - } else { - n_colles[i]--; - } - } -} - -void aux(int* abort, 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); - print_arr(stats, 10); - if(current_week > n_weeks) { - printf("Done\n"); - *abort = true; - } 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 pass_i; - bool pass_j; - bool is_valid_i = false; - bool is_valid_j = false; - int* perms_i = malloc(sizeof(int)*30); - int* perms_j = malloc(sizeof(int)*30); - int succ = current_grp+1; - if(succ == n_groups+1) { - succ = 1; - } - - printf("Colles for week %d, group %d {%d}\n", current_week, current_grp, (1-(*abort))*weeks_len[current_week-1]); - - //for(int i = 0; i < weeks_len[current_week]; i++) { // loop for 1st colle - for(int i = 0; i < (1-(*abort))*weeks_len[current_week-1]; 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) { - generate_random_perm(perms_i, n_available_i); - for(int ii = 0; ii < n_available_i; ii++) { - picked_i = perms_i[ii]; - - if(n_colles[current_grp-1] == 3) { - pass_i = available_i[picked_i].mat == PHYSICS || available_i[picked_i].mat == ENGLISH; - } else { - pass_i = available_i[picked_i].mat == MATH; - } - if(pass_i) { - // 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, 'i'); - - if(is_valid_i && *abort == 0) { - // /!\ 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"); - shiftright_ncolles(n_groups); - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp, current_week+1, current_offset+weeks_len[current_week-1], current_grp, true); - shiftleft_ncolles(n_groups); - } else { - if(current_grp == n_groups) { - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, current_week, current_offset, starting_group, false); - } else { - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp+1, current_week, current_offset, starting_group, is_first); - } - } - } else { - stats[8]++; - } - - for(int j = 0; j < (1-(*abort))*weeks_len[current_week-1]*(n_colles[current_grp-1] != 3); j++) { // loop for 2nd 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) { - generate_random_perm(perms_j, n_available_j); - for(int jj = 0; jj < n_available_j; jj++) { - // choose someone available - //picked_j = rand()%n_available_j; - picked_j = perms_j[jj]; - - if(available_j[picked_j].mat != MATH) { - - // 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, 'j'); - - if(is_valid_j && *abort == 0) { - // 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"); - shiftright_ncolles(n_groups); - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp, current_week+1, current_offset+weeks_len[current_week-1], current_grp, true); - shiftleft_ncolles(n_groups); - } else { - if(current_grp == n_groups) { - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, 1, current_week, current_offset, starting_group, false); - } else { - aux(abort, weeks_len, edt, len_edt, chads, n_chads, n_groups, n_weeks, current_grp+1, current_week, current_offset, starting_group, is_first); - } - } - } else { - stats[9]++; - } - - if(*abort == 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(*abort == 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); - free(perms_i); - free(perms_j); - } - //printf("[terminated : group %d with week %d]\n", current_grp, current_week); -} - -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++; - } - - print_arr(weeks_len, n_weeks); - - stats = malloc(sizeof(int)*10); - for(int i = 0; i < 10; i++) { - stats[i] = 0; - } - - n_colles = malloc(sizeof(int)*n_groups); - for(int i = 0; i < n_groups; i++) { - n_colles[i] = i%4; - } - // invariant : if n_colles[grp-1] = 3 then grp has only 1 colle that week - - - //print_arr(n_colles, n_groups); - //assert(0); - - printf("Entering aux\n"); - int abort = 0; - int* ptrbool = &abort; - aux(ptrbool, 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); - system("clear"); - - print_one_week(edt, len_edt, edt[0].date); - printf("\n"); - print_one_week(edt, len_edt, edt[16].date); - printf("\n"); - print_one_week(edt, len_edt, edt[32].date); - printf("\n"); - print_one_week(edt, len_edt, edt[48].date); - - free(weeks_len); - free(stats); - free(n_colles); - printf("It's over\n"); -} -*/ -// ----------------------------------------------------- // -// ------------------| NEW ALGORITHM |------------------ // -// ----------------------------------------------------- // -void add_colle(creneau* edt, colleur* chads, int grp, int id_edt, int id_chad) { - edt[id_edt].group = grp; - edt[id_edt].namelen = chads[id_chad].namelen; - str_copy(chads[id_chad].name, chads[id_chad].namelen, edt[id_edt].name); - edt[id_edt].mat = chads[id_chad].mat; - //printf("%s %d\n", chads[id_chad].name, chads[id_chad].namelen); - //printf("{%d %s %d %d %d}\n", edt[id_edt].group, edt[id_edt].name, edt[id_edt].namelen, (int)(edt[id_edt].mat), id_edt); -} - -void remove_colle(creneau* edt, int id_edt) { - edt[id_edt].group = 0; - edt[id_edt].namelen = 0; - str_copy("none", 4, edt[id_edt].name); - edt[id_edt].mat = NOTHING; -} - -void move_colle(creneau* edt, int len_edt, int id_src, int id_dest) { - if((id_src < len_edt && id_src >= 0 && id_dest < len_edt && id_dest >= 0) == false) { - printf("Bad\n"); - exit(1); - } - - edt[id_dest].group = edt[id_src].group; - edt[id_dest].namelen = edt[id_src].namelen; - str_copy(edt[id_src].name, edt[id_src].namelen, edt[id_dest].name); - edt[id_dest].mat = edt[id_src].mat; - - remove_colle(edt, id_src); -} - -void swap_colle(creneau* edt, int len_edt, int id_src, int id_dest) { - if((id_src < len_edt && id_dest < len_edt) == false) { - printf("Bad\n"); - exit(1); - } - int dest_grp = edt[id_dest].group; - - edt[id_dest].group = edt[id_src].group; - - //printf("%d %d\n", edt[id_src].group, dest_grp); - //edt[id_src].group = edt[id_src].group; -} - -int mem_id(creneau* edt, int len_edt, int grp, char* colleur) { - for(int i = 0; i < len_edt; i++) { - if(edt[i].group == grp && str_equal(edt[i].name, colleur)) { - return i; - } - } - return -1; -} - -bool is_overlap(creneau* edt, int len_edt, int id) { // detect if a colleur has 2 colles at the same time - int k = 1; - while(id+k < len_edt && is_equal_date(edt[id].date, edt[id+k].date)) { - if(str_equal(edt[id].name, edt[id+k].name)) { - return true; - } - k++; - } - k = 1; - while(id-k >= 0 && is_equal_date(edt[id].date, edt[id-k].date)) { - if(str_equal(edt[id].name, edt[id-k].name)) { - return true; - } - k++; - } - return false; -} - -bool is_overlap_creneau(creneau* edt, int len_edt, int id, int grp) { // detect if a group has 2 overlapping colles - int k = 1; - while((id+k < len_edt && edt[id+k].date.hour - edt[id].date.hour < edt[id].length) && edt[id+k].date.day == edt[id].date.day) { - if(edt[id+k].group == grp) { - return true; - } - k++; - } - k = 1; - while(id-k >= 0 && is_equal_date(edt[id].date, edt[id-k].date)) { - if(edt[id+k].group == grp) { - return true; - } - k++; - } - return false; -} - -int free_math_space(creneau* edt, int len_edt, int id) { - int k = 1; - int howmany = 0; - while(id+k < len_edt && is_equal_date(edt[id].date, edt[id+k].date)) { - if(edt[id+k].mat == NOTHING || edt[id+k].mat == MATH) { - howmany++; - } - k++; - } - k = 1; - while(id-k >= 0 && is_equal_date(edt[id].date, edt[id-k].date)) { - if(edt[id-k].mat == NOTHING || edt[id-k].mat == MATH) { - howmany++; - } - k++; - } - return howmany; -} - -void add_colles_for_group_MP2I(int* weeks_len, creneau* edt, int len_edt, colleur* chads, int len_chads, int n_weeks, int grp, topic start_rotation, int mth, int inf, int* skip_count) { - topic rotation = start_rotation; // physics/english rotation - int math = mth; // math (3/4) - int info = inf; // info (1/6) - - int r; // randomize the 1st date - int k = 0; // offset - int halt = 0; // timeout in case a colle cannot be placed - bool found; // interrupt in case a valid colle has been found - - int remaining_to_add = 0; /* self-explainatory - please note that this also tells what colle to add : - 1 = physics/english colle - 2 = math - 3 (not implemented) = info - */ - int len_dudes = 0; // length of colleur* - - int len_perm = 0; // length of int* - - int math_dude = 0; // length of colleur* - int weeklen; - - //printf("\n"); - for(int week = 0; week < n_weeks; week++) { - - weeklen = weeks_len[week]; - // update what colles to add - if(math == 0) { - math = 2; - } else { - remaining_to_add++; - math--; - } - if(rotation == ENGLISH) { - rotation = PHYSICS; - } else { - rotation = ENGLISH; - } - - remaining_to_add++; // physics/english - //printf("%d -> (%d %d)\n", grp, week, remaining_to_add); - - // initialize/reset variables - r = rand()%weeklen; - halt = 0; - found = false; - - info++; - // info colle - while(info >= 6) { - if(edt[k+r%weeklen].group == 0 && edt[k+r%weeklen].length == 2) { - // if creneau is empty - // import all colleurs available - colleur* dudes = get_colleurs(chads, len_chads, edt[k+r%weeklen].date, &len_dudes); - len_perm = len_dudes; - - // if there are colleurs available - if(len_dudes != 0) { - - // randomize the order of colleurs - int* perm = malloc(sizeof(int)*len_perm); - generate_random_perm(perm, len_perm); - - // for each one of them, add his colle for selected group pf and only if - // - he is a INFO colleur - // if a colle has been addded, interrupt the for and while loops - for(int dude = 0; dude < len_perm*(1-found); dude++) { - if(dudes[perm[dude]].mat == INFO && !is_overlap_creneau(edt, len_edt, k+r%weeklen, grp)) { - add_colle(edt, dudes, grp, k+r%weeklen, perm[dude]); - found = true; - info = 0; - } - } - free(perm); - } - free(dudes); - } - if(!found && halt > weeklen) { - info = 0; - printf("Warning : skipping info colle for week %d and group %d\n", week+1, grp); - *skip_count += 1; - } - r++; - halt++; - } - // reset the variables - r = rand()%weeklen; - found = false; - halt = 0; - - // if there is a math colle to add, enter this loop - while(remaining_to_add == 2) { - - if(edt[k+r%weeklen].mat == NOTHING && edt[k+r%weeklen].length == 1) { - // if creneau is empty - // import all colleurs available - colleur* dudes = get_colleurs(chads, len_chads, edt[k+r%weeklen].date, &len_dudes); - len_perm = len_dudes; - - // if there are colleurs available - if(len_dudes != 0) { - - // randomize the order of colleurs - int* perm = malloc(sizeof(int)*len_perm); - generate_random_perm(perm, len_perm); - - // for each one of them, add his colle for selected group pf and only if - // - he is a MATH colleur - // - he does not have another colle at the same time (is_overlap) - // if a colle has been addded, interrupt the for andwhile loops - for(int dude = 0; dude < len_perm*(1-found); dude++) { - if(dudes[perm[dude]].mat == MATH) { - add_colle(edt, dudes, grp, k+r%weeklen, perm[dude]); - if(is_overlap(edt, len_edt, k+r%weeklen)) { - remove_colle(edt, k+r%weeklen); - } else { - found = true; - remaining_to_add--; - //printf("+math for week %d and group %d (index %d)\n", week, grp, k+r%weeklen); - } - } - } - free(perm); - } - free(dudes); - } - if(!found && halt > weeklen) { - remaining_to_add--; - //printf("Warning : skipping math colle for week %d and group %d\n", week+1, grp); - *skip_count += 1; - } - r++; - halt++; - } - // reset the variables - r = rand()%weeklen; - found = false; - halt = 0; - - // do it again for physics/english colles - while(remaining_to_add == 1) { - if(edt[k+r%weeklen].mat == NOTHING && edt[k+r%weeklen].length == 1) { - colleur* dudes = get_colleurs(chads, len_chads, edt[k+r%weeklen].date, &len_dudes); - len_perm = len_dudes; - if(len_dudes != 0) { - int* perm = malloc(sizeof(int)*len_perm); - generate_random_perm(perm, len_perm); - math_dude = 0; - for(int dude = 0; dude < len_dudes; dude++) { - if(dudes[dude].mat == MATH) { - math_dude++; - } - } - for(int dude = 0; dude < len_perm*(1-found); dude++) { - //printf("%d\n", chads[perm[dude]]); - if(dudes[perm[dude]].mat == rotation) { - add_colle(edt, dudes, grp, k+r%weeklen, perm[dude]); - if(math_dude > free_math_space(edt, len_edt, k+r%weeklen) || is_overlap(edt, len_edt, k+r%weeklen)) { - //if(math_dude > free_math_space(edt, len_edt, k+r%weeklen)) { - remove_colle(edt, k+r%weeklen); - } else { - found = true; - remaining_to_add--; - ///rintf("+secondary for week %d and group %d (index %d)\n", week, grp, k+r%weeklen); - } - } - } - free(perm); - } - free(dudes); - } - if(!found && halt > weeks_len[week]) { - remaining_to_add--; - //printf("Warning : skipping secondary colle for week %d and group %d\n", week+1, grp); - *skip_count += 1; - } - r++; - halt++; - } - - k += weeks_len[week]; - remaining_to_add = 0; - } -} - -void write_to_file(char* filename, creneau* edt, int len_edt) { - FILE* ptr = fopen(filename, "w"); - fprintf(ptr, "hour,day,month,year,length,group,colleur,matiere\n"); - for(int i = 0; i < len_edt; i++) { - fprintf(ptr, "%d,%d,%d,%d,%d,%d,%s,", edt[i].date.hour, edt[i].date.day, edt[i].date.month, edt[i].date.year, edt[i].length, edt[i].group, edt[i].name); - if(edt[i].mat == NOTHING) { - fprintf(ptr, "_"); - } else if(edt[i].mat == MATH) { - fprintf(ptr, "Maths"); - } else if(edt[i].mat == PHYSICS) { - fprintf(ptr, "Physique"); - } else if(edt[i].mat == ENGLISH) { - fprintf(ptr, "Anglais"); - } else if(edt[i].mat == INFO) { - fprintf(ptr, "Info"); - } else if(edt[i].mat == FRENCH) { - fprintf(ptr, "Français"); - } else { - fprintf(ptr, "Unknown"); - } - fprintf(ptr, "\n"); - } - fclose(ptr); -} - -int min(int x, int y) { - if(x < y) { - return x; - } - return y; -} - -int max(int x, int y) { - if(x > y) { - return x; - } - return y; -} - -int score(creneau* edt, int len_edt, int grp, int n_weeks) { - int score = 100; - - int dist = 0; - for(int i = 0; i < len_edt; i++) { - for(int j = i+1; j < len_edt; j++) { - if(edt[i].group == grp && edt[j].group == grp) { - dist = date_dist(edt[i].date, edt[j].date); - if(dist == 0) { - score -= 4; - } - /*if(str_equal(edt[i].name, edt[j].name)) { - score -= max(0, 28-dist); - }*/ - if(dist == 7 && edt[i].date.hour == edt[j].date.hour) { - score -= 5; - } - if(dist < 5 && edt[i].date.hour == 18 && edt[j].date.hour == 18) { - score -= 10; - } - } - } - } - - char** met = malloc(sizeof(char*)*3*n_weeks); - int p = 0; - for(int i = 0; i < len_edt; i++) { - //printf("%d\n", i); - if(edt[i].group == grp) { - met[p] = malloc(sizeof(char)*30); - str_copy(edt[i].name, edt[i].namelen, met[p]); - for(int k = p-1; k >= 0; k--) { - if(str_equal(met[k], met[p])) { - switch(edt[i].mat) { - case MATH: - score -= 15; - break; - case PHYSICS: - score -= 15; - break; - case ENGLISH: - score -= 15; - break; - default: - break; - } - } - } - p++; - } - } - - for(int f = 0; f < p; f++) { - free(met[f]); - } - free(met); - return score; -} - -int get_colleur_id(colleur* dudes, int n_dudes, char* target) { - for(int i = 0; i < n_dudes; i++) { - if(str_equal(dudes[i].name, target)) { - return i; - } - } - return -1; -} - -char* get_name_from_id(colleur* dudes, int n_dudes, int id) { - for(int i = 0; i < n_dudes; i++) { - if(id == dudes[i].id) { - //printf("{%s}", dudes[i].name); - return dudes[i].name; - } - } - return "none"; -} - -topic get_mat_from_id(colleur* dudes, int n_dudes, int id) { - for(int i = 0; i < n_dudes; i++) { - if(id == dudes[i].id) { - return dudes[i].mat; - } - } - return NOTHING; -} - -void aux_2(creneau* edt, int len_edt, colleur* chads, int len_chads, int n_groups, int n_weeks, int n_sim, char* outname) { - int start = time(NULL); - int* weeks_len = malloc(sizeof(int)*n_weeks); - // this list is used to tell the above code what index of edt it has to go to search for a colle - 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++; - } - - int* group_stats = malloc(sizeof(int)*n_groups); - int* group_temp = malloc(sizeof(int)*n_groups); - - int max_score = -900000; - int global_min = 0; - int global_skipped = 0; - int screwed_group = 0; - int local_score = 0; - int local_min = 0; - int local_group = 0; - int temp = 0; - int skipped = 0; - int a = 0; - info("Testing %d combinations...", n_sim); - printf("\n"); - for(int k = 0; k < n_sim*(1 - (max_score == n_groups*100)); k++) { - if(k >= a) { - printf("\x1b[1F"); - printf("\x1b[2K"); - printf("%d%% Completed (current max is %d/%d)\n", 100*a/n_sim, max_score, 100*n_groups); - a += n_sim/100; - } - local_score = 0; - local_min = 100; - skipped = 0; - for(int i = 0; i < n_groups; i++) { - //for(int i = 0; i < 1; i++) { - //rintf("Adding colles for group %d...\n", i+1); - //add_colles_for_group_MP2I(weeks_len, edt, len_edt, chads, len_chads, n_weeks, i+1, (topic)(2+i%2), i%4, i%6, &skipped); - add_colles_for_group_MP2I(weeks_len, edt, len_edt, chads, len_chads, n_weeks, i+1, (topic)(2+i%2), i%3, -20, &skipped); - } - for(int i = 0; i < n_groups; i++) { - //printf("Score for group %d : %d\n", i+1, score(edt, len_edt, i+1)); - temp = score(edt, len_edt, i+1, n_weeks); - local_score += temp; - group_temp[i] = temp; - if(local_min > temp) { - local_min = temp; - local_group = i+1; - } - } - local_score -= skipped*30; - if(local_score > max_score) { - max_score = local_score; - screwed_group = local_group; - global_min = local_min; - global_skipped = skipped; - for(int p = 0; p < n_groups; p++) { - group_stats[p] = group_temp[p]; - } - write_to_file(outname, edt, len_edt); - } - for(int r = 0; r < len_edt; r++) { - remove_colle(edt, r); - } - } - - printf("\x1b[1F"); - printf("\x1b[2K"); - if(max_score == 100*n_groups) { - info("Interrupting early due to a perfect score achieved"); - } else { - info("100%% Completed, best score is %d/%d (without skip penalty) with %d skipped colle(s)", max_score+global_skipped*30, 100*n_groups, global_skipped); - info("Most screwed group is %d with a score of %d/100", screwed_group, global_min); - debug("Stats for all groups are :"); - for(int i = 0; i < n_groups; i++) { - debug("Group %d : %d/100", i+1, group_stats[i]); - } - } - int end = time(NULL); - info("Took %ds to find", end-start); - free(group_stats); - free(group_temp); - free(weeks_len); -} - - - - - - -