step 3 works first try

This commit is contained in:
SowinskiBraeden committed 2024-10-11 23:21:40 -07:00
1 parent d1311b27e8
commit 9eeccc1c65
2 files changed
+194 -44

No files matched your search

+192 -43
View File
@@ -53,10 +53,10 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
// uint8_t BLOCKS_PER_SEMESTER = TOTAL_BLOCKS / 2;
// Step 1 - Tally requests to check which courses are eligable to run
/*** STEP 1 - Tally requests to check which courses are eligable to run ***/
char activeCourses[MAX_COURSES][MAX_COURSE_NO_LEN] = {{"\0"}};
size_t activeCoursesIndexes[MAX_COURSES] = {0};
uint16_t activeCourseIndex = 0; // also acts as the length of activeCourses
uint16_t activeCoursesLen = 0; // also acts as the length of activeCourses
for (size_t i = 0; i < size_students; i++) {
for (size_t j = 0; j < students[i].requestsLen; j++) {
if (students[i].requests[j].alternate) continue;
@@ -67,13 +67,13 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
if (strcmp(courses[k].crsNo, students[i].requests[j].crsNo) == 0) {
courses[k].requests++;
if (courses[k].requests >= MIN_REQ) {
if (activeCourseIndex == 0) {
strcpy(activeCourses[activeCourseIndex], courses[k].crsNo);
activeCoursesIndexes[activeCourseIndex] = k;
activeCourseIndex++;
if (activeCoursesLen == 0) {
strcpy(activeCourses[activeCoursesLen], courses[k].crsNo);
activeCoursesIndexes[activeCoursesLen] = k;
activeCoursesLen++;
} else {
bool exists = false;
for (size_t l = 0; l < activeCourseIndex; l++) {
for (size_t l = 0; l < activeCoursesLen; l++) {
if (strcmp(activeCourses[l], courses[k].crsNo) == 0) {
exists = true;
break;
@@ -81,9 +81,9 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
}
if (!exists) {
strcpy(activeCourses[activeCourseIndex], courses[k].crsNo);
activeCoursesIndexes[activeCourseIndex] = k;
activeCourseIndex++;
strcpy(activeCourses[activeCoursesLen], courses[k].crsNo);
activeCoursesIndexes[activeCoursesLen] = k;
activeCoursesLen++;
}
}
}
@@ -94,43 +94,44 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
}
// Step 2 - Generate classes with no students, but calculate the number of expected students per class
/*** STEP 2 - Generate classes with no students, but calculate the number of expected students per class ***/
char hex[] = "0123456789abcdefABCDEF"; // Used to get a unique character to identify different classes of the same course
char hex[] = "0123456789abcdefABCDEF";
uint8_t *allClassRunCounts = malloc(activeCourseIndex * sizeof(uint8_t));
CLASS *emptyClasses = malloc(CLASSROOMS * TOTAL_BLOCKS * sizeof(CLASS)); // max this out to total number of classrooms available between both semesters
size_t currentIndex = 0;
for (size_t i = 0; i < activeCourseIndex; i++) {
uint8_t *allClassRunCounts = malloc(activeCoursesLen * sizeof(uint8_t));
// max this out to total number of classrooms available between both semesters
CLASS *classes = malloc(CLASSROOMS * TOTAL_BLOCKS * sizeof(CLASS));
size_t classesLen = 0;
for (size_t i = 0; i < activeCoursesLen; i++) {
uint16_t index = activeCoursesIndexes[i];
uint8_t classRunCount = floor((float) courses[index].requests / MEDIAN);
uint8_t remaining = courses[index].requests % MEDIAN;
size_t *courseClassIndexes = malloc((classRunCount + 1) * sizeof(size_t)); // add 1 to classRunCount in case we need to create an extra class with remaining
// add 1 to classRunCount in case we need to create an extra class with remaining
size_t *courseClassIndexes = malloc((classRunCount + 1) * sizeof(size_t));
for (size_t j = 0; j < classRunCount; j++) {
CLASS newClass;
char courseID[MAX_COURSE_NO_LEN + 3]; // +3 = "_n\0" where n is the ID
strcpy(newClass.baseCrsNo, courses[index].crsNo);
char courseID[MAX_COURSE_ID_LEN];
strcpy(courseID, courses[index].crsNo);
appendChar(courseID, hex[j]);
strcpy(newClass.crsNo, courseID);
strcpy(newClass.description, courses[index].description);
newClass.numberOfStudents = MEDIAN; // The expected number of students in this class
// CLASS_HASH emptyClass;
// strcpy(emptyClass.key, courses[index].crsNo);
// emptyClass.class = newClass;
// emptyClasses[currentIndex] = emptyClass;
emptyClasses[currentIndex] = newClass;
courseClassIndexes[j] = currentIndex;
currentIndex++;
classes[classesLen] = newClass;
courseClassIndexes[j] = classesLen;
classesLen++;
}
// Handle remaining requests
//*** Handle remaining requests ***/
// Can we add remaining requests to existing classes
bool remainingFitsInExistingClasses = remaining <= classRunCount * (CLASS_CAP - MEDIAN);
// Can we create a new class using only remaining requests
bool remainingCanCreateNewClass = remaining >= MIN_REQ;
// Can we create a new class if we borrow students from created classes to add to remaining requests to meet min req
bool remainingPlusExtraFromExistingCanCreateNewClass = MIN_REQ - remaining < classRunCount * (MEDIAN - MIN_REQ);
@@ -138,7 +139,7 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
// Simply add remaining to existing classes
while (remaining > 0) {
for (size_t j = 0; j < classRunCount; j++) {
emptyClasses[courseClassIndexes[j]].numberOfStudents++;
classes[courseClassIndexes[j]].numberOfStudents++;
remaining--;
if (remaining == 0) break;
}
@@ -147,7 +148,8 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
} else if (remainingCanCreateNewClass) {
// Create new class
CLASS newClass;
char courseID[MAX_COURSE_NO_LEN + 3]; // +3 = "_n\0" where n is the ID
strcpy(newClass.baseCrsNo, courses[index].crsNo);
char courseID[MAX_COURSE_ID_LEN];
strcpy(courseID, courses[index].crsNo);
appendChar(courseID, hex[classRunCount]);
strcpy(newClass.crsNo, courseID);
@@ -155,20 +157,20 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
newClass.numberOfStudents = remaining;
// Insert class into empty classes array and update index
emptyClasses[currentIndex] = newClass;
courseClassIndexes[classRunCount] = currentIndex;
currentIndex++;
classes[classesLen] = newClass;
courseClassIndexes[classRunCount] = classesLen;
classesLen++;
// update class run count; if there is more than one class, equalize the class number of students
classRunCount++;
if (classRunCount >= 2) {
uint8_t *numberOfStudentsArr = malloc(classRunCount * sizeof(uint8_t));
for (size_t j = 0; j < classRunCount; j++)
numberOfStudentsArr[j] = emptyClasses[courseClassIndexes[j]].numberOfStudents;
numberOfStudentsArr[j] = classes[courseClassIndexes[j]].numberOfStudents;
numberOfStudentsArr = equal(numberOfStudentsArr, classRunCount);
for (size_t j = 0; j < classRunCount; j++)
emptyClasses[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
classes[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
free(numberOfStudentsArr);
}
@@ -177,7 +179,7 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
// Take 1 student from each existing class till min requirement is met
while (remaining < MIN_REQ) {
for (size_t j = 0; j < classRunCount; j++) {
emptyClasses[courseClassIndexes[j]].numberOfStudents--;
classes[courseClassIndexes[j]].numberOfStudents--;
remaining++;
if (remaining == MIN_REQ) break;
}
@@ -185,7 +187,8 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
// Create new class with remaining
CLASS newClass;
char courseID[MAX_COURSE_NO_LEN + 3]; // +3 = "_n\0" where n is the ID
strcpy(newClass.baseCrsNo, courses[index].crsNo);
char courseID[MAX_COURSE_ID_LEN];
strcpy(courseID, courses[index].crsNo);
appendChar(courseID, hex[classRunCount]);
strcpy(newClass.crsNo, courseID);
@@ -193,19 +196,19 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
newClass.numberOfStudents = remaining;
// Insert class into empty classes array and update index
emptyClasses[currentIndex] = newClass;
courseClassIndexes[classRunCount] = currentIndex;
currentIndex++;
classes[classesLen] = newClass;
courseClassIndexes[classRunCount] = classesLen;
classesLen++;
classRunCount++;
// Equalize the class number of students
uint8_t *numberOfStudentsArr = malloc(classRunCount * sizeof(uint8_t));
for (size_t j = 0; j < classRunCount; j++)
numberOfStudentsArr[j] = emptyClasses[courseClassIndexes[j]].numberOfStudents;
numberOfStudentsArr[j] = classes[courseClassIndexes[j]].numberOfStudents;
numberOfStudentsArr = equal(numberOfStudentsArr, classRunCount);
for (size_t j = 0; j < classRunCount; j++)
emptyClasses[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
classes[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
free(numberOfStudentsArr);
@@ -220,13 +223,13 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
bool full = false;
while (!full) {
for (size_t j = 0; j < classRunCount; j++) {
if (emptyClasses[courseClassIndexes[classRunCount - 1]].numberOfStudents == CLASS_CAP) {
if (classes[courseClassIndexes[classRunCount - 1]].numberOfStudents == CLASS_CAP) {
// If the last class in the array is at class_cap, all other classes must be at class cap and we are full
full = true;
break;
}
emptyClasses[courseClassIndexes[j]].numberOfStudents++;
classes[courseClassIndexes[j]].numberOfStudents++;
remaining--;
}
}
@@ -236,9 +239,155 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
allClassRunCounts[i] = classRunCount;
}
// realloc classes to correct size
CLASS *tempclasses = malloc(classesLen * sizeof(CLASS));
for (size_t i = 0; i < classesLen; i++)
tempclasses[i] = classes[i];
classes = realloc(classes, classesLen * sizeof(CLASS));
memcpy(classes, tempclasses, classesLen * sizeof(CLASS));
free(tempclasses);
/*** STEP 3 - Insert students into empty classes ... yikes ***/
STUDENT *tempStudents = malloc(size_students * sizeof(STUDENT));
size_t size_tempStudents = size_students;
memcpy(tempStudents, students, size_students * sizeof(STUDENT));
uint8_t *currentInserted = malloc(classesLen * sizeof(uint8_t));
for (size_t i = 0; i < classesLen; i++)
currentInserted[i] = 0;
while (size_tempStudents > 0) {
// Choose student at random, to prevent success bias to students first in the array
STUDENT student = tempStudents[rand() % size_tempStudents];
// printf("pupilNum: %d\n", student.pupilNum);
// Create an array of students alternates
size_t numberOfAlts = 0;
for (size_t i = 0; i < student.requestsLen; i++)
if (student.requests[i].alternate)
numberOfAlts++;
REQUEST *alternates = malloc(numberOfAlts * sizeof(REQUEST));
size_t alternateIdx = 0;
for (size_t i = 0; i < student.requestsLen; i++) {
if (student.requests[i].alternate) {
alternates[alternateIdx] = student.requests[i];
alternateIdx++;
}
}
// Search existing classes to insert student based off request
for (size_t i = 0; i < student.requestsLen; i++) {
if (student.requests[i].alternate) continue; // Ignore alternates
char course[MAX_COURSE_NO_LEN] = {"\0"};
strcpy(course, student.requests[i].crsNo);
bool getAvailableCourse = true;
bool isAlt = false;
// printf("getting available course for %s...\n", course);
while (getAvailableCourse) {
// printf("searching...\n");
for (size_t j = 0; j < classesLen; j++) {
// Class exists in classes
// printf("comparing target %s to %s at idx %ld\n", course, classes[j].crsNo, j);
if (strcmp(classes[j].baseCrsNo, course) == 0) {
// printf("course %s exists\n", course);
// If this is an alternate, and there is room to expand, increase number of students to allow extra
if (isAlt && classes[j].numberOfStudents < CLASS_CAP)
classes[j].numberOfStudents++;
// Class exists with room for student
if (currentInserted[j] < classes[j].numberOfStudents) {
classes[j].students[currentInserted[j]] = student.pupilNum;
currentInserted[j]++;
getAvailableCourse = false;
break;
} else if (currentInserted[j] == classes[j].numberOfStudents) {
// If class is full, and there's no more classes available for that course, convert to alt
if (j == classesLen - 1 || (j != classesLen - 1 && strcmp(classes[j + 1].baseCrsNo, course) != 0)) {
if (numberOfAlts > 0) {
// Use alternate
strcpy(course, alternates[0].crsNo); // asign alternate to course and retry
// remove alternate from array of alts to retry same alt over and over
REQUEST *tempAlternates = malloc(numberOfAlts * sizeof(REQUEST));
memcpy(tempAlternates, alternates, numberOfAlts * sizeof(REQUEST));
numberOfAlts--;
alternates = realloc(alternates, numberOfAlts * sizeof(REQUEST));
for (size_t k = 1; k <= numberOfAlts; k++)
alternates[k - 1] = tempAlternates[k];
free(tempAlternates);
isAlt = true;
break;
} else {
// Force break the loop, ignore as it cannot be resolved
// Allow administrator to handle error manually
getAvailableCourse = false;
break;
}
}
}
// this class does not exist, i.e not enough requests
} else if (j == classesLen - 1) {
// printf("course %s does not exist\n", course);
if (numberOfAlts > 0) {
// Use alternate
strcpy(course, alternates[0].crsNo); // asign alternate to course and retry
// remove alternate from array of alts to retry same alt over and over
REQUEST *tempAlternates = malloc(numberOfAlts * sizeof(REQUEST));
memcpy(tempAlternates, alternates, numberOfAlts * sizeof(REQUEST));
numberOfAlts--;
alternates = realloc(alternates, numberOfAlts * sizeof(REQUEST));
for (size_t k = 1; k <= numberOfAlts; k++)
alternates[k - 1] = tempAlternates[k];
free(tempAlternates);
isAlt = true;
break;
} else {
// Force break the loop, ignore as it cannot be resolved
// Allow administrator to handle error manually
getAvailableCourse = false;
break;
}
}
}
}
// printf("got available course for %s...\n", course);
}
// Asign remaining alternates to student
for (size_t i = 0; i < size_students; i++) {
if (students[i].pupilNum == student.pupilNum) {
students[i].remainingAlts = realloc(students[i].remainingAlts, numberOfAlts * sizeof(REQUEST));
memcpy(students[i].remainingAlts, alternates, numberOfAlts * sizeof(REQUEST));
students[i].remainingAltsLen = numberOfAlts;
break;
}
}
free(alternates);
// realloc tempStudents to be size_tempStudents - 1 without struct of student just processed
size_tempStudents--;
STUDENT *new_tempStudents = malloc(size_tempStudents * sizeof(STUDENT));
size_t idx = 0;
for (size_t i = 0; i <= size_tempStudents; i++) {
if (tempStudents[i].pupilNum != student.pupilNum) {
new_tempStudents[idx] = tempStudents[i];
idx++;
}
}
tempStudents = realloc(tempStudents, size_tempStudents * sizeof(STUDENT));
memcpy(tempStudents, new_tempStudents, size_tempStudents * sizeof(STUDENT));
free(new_tempStudents);
}
free(currentInserted);
free(tempStudents);
// DO MORE ALGORITHM
free(emptyClasses);
free(classes);
free(allClassRunCounts);
return timetable;