/* modified version of timetable.c to reflect changes in design */ #include #include #include #define MAX_ROOMS 20 /* max. valid rooms */ #define MAX_COURSES 30 /* max. valid courses */ #define MAX_TIMES 15 /* max. possible timeslots */ #define MAX_CAP 300 /* max. allowed room capacity */ #define MIN_CAP 10 /* min. room capacity */ #define MAX_LN_LENG 80 /* max. input line length */ #define TRUE 1 #define FALSE 0 #define MAX_COURSENO_SIZE 6 /* max. size of course number string */ #define MAX_TIMESLOT_SIZE 9 /* max. size of time slot string */ #define MAX_ROOMNO_SIZE 4 /* max. size of room no. string */ typedef char courseno[MAX_COURSENO_SIZE]; typedef char timeslot[MAX_TIMESLOT_SIZE]; typedef struct /* info about a valid room */ { char room_no[MAX_ROOMNO_SIZE]; int capacity; }room; /* A general linked list of integers */ typedef struct LstNode { int pref_index; /* Typically index in some DB will be kept */ struct LstNode *next; }lstnode; typedef struct /* information about the course to be scheduled */ { int cnum; /* index of the course in CourseDB */ int enrol; /* expected enrollment */ lstnode *prefs; /* list of valid preferences */ }course; typedef struct /* to produce conflict or explanation info */ { int err_code; /* error code */ int cnum; /* index into course no_db */ int roomno; /* index into ClassroomDB */ lstnode *prefs; }error; /* The next 6 data items obtained by parsing file1 */ room ClassroomDB[MAX_COURSES]; /* valid courses */ courseno CourseDB[MAX_ROOMS]; /* valid rooms */ timeslot TimeslotDB[MAX_TIMES]; /* valid timeslots */ int TotRooms; /* total number of rooms */ int TotTimes; /* total number of possible lecture times */ int TotCourses;/*total courses in file 1 */ course SchCourses[MAX_COURSES]; /* list of courses to be scheduled */ int TotSchCourses; /* total number of courses to scheduled */ /* The following 4 pointers are set up after the SchCourses is "sorted" */ int PgP=0; /* start of pg_prefs course; Is 0 */ int UgP; /* first index of ug_prefs courses */ int PgNP; /* first index of pg_no_pref courses */ int UgNP; /* first index of ug_no_pref courses */ int TimeTable[MAX_ROOMS][MAX_TIMES]; /* the rows are indices in ClassroomDB, columns are indices into TimeslotDB */ int PgAlloc[MAX_TIMES]; /* Time slots occupied by PG courses. An entry is -ve if not allocated to a PG course, +ve otherwise. Used for checking conflicts while scheduling PG courses */ error ConflLst[MAX_COURSES]; /* expln for unschedualble courses */ error ExplnLst[MAX_COURSES]; /* expln for each unschedualble pref */ int TotConfl = 0; /* represents last entry in ConflLst */ int TotExpln = 0; /* represents last entry in ExplnLst */ int line_no=1; lstnode *form_pref_list(); /************************************************************************************************/ main(argc,argv) int argc; char *argv[]; { FILE *fd1,*fd2; if (argc != 3) { printf("usage : schedule file1 file2\n"); exit(-1); } /* opening file1 */ if ((fd1=fopen(argv[1],"r"))== NULL) { printf("can't open file %s\n",argv[1]); exit(-1); } /* opening file2 */ if ((fd2=fopen(argv[2],"r"))== NULL) { printf("can't open file %s\n",argv[2]); exit(-1); } /* get the data from input files */ get_validated_input(fd1,fd2,TimeslotDB,ClassroomDB,CourseDB,SchCourses); schedule(ClassroomDB,TimeslotDB,CourseDB,SchCourses, TimeTable,ConflLst,ExplnLst); /* schedule courses*/ print_output(TimeTable,ExplnLst,ConflLst); /* ouput timetable and explanations */ } /***************************************************************************/ /* This module validates the contents of file1 and file2 and produces * lists for valid courses,classrooms,time slots,and courses to be * scheduled. Iferrors found in input file format, it exits if * scheduling is not possible, else ignores the erroneous data */ get_validated_input(file1,file2,TimeslotDB,ClassroomDB,CourseDB,SchCourses) FILE * file1, * file2; timeslot * TimeslotDB; room * ClassroomDB; courseno * CourseDB; course * SchCourses; { FILE *fd; /* get data from file1 */ printf("Reading %s.....\n",file1); validate_file1(file1,ClassroomDB,CourseDB,TimeslotDB); /* get data from file2 */ printf("Reading %s.....\n",file2); validate_file2(file2, SchCourses); separate_courses(CourseDB,SchCourses); } /*------------------------------------------------------------------------*/ /* Top level module to schedule courses. Besides timetable, it * gives explanation for courses/prefs which could not be satisfied */ schedule(ClassroomDB,TimeslotDB,CourseDB,SchCourses, TimeTable,ConflLst,ExplnLst) room * ClassroomDB; timeslot * TimeslotDB; courseno * CourseDB; course * SchCourses; int TimeTable[][MAX_TIMES]; error * ConflLst; error * ExplnLst; { int row,col; /* initializing time table & PgAlloc */ for(row=0;rowMAX_CAP)) { printf("line# %d : enrollment \"%d\" not in the allowed range \n",line_no,enrol); printf("line# %d : course \"%s\" is ignored\n",line_no,CourseDB[course_index]); continue; } if (chk_dup_sched_course(SchCourses,course_index)) { printf("line# %d : \"%s\" duplicate course *** ignored\n",line_no,CourseDB[course_index]); continue; } strcpy(line,(token+strlen(token)+1)); /* get the list of preferences fo this course */ pref_list = form_pref_list(line,TimeslotDB); SchCourses[TotSchCourses].cnum = course_index; SchCourses[TotSchCourses].enrol = enrol; SchCourses[TotSchCourses].prefs = pref_list; TotSchCourses++; } if (TotSchCourses>MAX_COURSES) { printf("line# %d : More number of courses than permissible\n",line_no++); printf("later ones are ignored\n"); } if (TotSchCourses == 0) { printf("no courses to schedule\n"); printf("scheduling aborted \n"); exit(-1); } close(fd); } /*------------------------------------------------------------------------*/ /* Rearrange the courses in the following order: PG courses with * preferences, UG courses with preferences, PG courses with no * preferences, UG courses with no preferences */ separate_courses(CourseDB,SchCourses) courseno *CourseDB; course *SchCourses; { course pg_pref[MAX_COURSES], pg_no_pref[MAX_COURSES], ug_pref[MAX_COURSES], ug_no_pref[MAX_COURSES]; int pg_pref_i = 0; /* index of last entry in pg_pref */ int ug_pref_i = 0; int pg_no_pref_i = 0; int ug_no_pref_i = 0; char temp_char; int i,j; for (i=0;i '5') /* pg course */ if (SchCourses[i].prefs != NULL) /* preferences given */ pg_pref[pg_pref_i++]=SchCourses[i]; else pg_no_pref[pg_no_pref_i++]=SchCourses[i]; else /* ug course */ if (SchCourses[i].prefs != NULL) /* preferences given */ ug_pref[ug_pref_i++]=SchCourses[i]; else ug_no_pref[ug_no_pref_i++]=SchCourses[i]; } /* copy back from temporary storage */ for (i=0,j=0;ipref_index; pref_tail=NULL; sched_done=FALSE; while ((pref_list != NULL)&&(!sched_done)) { pref_index = pref_list->pref_index; if (PgAlloc[pref_index]<0) /* no pg course at this time slot */ { pref_honored = pref_index; PgAlloc[pref_index] = course_index; TimeTable[room_index][pref_index] = course_index; sched_done = TRUE; } else { /* preserve info about pref to give explantions */ new_pref = (lstnode *)malloc(sizeof(lstnode)); new_pref->pref_index = pref_index; new_pref->next = NULL; if (pref_tail == NULL) pref_tail = temp_pref = new_pref; else { pref_tail->next = new_pref; pref_tail = new_pref; } } pref_list = pref_list->next; } /* while */ if ( !sched_done) { ConflLst[TotConfl].err_code = 1; ConflLst[TotConfl].cnum = course_index; ConflLst[TotConfl++].prefs = temp_pref; } else if (pref_honored != first_pref) { ExplnLst[TotExpln].err_code=pref_honored; ExplnLst[TotExpln].prefs=temp_pref; ExplnLst[TotExpln].cnum=course_index; ExplnLst[TotExpln++].roomno=-1; } } /* for */ } /*------------------------------------------------------------------------*/ /* Schedule UG courses with preferences. This is not straighforward. * Before alloting a , it has to check if this * allotment is "safe", i.e. the schedulability of PG courses with * no prefs is not disturbed. It does so by first "simulating" a * scheduling of pg_no_pref courses to find out how many can be * scheduled. An allotment is safe if the same no. can be still * scheduled */ sched_ug_pref(SchCourses,PgAlloc, ConflLst,ExplnLst, TimeTable) course *SchCourses; int *PgAlloc; error *ConflLst; error *ExplnLst; int TimeTable[][MAX_TIMES]; { int pref_index, course_index, room_index, enrol, index, room_no; int num_pg_no_pref,/* number of pg courses with no preferences */ pref_honored, first_pref; lstnode *pref_list; lstnode *temp_lstnode_ptr, *temp, *pref_tail; int sched_done = FALSE;/* set if scheduling is done */ int TotSchPgNoPref; /* schedulable pg no prefs */ /* number of pg_no_prefs courses that can be scheduled before ug_prefs are scheduled */ TotSchPgNoPref = PgNoPrefSchLable(TimeTable,PgAlloc,SchCourses); num_pg_no_pref=UgNP-PgNP; for (index=UgP;indexpref_index; sched_done = FALSE; pref_tail = NULL; while ((pref_list != NULL)&&(!sched_done)) { pref_index = pref_list->pref_index; if ((num_pg_no_pref == 0)|| (PgAlloc[pref_index]>=0)) /* this time slot is not useful for pg_no_prefs */ { for(room_index = room_no;room_indexpref_index = pref_index; temp->next = NULL; if (pref_tail == NULL) pref_tail = temp_lstnode_ptr = temp; else { pref_tail->next = temp; pref_tail = temp; } } pref_list = pref_list->next; } /* while */ if (!sched_done) { ConflLst[TotConfl].err_code = 2; ConflLst[TotConfl].cnum = course_index; ConflLst[TotConfl++].prefs= temp_lstnode_ptr; } else if (pref_honored != first_pref) { ExplnLst[TotExpln].err_code = pref_honored; ExplnLst[TotExpln].prefs = temp_lstnode_ptr; ExplnLst[TotExpln].cnum = course_index; ExplnLst[TotExpln++].roomno = room_no; } } /* for */ } /*------------------------------------------------------------------------*/ /* Schedule PG courses with no preferences specified; Returns the * number of courses it is able to schedule */ int sched_pg_no_pref(sched_db,ConflLst,TotConfl,PgAlloc,TimeTable) course *sched_db; error *ConflLst; int *TotConfl; int *PgAlloc; int TimeTable[][MAX_TIMES]; /* schedule pg courses with no preferences */ { int course_index, enrol, room_index, sched_done, cur_slot; int i; int tot_scheduled=0; for(i = PgNP;ipref_index = pref_index; new_pref->next = NULL; if (pref_tail == NULL) pref_tail = pref_list = new_pref; else { pref_tail->next = new_pref; pref_tail = new_pref; } } token = strtok((char *)NULL," ,;\t\n"); } if ((token != NULL)&&(num_of_pref>4)) { printf("line# %d : more preferences than allowed\n",line_no); printf(" time slots from \"%s\" are ignored\n",token); } return(pref_list); } /*------------------------------------------------------------------------*/ /* outputs the time table in tabular form as * room numbers into rows and time slots into columns */ print_TimeTable(TimeslotDB,ClassroomDB,CourseDB,TimeTable) timeslot *TimeslotDB; room *ClassroomDB; courseno *CourseDB; int TimeTable[][MAX_TIMES]; { int i,j,breadth,space; breadth = (TotTimes+1) * 12; space = (breadth-10)/2; printf("\n"); /* initial spaces before 'TIME TABLE' */ if (space >0) for (i=0;ipref_index]); if (room_index <0) printf("Conflicting with course %s\n", CourseDB[PgAlloc[temp_pref->pref_index]]); else printf("Room with proper capacity not found\n"); temp_pref=temp_pref->next; } if ((room_index >= 0)&& (TimeTable[room_index][pref_honored]!=ExplnLst[i].cnum)) { printf("\t %s :\n",TimeslotDB[pref_honored]); while (TimeTable[room_index][pref_honored] != ExplnLst[i].cnum) { printf("\t\t room#%s :",ClassroomDB[room_index].room_no); printf("conflicting with course %s\n", CourseDB[TimeTable[room_index][pref_honored]]); room_index++; } } } printf("\n"); } /*------------------------------------------------------------------------*/ /* Print the list of courses that are not scheduled in the final table, * and specify the conflicts that prevented their scheduling */ print_conflicts(ConflLst,CourseDB) error *ConflLst; courseno *CourseDB; { int i; lstnode *temp; if (TotConfl <1) return; printf("\n\t\t\tConflict Report\n"); printf("\t-----------------------------------------------\n\n"); for (i=0;ipref_index]); printf("conflicting with course %s \n", CourseDB[PgAlloc[temp->pref_index]]); temp = temp->next; } break; case 2 : temp = ConflLst[i].prefs; while (temp != NULL) { printf("\t %s : ",TimeslotDB[temp->pref_index]); printf("Room with proper capacity not found\n"); temp = temp->next; } break; case 3 : printf("\tExcess PG course : no time slot available\n"); break; case 4 : printf("\tNo free room with required capacity available\n"); break; case 5 : printf("\tIgnored : No room with adequate capacity for this enrollment\n"); break; case 6 : printf("\tIgnored : course repeated more than once in file2\n"); break; } printf("\n"); } } /*************************************************************************** * Utility routines * ***************************************************************************/ /* * returns first non empty line from the input file. * returns null string if eof is encountered & no non * empty line is found. * All the initial spaces before a line are removed. * The last character of the string will be '\n' if is * a non empty line. */ get_next_line(fd,buffer) char *buffer; FILE *fd; { int ln_found = FALSE; char *temp_char; *buffer = '\0'; while ( !ln_found ) { line_no++; fgets(buffer,MAX_LN_LENG,fd); temp_char=buffer; /* removes initial spaces */ while ( (*temp_char != NULL) && isspace(*temp_char) ) temp_char++; if ((*temp_char != NULL) || feof(fd) ) ln_found=TRUE; } if (buffer != temp_char) strcpy(buffer,temp_char); } /*------------------------------------------------------------------------*/ /* Checks if the room_no given already exists in the ClassroomDB */ int chk_dup_room(ClassroomDB,TotRooms,room_number) room * ClassroomDB; int TotRooms; char * room_number; /* check, whether the given room number already exists in the data base. returns TRUE if so, otherwise false */ { int i; for (i=0;i=MIN_CAP)&&(capacity<=MAX_CAP)) ? TRUE :FALSE; if (!flag) { printf("line# %d : error in room capacity \"%d\" \n",line_no,capacity); printf("scheduling aborted \n"); exit(-1); } } /*------------------------------------------------------------------------*/ chk_fmt_room_no(room_number) char *room_number; /* checks the format of room number aborts with error message,if it is not in correct format. */ { int i,str_leng; int fmt_error=FALSE; str_leng=strlen(room_number); if (str_leng>3) fmt_error=TRUE; else for (i=0;iClassroomDB[j].capacity) { strcpy(temp_room.room_no,ClassroomDB[i].room_no); temp_room.capacity=ClassroomDB[i].capacity; strcpy(ClassroomDB[i].room_no,ClassroomDB[j].room_no); ClassroomDB[i].capacity=ClassroomDB[j].capacity; strcpy(ClassroomDB[j].room_no,temp_room.room_no); ClassroomDB[j].capacity=temp_room.capacity; } } /*------------------------------------------------------------------------*/ chk_fmt_course_no(course_no) char *course_no; /* checks the format of course number i.e csddd aborts, if any error found */ { int str_leng; int fmt_error = FALSE; str_leng = strlen(course_no); if (str_leng != 5) fmt_error=TRUE; else if ( strncmp(course_no,"cs",2) != 0 ) fmt_error = TRUE; else if ( !isdigit(course_no[2]) ) fmt_error = TRUE; else if ( !isdigit(course_no[3]) ) fmt_error = TRUE; else if ( !isdigit(course_no[4]) ) fmt_error = TRUE; if (fmt_error) { printf("line #%d : error in the format of course number \"%s\"\n",line_no,course_no); printf("scheduling aborted\n"); exit(-1); } } /*------------------------------------------------------------------------*/ int chk_dup_course_no(CourseDB,TotCourses,course_number) courseno * CourseDB; int TotCourses; char * course_number; { int i; for (i=0;i8)); if (!fmt_error) { temp_str=temp_slot; while ( !isdigit(*temp_str) ) temp_str++; strcpy(time,temp_str); *temp_str = '\0'; if (strcmp(temp_slot,"MWF")&&strcmp(temp_slot,"TT")) fmt_error = TRUE; else { temp_char = strchr(time,':'); if (temp_char != NULL) *temp_char = '9'; /* any digit */ while (time[i] != NULL) if (!isdigit(time[i++])) fmt_error = TRUE; } } if (fmt_error) { printf("line# %d : error in the format of time slot \"%s\"\n",line_no,time_slot); printf("scheduling is aborted\n"); exit(-1); } } /*------------------------------------------------------------------------*/ int chk_dup_time_slot(TimeslotDB,TotTimes,time_slot) timeslot * TimeslotDB; int TotTimes; char * time_slot; { int i; for (i=0;i=enrol) return(i); return(-1); } /*------------------------------------------------------------------------*/ /* following routines are for debugging purpose only */ display_rooms() { int i; for (i=0;ipref_index]); temp_pref=temp_pref->next; } } /*------------------------------------------------------------------------*/ display_scheds() { int i; printf("total courses %d\n",TotSchCourses); printf("ug start %d\n",UgP); printf("pg no prefstart %d\n",PgNP); printf("ug no prefstart %d\n",UgNP); for (i=0;i