begin refactor
This commit is contained in:
10 files changed
+323
-445
No files matched your search
+3
-1
@@ -2,9 +2,11 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
*.py
|
*test.c
|
||||||
|
*.out
|
||||||
|
|
||||||
# output
|
# output
|
||||||
output/
|
output/
|
||||||
obj/
|
obj/
|
||||||
bin/
|
bin/
|
||||||
|
|
||||||
@@ -28,4 +28,7 @@ $(BIN_DIR) $(OBJ_DIR):
|
|||||||
clean:
|
clean:
|
||||||
@$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
|
@$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
|
||||||
|
|
||||||
|
run:
|
||||||
|
@$(BIN_DIR)/main
|
||||||
|
|
||||||
-include $(OBJ:.o=.d)
|
-include $(OBJ:.o=.d)
|
||||||
+1
-1
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
static const char FLEX[][11] = {"XAT--12A-S", "XAT--12B-S"};
|
static const char FLEX[][11] = {"XAT--12A-S", "XAT--12B-S"};
|
||||||
|
|
||||||
void handle(void* mem, char name[]);
|
void handleMalloc(void* mem, char name[]);
|
||||||
|
|
||||||
bool isFlex(char crsNo[MAX_COURSE_NO_LEN]);
|
bool isFlex(char crsNo[MAX_COURSE_NO_LEN]);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ UNIQUE_COURSES getNumberOfCourses(CSV_LINE *lines, size_t lines_len) {
|
|||||||
|
|
||||||
COURSE *getCourses(CSV_LINE *lines, size_t lines_len, UNIQUE_COURSES unique_course_info) {
|
COURSE *getCourses(CSV_LINE *lines, size_t lines_len, UNIQUE_COURSES unique_course_info) {
|
||||||
COURSE *courses = malloc(unique_course_info.numberOfCourses * sizeof(COURSE));
|
COURSE *courses = malloc(unique_course_info.numberOfCourses * sizeof(COURSE));
|
||||||
handle(courses, "'courses' from getCourses");
|
handleMalloc(courses, "'courses' from getCourses");
|
||||||
for (size_t i = 0; i < unique_course_info.numberOfCourses; i++) {
|
for (size_t i = 0; i < unique_course_info.numberOfCourses; i++) {
|
||||||
for (size_t j = 0; j < lines_len; j++) {
|
for (size_t j = 0; j < lines_len; j++) {
|
||||||
if (strcmp(lines[j].crsNo, unique_course_info.uniqueCrsNos[j]) == 0) {
|
if (strcmp(lines[j].crsNo, unique_course_info.uniqueCrsNos[j]) == 0) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ CSV_LINE *csvReader(char data_dir[], size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CSV_LINE *lines = malloc(size * sizeof(CSV_LINE));
|
CSV_LINE *lines = malloc(size * sizeof(CSV_LINE));
|
||||||
handle(lines, "'lines' from csvReader");
|
handleMalloc(lines, "'lines' from csvReader");
|
||||||
|
|
||||||
char buff[MAX_CHAR];
|
char buff[MAX_CHAR];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
+287
-436
@@ -8,11 +8,14 @@
|
|||||||
#include "../include/courses.h"
|
#include "../include/courses.h"
|
||||||
#include "../include/generator.h"
|
#include "../include/generator.h"
|
||||||
|
|
||||||
|
/*** for testing ***/
|
||||||
|
#include<stdio.h>
|
||||||
|
|
||||||
const char hex[] = "0123456789abcdefABCDEF";
|
const char hex[] = "0123456789abcdefABCDEF";
|
||||||
|
|
||||||
void appendChar(char *str, char ch) {
|
void appendChar(char *str, char c) {
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
str[len] = ch;
|
str[len] = c;
|
||||||
str[len + 1] = '\0';
|
str[len + 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,46 +42,45 @@ uint8_t *equal(uint8_t *arr, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stepIndex(int offset, StepType type, uint8_t blocksPerSemester) {
|
int stepIndex(int offset, StepType type, uint8_t blocksPerSemester) {
|
||||||
if (type == FirstToSecondSemester)
|
if (type == FirstToSecondSemester) {
|
||||||
return (offset == 0 || offset == -1 * (blocksPerSemester - 1)) ? blocksPerSemester : (-1 * (blocksPerSemester - 1));
|
bool toNextSemester = offset == 0 || offset == -1 * (blocksPerSemester - 1);
|
||||||
|
return toNextSemester ? blocksPerSemester : (-1 * (blocksPerSemester - 1));
|
||||||
|
}
|
||||||
|
|
||||||
if (type == SecondToFirstSemester)
|
if (type == SecondToFirstSemester) {
|
||||||
return (offset == 0 || offset == blocksPerSemester + 1) ? (-1 * blocksPerSemester) : (blocksPerSemester + 1);
|
bool toLastSemester = offset == 0 || offset == blocksPerSemester + 1;
|
||||||
|
return toLastSemester ? (-1 * blocksPerSemester) : (blocksPerSemester + 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Should not be possible
|
// Should not be possible
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *courses, size_t size_courses) {
|
/*
|
||||||
TIMETABLE_BLOCK defaultBlock;
|
totals student requests for each course,
|
||||||
defaultBlock.numberOfClasses = 0;
|
if course requests > MIN_REQ, course ID
|
||||||
TIMETABLE timetable = {{defaultBlock}, false};
|
is added to activeCourses.
|
||||||
|
*/
|
||||||
|
uint16_t calculateActiveCourses(
|
||||||
|
STUDENT *students,
|
||||||
|
size_t size_students,
|
||||||
|
COURSE *courses,
|
||||||
|
size_t size_courses,
|
||||||
|
char **activeCourses,
|
||||||
|
uint16_t *activeCoursesIndexes
|
||||||
|
) {
|
||||||
|
|
||||||
uint8_t MEDIAN = floor((float) (MIN_REQ + CLASS_CAP) / 2);
|
uint16_t activeCoursesLen = 0;
|
||||||
uint8_t BLOCKS_PER_SEMESTER = TOTAL_BLOCKS / 2;
|
|
||||||
|
|
||||||
|
|
||||||
/*** STEP 1 - Tally requests to check which courses are eligable to run ***/
|
|
||||||
char **activeCourses = malloc(MAX_CLASSES * sizeof(char *));
|
|
||||||
uint16_t *activeCoursesIndexes = malloc(MAX_CLASSES * sizeof(uint16_t));
|
|
||||||
handle(activeCourses, "'activeCourses' from generateTimetable");
|
|
||||||
handle(activeCoursesIndexes, "'activeCoursesIndexes' from generateTimetable");
|
|
||||||
uint16_t activeCoursesLen = 0; // also acts as the length of activeCourses
|
|
||||||
for (size_t i = 0; i < size_students; i++) {
|
for (size_t i = 0; i < size_students; i++) {
|
||||||
for (size_t j = 0; j < students[i].requestsLen; j++) {
|
for (size_t j = 0; j < students[i].requestsLen; j++) {
|
||||||
if (students[i].requests[j].alternate || isFlex(students[i].requests[j].crsNo)) continue;
|
if (students[i].requests[j].alternate ||
|
||||||
|
isFlex(students[i].requests[j].crsNo)) continue;
|
||||||
|
|
||||||
for (size_t k = 0; k < size_courses; k++) {
|
for (size_t k = 0; k < size_courses; k++) {
|
||||||
if (strcmp(courses[k].crsNo, students[i].requests[j].crsNo) == 0) {
|
if (strcmp(courses[k].crsNo, students[i].requests[j].crsNo) == 0) {
|
||||||
courses[k].requests++;
|
courses[k].requests++;
|
||||||
if (courses[k].requests >= MIN_REQ) {
|
if (courses[k].requests >= MIN_REQ) {
|
||||||
if (activeCoursesLen == 0) {
|
|
||||||
activeCourses[activeCoursesLen] = malloc(sizeof(char) * MAX_COURSE_NO_LEN);
|
|
||||||
handle(activeCourses[activeCoursesLen], "'activeCourses[idx]' from generateTimetable");
|
|
||||||
strcpy(activeCourses[activeCoursesLen], courses[k].crsNo);
|
|
||||||
activeCoursesIndexes[activeCoursesLen] = k;
|
|
||||||
activeCoursesLen++;
|
|
||||||
} else {
|
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
for (size_t l = 0; l < activeCoursesLen; l++) {
|
for (size_t l = 0; l < activeCoursesLen; l++) {
|
||||||
if (strcmp(activeCourses[l], courses[k].crsNo) == 0) {
|
if (strcmp(activeCourses[l], courses[k].crsNo) == 0) {
|
||||||
@@ -89,472 +91,321 @@ TIMETABLE generateTimetable(STUDENT *students, size_t size_students, COURSE *cou
|
|||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
activeCourses[activeCoursesLen] = malloc(sizeof(char) * MAX_COURSE_NO_LEN);
|
activeCourses[activeCoursesLen] = malloc(sizeof(char) * MAX_COURSE_NO_LEN);
|
||||||
handle(activeCourses[activeCoursesLen], "'activeCourses[idx]' from generateTimetable");
|
handleMalloc(activeCourses[activeCoursesLen], "'activeCourses[idx]' from calculateActiveCourses");
|
||||||
strcpy(activeCourses[activeCoursesLen], courses[k].crsNo);
|
strcpy(activeCourses[activeCoursesLen], courses[k].crsNo);
|
||||||
activeCoursesIndexes[activeCoursesLen] = k;
|
activeCoursesIndexes[activeCoursesLen] = k; // Save original index
|
||||||
activeCoursesLen++;
|
activeCoursesLen++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return activeCoursesLen;
|
||||||
|
}
|
||||||
|
|
||||||
/*** STEP 2 - Generate classes with no students, but calculate the number of expected students per class ***/
|
void createAndInsertClass(
|
||||||
|
CLASS *classes,
|
||||||
uint8_t *allClassRunCounts = malloc(activeCoursesLen * sizeof(uint8_t));
|
size_t *classesLen,
|
||||||
// max this out to total number of classrooms available between both semesters
|
size_t *courseClassIndexes,
|
||||||
CLASS *classes = malloc(CLASSROOMS * TOTAL_BLOCKS * sizeof(CLASS));
|
size_t index,
|
||||||
handle(allClassRunCounts, "'allClassRunCounts' from generateTimetable");
|
COURSE course,
|
||||||
handle(classes, "'classes' from generateTimetable");
|
char id,
|
||||||
size_t classesLen = 0;
|
uint8_t numberOfStudents
|
||||||
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;
|
|
||||||
|
|
||||||
// add 1 to classRunCount in case we need to create an extra class with remaining
|
|
||||||
size_t *courseClassIndexes = malloc((classRunCount + 1) * sizeof(size_t));
|
|
||||||
handle(courseClassIndexes, "'courseClassIndexes' from generateTimetable");
|
|
||||||
for (size_t j = 0; j < classRunCount; j++) {
|
|
||||||
CLASS newClass;
|
CLASS newClass;
|
||||||
strcpy(newClass.baseCrsNo, courses[index].crsNo);
|
strcpy(newClass.baseCrsNo, course.crsNo);
|
||||||
|
|
||||||
char courseID[MAX_COURSE_ID_LEN];
|
char courseID[MAX_COURSE_ID_LEN];
|
||||||
strcpy(courseID, courses[index].crsNo);
|
strcpy(courseID, course.crsNo);
|
||||||
appendChar(courseID, hex[j]);
|
appendChar(courseID, id);
|
||||||
strcpy(newClass.crsNo, courseID);
|
strcpy(newClass.crsNo, courseID);
|
||||||
strcpy(newClass.description, courses[index].description);
|
|
||||||
newClass.numberOfStudents = MEDIAN; // The expected number of students in this class
|
|
||||||
|
|
||||||
classes[classesLen] = newClass;
|
strcpy(newClass.description, course.description);
|
||||||
courseClassIndexes[j] = classesLen;
|
|
||||||
classesLen++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//*** Handle remaining requests ***/
|
newClass.numberOfStudents = numberOfStudents;
|
||||||
|
|
||||||
// Can we add remaining requests to existing classes
|
classes[*classesLen] = newClass;
|
||||||
bool remainingFitsInExistingClasses = remaining <= classRunCount * (CLASS_CAP - MEDIAN);
|
courseClassIndexes[index] = *classesLen;
|
||||||
|
(*classesLen)++;
|
||||||
|
}
|
||||||
|
|
||||||
// Can we create a new class using only remaining requests
|
void addRemainingToClasses(
|
||||||
bool remainingCanCreateNewClass = remaining >= MIN_REQ;
|
uint8_t classRunCount,
|
||||||
|
uint8_t remaining,
|
||||||
// Can we create a new class if we borrow students from created classes to add to remaining requests to meet min req
|
CLASS *classes,
|
||||||
bool remainingPlusExtraFromExistingCanCreateNewClass = MIN_REQ - remaining < classRunCount * (MEDIAN - MIN_REQ);
|
size_t *courseClassIndexes
|
||||||
|
) {
|
||||||
if (remainingFitsInExistingClasses) {
|
|
||||||
// Simply add remaining to existing classes
|
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
for (size_t j = 0; j < classRunCount; j++) {
|
for (size_t i = 0; i < classRunCount; i++) {
|
||||||
classes[courseClassIndexes[j]].numberOfStudents++;
|
size_t index = courseClassIndexes[i];
|
||||||
|
classes[index].numberOfStudents++;
|
||||||
remaining--;
|
remaining--;
|
||||||
if (remaining == 0) break;
|
if (remaining == 0) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (remainingCanCreateNewClass) {
|
void equalizeNumberOfStudents(
|
||||||
// Create new class
|
CLASS *classes,
|
||||||
CLASS newClass;
|
size_t *courseClassIndexes,
|
||||||
strcpy(newClass.baseCrsNo, courses[index].crsNo);
|
uint8_t classRunCount
|
||||||
char courseID[MAX_COURSE_ID_LEN];
|
) {
|
||||||
strcpy(courseID, courses[index].crsNo);
|
|
||||||
appendChar(courseID, hex[classRunCount]);
|
|
||||||
strcpy(newClass.crsNo, courseID);
|
|
||||||
strcpy(newClass.description, courses[index].description);
|
|
||||||
newClass.numberOfStudents = remaining;
|
|
||||||
|
|
||||||
// Insert class into empty classes array and update index
|
|
||||||
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));
|
uint8_t *numberOfStudentsArr = malloc(classRunCount * sizeof(uint8_t));
|
||||||
handle(numberOfStudentsArr, "'numberOfStudentsArr' from generateTimetable");
|
handleMalloc(numberOfStudentsArr, "'numberOfStudentsArr' from equalizeNumberOfStudents");
|
||||||
for (size_t j = 0; j < classRunCount; j++)
|
|
||||||
numberOfStudentsArr[j] = classes[courseClassIndexes[j]].numberOfStudents;
|
|
||||||
|
|
||||||
numberOfStudentsArr = equal(numberOfStudentsArr, classRunCount);
|
for (size_t i = 0; i < classRunCount; i++) {
|
||||||
for (size_t j = 0; j < classRunCount; j++)
|
size_t index = courseClassIndexes[i];
|
||||||
classes[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
|
numberOfStudentsArr[i] = classes[index].numberOfStudents;
|
||||||
|
|
||||||
free(numberOfStudentsArr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (remainingPlusExtraFromExistingCanCreateNewClass) {
|
numberOfStudentsArr = equal(numberOfStudentsArr, classRunCount);
|
||||||
// Take 1 student from each existing class till min requirement is met
|
for (size_t i = 0; i < classRunCount; i++) {
|
||||||
|
size_t index = courseClassIndexes[i];
|
||||||
|
classes[index].numberOfStudents = numberOfStudentsArr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
free(numberOfStudentsArr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createClassWithRemaining(
|
||||||
|
COURSE course,
|
||||||
|
uint8_t *classRunCount,
|
||||||
|
uint8_t remaining,
|
||||||
|
CLASS *classes,
|
||||||
|
size_t *classesLen,
|
||||||
|
size_t *courseClassIndexes
|
||||||
|
) {
|
||||||
|
createAndInsertClass(
|
||||||
|
classes,
|
||||||
|
classesLen,
|
||||||
|
courseClassIndexes,
|
||||||
|
*classRunCount,
|
||||||
|
course,
|
||||||
|
hex[*classRunCount],
|
||||||
|
remaining
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update class run count; if there is more than one class, equalize the class number of students
|
||||||
|
(*classRunCount)++;
|
||||||
|
if (*classRunCount >= 2)
|
||||||
|
equalizeNumberOfStudents(classes, courseClassIndexes, *classRunCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createClassWithRemainingAndExisting(
|
||||||
|
COURSE course,
|
||||||
|
uint8_t *classRunCount,
|
||||||
|
uint8_t remaining,
|
||||||
|
CLASS *classes,
|
||||||
|
size_t *classesLen,
|
||||||
|
size_t *courseClassIndexes
|
||||||
|
) {
|
||||||
|
// Take 1 student spot from each existing class till
|
||||||
|
// minimum requirement is met
|
||||||
while (remaining < MIN_REQ) {
|
while (remaining < MIN_REQ) {
|
||||||
for (size_t j = 0; j < classRunCount; j++) {
|
for (size_t i = 0; i < *classRunCount; i++) {
|
||||||
classes[courseClassIndexes[j]].numberOfStudents--;
|
size_t index = courseClassIndexes[i];
|
||||||
|
classes[index].numberOfStudents--;
|
||||||
remaining++;
|
remaining++;
|
||||||
if (remaining == MIN_REQ) break;
|
if (remaining == MIN_REQ) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new class with remaining
|
createAndInsertClass(
|
||||||
CLASS newClass;
|
classes,
|
||||||
strcpy(newClass.baseCrsNo, courses[index].crsNo);
|
classesLen,
|
||||||
char courseID[MAX_COURSE_ID_LEN];
|
courseClassIndexes,
|
||||||
strcpy(courseID, courses[index].crsNo);
|
*classRunCount,
|
||||||
appendChar(courseID, hex[classRunCount]);
|
course,
|
||||||
strcpy(newClass.crsNo, courseID);
|
hex[*classRunCount],
|
||||||
strcpy(newClass.description, courses[index].description);
|
remaining
|
||||||
newClass.numberOfStudents = remaining;
|
);
|
||||||
|
|
||||||
// Insert class into empty classes array and update index
|
(*classRunCount)++;
|
||||||
classes[classesLen] = newClass;
|
equalizeNumberOfStudents(classes, courseClassIndexes, *classRunCount);
|
||||||
courseClassIndexes[classRunCount] = classesLen;
|
}
|
||||||
classesLen++;
|
|
||||||
classRunCount++;
|
|
||||||
|
|
||||||
// Equalize the class number of students
|
|
||||||
uint8_t *numberOfStudentsArr = malloc(classRunCount * sizeof(uint8_t));
|
|
||||||
handle(numberOfStudentsArr, "'numberOfStudentsArr' from generateTimetable");
|
|
||||||
for (size_t j = 0; j < classRunCount; j++)
|
|
||||||
numberOfStudentsArr[j] = classes[courseClassIndexes[j]].numberOfStudents;
|
|
||||||
|
|
||||||
numberOfStudentsArr = equal(numberOfStudentsArr, classRunCount);
|
|
||||||
for (size_t j = 0; j < classRunCount; j++)
|
|
||||||
classes[courseClassIndexes[j]].numberOfStudents = numberOfStudentsArr[j];
|
|
||||||
|
|
||||||
free(numberOfStudentsArr);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
If all above cannot handle remaining requests we will add as many of
|
|
||||||
the remaining requests to the existing classes. Any number of requests
|
|
||||||
that dont fit will be ignored so later they can be folded into their
|
|
||||||
alternative choices
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
void addRemainingToClassesTillFull(
|
||||||
|
size_t classRunCount,
|
||||||
|
size_t *courseClassIndexes,
|
||||||
|
CLASS *classes,
|
||||||
|
size_t remaining
|
||||||
|
) {
|
||||||
bool full = false;
|
bool full = false;
|
||||||
while (!full) {
|
while (!full) {
|
||||||
for (size_t j = 0; j < classRunCount; j++) {
|
for (size_t i = 0; i < classRunCount; i++) {
|
||||||
if (classes[courseClassIndexes[classRunCount - 1]].numberOfStudents == CLASS_CAP) {
|
size_t lastIndex = courseClassIndexes[classRunCount - 1];
|
||||||
// If the last class in the array is at class_cap, all other classes must be at class cap and we are full
|
if (classes[lastIndex].numberOfStudents == CLASS_CAP) {
|
||||||
|
// If the last class is full, all classes before are
|
||||||
|
// assumed to be full ass well.
|
||||||
full = true;
|
full = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
classes[courseClassIndexes[j]].numberOfStudents++;
|
size_t index = courseClassIndexes[i];
|
||||||
|
if (classes[index].numberOfStudents == CLASS_CAP) continue;
|
||||||
|
classes[index].numberOfStudents++;
|
||||||
remaining--;
|
remaining--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates an array of classes,
|
||||||
|
each with an estimaed number of students
|
||||||
|
per class.
|
||||||
|
*/
|
||||||
|
size_t generateEmptyClasses(
|
||||||
|
COURSE *courses,
|
||||||
|
size_t size_courses,
|
||||||
|
uint16_t *activeCoursesIndexes,
|
||||||
|
uint16_t activeCoursesLen,
|
||||||
|
uint8_t *allClassRuns,
|
||||||
|
CLASS *classes,
|
||||||
|
uint8_t MEDIAN
|
||||||
|
) {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Add 1 to classRunCount in case an extra class can be created with remaining
|
||||||
|
size_t *courseClassIndexes = malloc((classRunCount + 1) * sizeof(size_t));
|
||||||
|
handleMalloc(courseClassIndexes, "'courseClassIndexes' from generateEmptyClasses");
|
||||||
|
|
||||||
|
for (size_t j = 0; j < classRunCount; j++) {
|
||||||
|
createAndInsertClass(
|
||||||
|
classes,
|
||||||
|
&classesLen,
|
||||||
|
courseClassIndexes,
|
||||||
|
j,
|
||||||
|
courses[index],
|
||||||
|
hex[j],
|
||||||
|
MEDIAN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** Handle remaining requests ***/
|
||||||
|
|
||||||
|
// Can add remaining requests to existing classes
|
||||||
|
bool remainingFitsInExisting = remaining <= classRunCount * (CLASS_CAP - MEDIAN);
|
||||||
|
|
||||||
|
// Can create new class using only remaining requets
|
||||||
|
bool remainingCanCreateNewClass = remaining >= MIN_REQ;
|
||||||
|
|
||||||
|
// Can create new class with remaining and borrowing requests from existing classes
|
||||||
|
bool remainingWithExistingCanCreateNewClass = MIN_REQ - remaining < classRunCount * (MEDIAN - MIN_REQ);
|
||||||
|
|
||||||
|
if (remainingFitsInExisting) {
|
||||||
|
addRemainingToClasses(classRunCount, remaining, classes, courseClassIndexes);
|
||||||
|
} else if (remainingCanCreateNewClass) {
|
||||||
|
createClassWithRemaining(
|
||||||
|
courses[index],
|
||||||
|
&classRunCount,
|
||||||
|
remaining,
|
||||||
|
classes,
|
||||||
|
&classesLen,
|
||||||
|
courseClassIndexes
|
||||||
|
);
|
||||||
|
} else if (remainingWithExistingCanCreateNewClass) {
|
||||||
|
createClassWithRemainingAndExisting(
|
||||||
|
courses[index],
|
||||||
|
&classRunCount,
|
||||||
|
remaining,
|
||||||
|
classes,
|
||||||
|
&classesLen,
|
||||||
|
courseClassIndexes
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
addRemainingToClassesTillFull(
|
||||||
|
classRunCount,
|
||||||
|
courseClassIndexes,
|
||||||
|
classes,
|
||||||
|
remaining
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(courseClassIndexes);
|
free(courseClassIndexes);
|
||||||
allClassRunCounts[i] = classRunCount;
|
allClassRuns[i] = classRunCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// realloc classes to correct size
|
// realloc classes to correct size
|
||||||
CLASS *tempClasses = malloc(classesLen * sizeof(CLASS));
|
// CLASS *tempClasses = malloc(classesLen * sizeof(CLASS));
|
||||||
handle(tempClasses, "'tempClasses' from generateTimetable");
|
// handleMalloc(tempClasses, "'tempClasses' from generateEmptyClasses");
|
||||||
for (size_t i = 0; i < classesLen; i++)
|
// for (size_t i = 0; i < classesLen; i++)
|
||||||
tempClasses[i] = classes[i];
|
// tempClasses[i] = classes[i];
|
||||||
classes = realloc(classes, classesLen * sizeof(CLASS));
|
// classes = realloc(classes, classesLen * sizeof(CLASS));
|
||||||
memcpy(classes, tempClasses, classesLen * sizeof(CLASS));
|
// memcpy(classes, tempClasses, classesLen * sizeof(CLASS));
|
||||||
free(tempClasses);
|
// free(tempClasses);
|
||||||
|
|
||||||
|
// ^^^ not needed if we are iterating using classesLen
|
||||||
|
// realloc is an expensive operation apparently.
|
||||||
|
|
||||||
|
return classesLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMETABLE generateTimetable(
|
||||||
|
STUDENT *students,
|
||||||
|
size_t size_students,
|
||||||
|
COURSE *courses,
|
||||||
|
size_t size_courses
|
||||||
|
) {
|
||||||
|
|
||||||
|
TIMETABLE_BLOCK defaultBlock;
|
||||||
|
defaultBlock.numberOfClasses = 0;
|
||||||
|
TIMETABLE timetable = {{defaultBlock}, false};
|
||||||
|
|
||||||
|
uint8_t MEDIAN = floor((float) (MIN_REQ + CLASS_CAP) / 2);
|
||||||
|
uint8_t BLOCKS_PER_SEMESTER = TOTAL_BLOCKS / 2;
|
||||||
|
|
||||||
|
/*** STEP 1 - Tally requests to check which coures are eligble to run ***/
|
||||||
|
// Array of course IDs that have met minimum requests.
|
||||||
|
char **activeCourses = malloc(MAX_CLASSES * sizeof(char *));
|
||||||
|
uint16_t *activeCoursesIndexes = malloc(MAX_CLASSES * sizeof(uint16_t));
|
||||||
|
handleMalloc(activeCourses, "'activeCourses' from generateTimetable");
|
||||||
|
handleMalloc(activeCoursesIndexes, "'activeCoursesIndexes' from generateTimetable");
|
||||||
|
|
||||||
|
uint16_t activeCoursesLen = calculateActiveCourses(
|
||||||
|
students,
|
||||||
|
size_students,
|
||||||
|
courses,
|
||||||
|
size_courses,
|
||||||
|
activeCourses,
|
||||||
|
activeCoursesIndexes
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*** STEP 2 - Generate classes with no students
|
||||||
|
* - Calculate number of expected students per class ***/
|
||||||
|
uint8_t *allClassRuns = malloc(activeCoursesLen * sizeof(uint8_t));
|
||||||
|
CLASS *classes = malloc(CLASSROOMS * TOTAL_BLOCKS * sizeof(CLASS));
|
||||||
|
handleMalloc(allClassRuns, "'allClassRuns' from generateTimetable");
|
||||||
|
handleMalloc(classes, "'classes' from generateTimetable");
|
||||||
|
size_t size_classes = generateEmptyClasses(
|
||||||
|
courses,
|
||||||
|
size_courses,
|
||||||
|
activeCoursesIndexes,
|
||||||
|
activeCoursesLen,
|
||||||
|
allClassRuns,
|
||||||
|
classes,
|
||||||
|
MEDIAN
|
||||||
|
);
|
||||||
|
|
||||||
free(activeCoursesIndexes);
|
free(activeCoursesIndexes);
|
||||||
|
|
||||||
|
|
||||||
/*** STEP 3 - Insert students into empty classes ***/
|
/*** STEP 3 - Insert students into empty classes ***/
|
||||||
STUDENT *tempStudents = malloc(size_students * sizeof(STUDENT));
|
|
||||||
handle(tempStudents, "'tempStudents' from generateTimetable");
|
|
||||||
size_t size_tempStudents = size_students;
|
|
||||||
memcpy(tempStudents, students, size_students * sizeof(STUDENT));
|
|
||||||
|
|
||||||
uint8_t *currentInserted = malloc(classesLen * sizeof(uint8_t));
|
|
||||||
handle(currentInserted, "'currentInserted' from generateTimetable");
|
|
||||||
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];
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
handle(alternates, "'alternates' from generateTimetable");
|
|
||||||
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;
|
|
||||||
|
|
||||||
while (getAvailableCourse) {
|
|
||||||
for (size_t j = 0; j < classesLen; j++) {
|
|
||||||
// Class exists in classes
|
|
||||||
if (strcmp(classes[j].baseCrsNo, course) == 0) {
|
|
||||||
// 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;
|
|
||||||
student.classes++;
|
|
||||||
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));
|
|
||||||
handle(tempAlternates, "'tempAlternates' from generateTimetable");
|
|
||||||
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) {
|
|
||||||
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));
|
|
||||||
handle(tempAlternates, "'tempAlternates' from generateTimetable");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Asign remaining alternates && classes 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;
|
|
||||||
|
|
||||||
students[i].classes = student.classes;
|
|
||||||
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));
|
|
||||||
handle(new_tempStudents, "'new_tempStudents' from generateTimetable");
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
/*** STEP 4 - Insert classes into timetable ***/
|
/*** Done ***/
|
||||||
while (activeCoursesLen > 0) {
|
|
||||||
// Find highest resource class (most times run)
|
|
||||||
size_t index = 0;
|
|
||||||
uint8_t max = 0;
|
|
||||||
for (size_t i = 0; i < activeCoursesLen; i++) {
|
|
||||||
if (allClassRunCounts[i] > max) {
|
|
||||||
max = allClassRunCounts[i];
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tally first semester and second semester
|
|
||||||
uint8_t allSemesterBlockLens[TOTAL_BLOCKS] = {0};
|
|
||||||
for (uint8_t i = 0; i < TOTAL_BLOCKS; i++)
|
|
||||||
allSemesterBlockLens[i] = timetable.blocks[i].numberOfClasses;
|
|
||||||
|
|
||||||
// If there is more than one class running
|
|
||||||
if (allClassRunCounts[index] > 1) {
|
|
||||||
// Get index of block with least class run counts
|
|
||||||
uint8_t minClassrooms = CLASSROOMS;
|
|
||||||
uint8_t blockIndex = 0;
|
|
||||||
for (uint8_t i = 0; i < TOTAL_BLOCKS; i++) {
|
|
||||||
if (allSemesterBlockLens[i] < minClassrooms) {
|
|
||||||
minClassrooms = allSemesterBlockLens[i];
|
|
||||||
blockIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StepType step = blockIndex < BLOCKS_PER_SEMESTER ? FirstToSecondSemester : SecondToFirstSemester;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
// Disperse classes throughout both semesters
|
|
||||||
// Find base class ID index
|
|
||||||
size_t indexOffset = 0;
|
|
||||||
size_t baseIndex = 0;
|
|
||||||
for (size_t i = 0; i < classesLen; i++) {
|
|
||||||
if (strcmp(classes[i].baseCrsNo, activeCourses[index]) == 0) {
|
|
||||||
baseIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint8_t classRunCounts = allClassRunCounts[index];
|
|
||||||
for (size_t i = 0; i < classRunCounts; i++) {
|
|
||||||
bool classInserted = false;
|
|
||||||
while (!classInserted) {
|
|
||||||
blockIndex += offset;
|
|
||||||
|
|
||||||
// Insert class
|
|
||||||
if (timetable.blocks[blockIndex].numberOfClasses < CLASSROOMS) {
|
|
||||||
uint8_t classIndex = timetable.blocks[blockIndex].numberOfClasses;
|
|
||||||
timetable.blocks[blockIndex].classes[classIndex] = classes[baseIndex + indexOffset];
|
|
||||||
timetable.blocks[blockIndex].numberOfClasses++;
|
|
||||||
allClassRunCounts[index]--;
|
|
||||||
indexOffset++;
|
|
||||||
classInserted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update offset and to get index of block for next semester
|
|
||||||
offset = stepIndex(offset, step, BLOCKS_PER_SEMESTER);
|
|
||||||
if (blockIndex >= (TOTAL_BLOCKS - 1)) {
|
|
||||||
blockIndex = step == FirstToSecondSemester ? 0 : BLOCKS_PER_SEMESTER;
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the class only runs once, place in semester with least classes
|
|
||||||
} else if (allClassRunCounts[index] == 1) {
|
|
||||||
// Get index of block with least class run counts
|
|
||||||
uint8_t minClassrooms = CLASSROOMS;
|
|
||||||
uint8_t blockIndex = 0;
|
|
||||||
for (uint8_t i = 0; i < TOTAL_BLOCKS; i++) {
|
|
||||||
if (allSemesterBlockLens[i] < minClassrooms) {
|
|
||||||
minClassrooms = allSemesterBlockLens[i];
|
|
||||||
blockIndex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get class ID index
|
|
||||||
size_t baseIndex = 0;
|
|
||||||
for (size_t i = 0; i < classesLen; i++) {
|
|
||||||
if (strcmp(classes[i].baseCrsNo, activeCourses[index]) == 0) {
|
|
||||||
baseIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert class
|
|
||||||
uint8_t classIndex = timetable.blocks[blockIndex].numberOfClasses;
|
|
||||||
timetable.blocks[blockIndex].classes[classIndex] = classes[baseIndex];
|
|
||||||
timetable.blocks[blockIndex].numberOfClasses++;
|
|
||||||
allClassRunCounts[index]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that the classRunCount is 0 since all classes have been inserted into the timetable
|
|
||||||
// delete this course as it has been handled
|
|
||||||
activeCoursesLen--;
|
|
||||||
|
|
||||||
// create temp arrays of data
|
|
||||||
uint8_t *tempAllClassRunCounts = malloc(activeCoursesLen * sizeof(uint8_t));
|
|
||||||
char **tempActiveCourses = malloc(activeCoursesLen * sizeof(char*));
|
|
||||||
handle(tempAllClassRunCounts, "'tempAllClassRunCounts' from generateTimetable");
|
|
||||||
handle(tempActiveCourses, "'tempActiveCourses' from generateTimetable");
|
|
||||||
|
|
||||||
// Copy data without the course we just handled
|
|
||||||
size_t tempIndex = 0;
|
|
||||||
for (size_t i = 0; i <= activeCoursesLen; i++) {
|
|
||||||
if (activeCourses[i] == activeCourses[index]) {
|
|
||||||
free(activeCourses[i]);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
tempAllClassRunCounts[tempIndex] = allClassRunCounts[i];
|
|
||||||
tempActiveCourses[tempIndex] = activeCourses[i];
|
|
||||||
tempIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reallocate the arrays of course data to be 1 less in size and copy temp data back to them, then free temp data
|
|
||||||
allClassRunCounts = realloc(allClassRunCounts, activeCoursesLen * sizeof(uint8_t));
|
|
||||||
activeCourses = realloc(activeCourses, activeCoursesLen * sizeof(char*));
|
|
||||||
memcpy(allClassRunCounts, tempAllClassRunCounts, activeCoursesLen * sizeof(uint8_t));
|
|
||||||
memcpy(activeCourses, tempActiveCourses, activeCoursesLen * sizeof(char*));
|
|
||||||
free(tempAllClassRunCounts);
|
|
||||||
free(tempActiveCourses);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// STEP 5 - fill student schedule
|
|
||||||
for (size_t i = 0; i < TOTAL_BLOCKS; i++) {
|
|
||||||
for (size_t j = 0; j < timetable.blocks[i].numberOfClasses; j++) {
|
|
||||||
for (size_t k = 0; k < timetable.blocks[i].classes[j].numberOfStudents; k++) {
|
|
||||||
for (size_t l = 0; l < size_students; l++) {
|
|
||||||
if (students[l].pupilNum == timetable.blocks[i].classes[j].students[k]) {
|
|
||||||
strcpy(students[l].schedule[i], timetable.blocks[i].classes[j].crsNo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// STEP 6 - Solve student schedule errors
|
|
||||||
|
|
||||||
free(classes);
|
free(classes);
|
||||||
free(allClassRunCounts);
|
free(allClassRuns);
|
||||||
|
for (size_t i = 0; i < activeCoursesLen; i++)
|
||||||
|
free(activeCourses[i]);
|
||||||
free(activeCourses);
|
free(activeCourses);
|
||||||
|
|
||||||
return timetable;
|
return timetable;
|
||||||
|
|||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
typedef struct {
|
||||||
|
const char *key;
|
||||||
|
void *value;
|
||||||
|
} hashEntry;
|
||||||
|
|
||||||
|
struct hashTable {
|
||||||
|
hashEntry entries;
|
||||||
|
size_t capacity;
|
||||||
|
size_t length;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashTable* createHashTable(void) {
|
||||||
|
hashTable *table = malloc(sizeof(hashTable));
|
||||||
|
handleMalloc(table, "'table' from createHashTable");
|
||||||
|
table->length = 0;
|
||||||
|
table->capacity = 64;
|
||||||
|
|
||||||
|
table->entries = calloc(table->capacity, sizeof(hashEntry));
|
||||||
|
handleMalloc(table->entries, "'table->entries' from createHashTable");
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
+2
-2
@@ -11,7 +11,7 @@
|
|||||||
#include "../include/json.h"
|
#include "../include/json.h"
|
||||||
#include "../include/generator.h"
|
#include "../include/generator.h"
|
||||||
|
|
||||||
void handle(void *mem, char name[]) {
|
void handleMalloc(void *mem, char name[]) {
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
fprintf(stderr, "Failed to allocate memory! - Memory: %s\n", name);
|
fprintf(stderr, "Failed to allocate memory! - Memory: %s\n", name);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
@@ -24,7 +24,7 @@ bool isFlex(char crsNo[MAX_COURSE_NO_LEN]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(void) {
|
||||||
/*
|
/*
|
||||||
read csv data into array of structs that can
|
read csv data into array of structs that can
|
||||||
be processed into an array of student structs
|
be processed into an array of student structs
|
||||||
|
|||||||
+3
-3
@@ -40,7 +40,7 @@ STUDENT *getStudents(CSV_LINE *lines, size_t lines_len, int total_blocks, UNIQUE
|
|||||||
|
|
||||||
// Create our student array with the correct number of students
|
// Create our student array with the correct number of students
|
||||||
STUDENT *students = malloc(students_info.numberOfStudents * sizeof(STUDENT));
|
STUDENT *students = malloc(students_info.numberOfStudents * sizeof(STUDENT));
|
||||||
handle(students, "'students' from getStudents");
|
handleMalloc(students, "'students' from getStudents");
|
||||||
for (uint16_t i = 0; i < students_info.numberOfStudents; i++) {
|
for (uint16_t i = 0; i < students_info.numberOfStudents; i++) {
|
||||||
STUDENT student;
|
STUDENT student;
|
||||||
|
|
||||||
@@ -52,14 +52,14 @@ STUDENT *getStudents(CSV_LINE *lines, size_t lines_len, int total_blocks, UNIQUE
|
|||||||
student.remainingAltsLen = 0;
|
student.remainingAltsLen = 0;
|
||||||
|
|
||||||
REQUEST *requests = malloc(numRequests[i] * sizeof(REQUEST));
|
REQUEST *requests = malloc(numRequests[i] * sizeof(REQUEST));
|
||||||
handle(requests, "'requests' from getStudents");
|
handleMalloc(requests, "'requests' from getStudents");
|
||||||
student.requests = requests;
|
student.requests = requests;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < TOTAL_BLOCKS; i++)
|
for (uint8_t i = 0; i < TOTAL_BLOCKS; i++)
|
||||||
strcpy(student.schedule[i], i < TOTAL_BLOCKS / 2 ? FLEX[0] : FLEX[1]);
|
strcpy(student.schedule[i], i < TOTAL_BLOCKS / 2 ? FLEX[0] : FLEX[1]);
|
||||||
|
|
||||||
REQUEST *remainingAlts = malloc(MAX_REQUEST_ALTS * sizeof(REQUEST));
|
REQUEST *remainingAlts = malloc(MAX_REQUEST_ALTS * sizeof(REQUEST));
|
||||||
handle(remainingAlts, "'remainingAlts' from getStudents");
|
handleMalloc(remainingAlts, "'remainingAlts' from getStudents");
|
||||||
student.remainingAlts = remainingAlts;
|
student.remainingAlts = remainingAlts;
|
||||||
|
|
||||||
students[i] = student;
|
students[i] = student;
|
||||||
|
|||||||
Reference in new issue
Block a user