Skip to content

Commit 34d54c8

Browse files
committed
feat(timetable): add user input, preferred slots, conflict checking, GA optimization, and sorted timetable output
1 parent b3ebf0d commit 34d54c8

File tree

7 files changed

+277
-0
lines changed

7 files changed

+277
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include "genetic_algorithm.h"
2+
3+
Timetable GeneticAlgorithm::crossover(const Timetable& p1, const Timetable& p2) {
4+
Timetable child = p1;
5+
int half = p1.sessions.size() / 2;
6+
for (size_t i = half; i < p1.sessions.size(); ++i)
7+
child.sessions[i] = p2.sessions[i];
8+
return child;
9+
}
10+
11+
void GeneticAlgorithm::mutate(Timetable& t) {
12+
int n = t.sessions.size();
13+
for (int i = 0; i < n; ++i) {
14+
if ((rand() / (double)RAND_MAX) < mutationRate) {
15+
t.sessions[i].day = rand() % t.numDays;
16+
t.sessions[i].slot = rand() % t.slotsPerDay;
17+
t.sessions[i].room = t.rooms[rand() % t.rooms.size()].name;
18+
}
19+
}
20+
}
21+
22+
Timetable GeneticAlgorithm::run(const Timetable& base, bool verbose) {
23+
vector<Timetable> population;
24+
for (int i = 0; i < populationSize; ++i) {
25+
Timetable t = base;
26+
t.generateRandom();
27+
population.push_back(t);
28+
}
29+
30+
Timetable best = population[0];
31+
int bestFitness = best.computeConflicts();
32+
33+
for (int gen = 0; gen < generations; ++gen) {
34+
sort(population.begin(), population.end(),
35+
[](const Timetable &a, const Timetable &b) {
36+
return a.computeConflicts() < b.computeConflicts();
37+
});
38+
39+
if (population[0].computeConflicts() < bestFitness) {
40+
best = population[0];
41+
bestFitness = best.computeConflicts();
42+
}
43+
44+
if (bestFitness == 0) break; // Perfect timetable found
45+
46+
vector<Timetable> newPop;
47+
for (int i = 0; i < populationSize / 2; ++i) {
48+
Timetable child1 = crossover(population[i], population[rand() % populationSize]);
49+
Timetable child2 = crossover(population[rand() % populationSize], population[i]);
50+
mutate(child1);
51+
mutate(child2);
52+
newPop.push_back(child1);
53+
newPop.push_back(child2);
54+
}
55+
population = newPop;
56+
57+
if (verbose && gen % 10 == 0)
58+
cout << "Generation " << gen << " | Best Conflicts: " << bestFitness << "\n";
59+
}
60+
61+
return best;
62+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef GENETIC_ALGORITHM_H
2+
#define GENETIC_ALGORITHM_H
3+
4+
#include "timetable.h"
5+
6+
class GeneticAlgorithm {
7+
public:
8+
int populationSize;
9+
int generations;
10+
double mutationRate;
11+
12+
GeneticAlgorithm(int pop, int gen, double mut)
13+
: populationSize(pop), generations(gen), mutationRate(mut) {}
14+
15+
Timetable run(const Timetable& base, bool verbose = true);
16+
17+
private:
18+
Timetable crossover(const Timetable& p1, const Timetable& p2);
19+
void mutate(Timetable& t);
20+
};
21+
22+
#endif

Src/Time_table_Generator/main.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "timetable.h"
2+
#include "genetic_algorithm.h"
3+
#include "utils.h"
4+
5+
int main() {
6+
srand(time(nullptr));
7+
cout << "\n=== C++ Timetable Generator (Genetic Algorithm) ===\n";
8+
Timetable base = getUserInput();
9+
10+
GeneticAlgorithm ga(30, 100, 0.1); // pop size, generations, mutation rate
11+
Timetable optimized = ga.run(base, true);
12+
13+
cout << "\nFinal Best Timetable (Conflicts: " << optimized.computeConflicts() << ")\n";
14+
optimized.print();
15+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "timetable.h"
2+
#include <algorithm>
3+
#include <cstdlib>
4+
#include <ctime>
5+
#include <iostream>
6+
using namespace std;
7+
8+
void Timetable::generateRandom() {
9+
sessions.clear();
10+
srand(time(nullptr));
11+
for (auto &course : courses) {
12+
for (int i = 0; i < course.sessionsPerWeek; ++i) {
13+
Session session;
14+
session.courseName = course.name;
15+
session.instructor = course.instructor;
16+
session.room = rooms[rand() % rooms.size()].name;
17+
session.day = rand() % numDays;
18+
session.slot = rand() % slotsPerDay;
19+
sessions.push_back(session);
20+
}
21+
}
22+
}
23+
24+
int Timetable::computeConflicts() const {
25+
int conflicts = 0;
26+
27+
// Room & instructor conflicts
28+
for (size_t i = 0; i < sessions.size(); ++i) {
29+
for (size_t j = i + 1; j < sessions.size(); ++j) {
30+
const Session &a = sessions[i];
31+
const Session &b = sessions[j];
32+
if (a.day == b.day && a.slot == b.slot) {
33+
if (a.room == b.room) conflicts++; // Room conflict
34+
if (a.instructor == b.instructor) conflicts++; // Instructor conflict
35+
}
36+
}
37+
}
38+
39+
// Preferred time-slot conflicts
40+
for (auto &s : sessions) {
41+
auto it = find_if(courses.begin(), courses.end(),
42+
[&](const Course &c){ return c.name == s.courseName; });
43+
if (it != courses.end() && !it->allowedSlots.empty()) {
44+
if (find(it->allowedSlots.begin(), it->allowedSlots.end(), s.slot) == it->allowedSlots.end()) {
45+
conflicts++; // Penalize for being outside preferred slots
46+
}
47+
}
48+
}
49+
50+
return conflicts;
51+
}
52+
53+
void Timetable::print() const {
54+
vector<Session> sorted = sessions;
55+
sort(sorted.begin(), sorted.end(), [](const Session &a, const Session &b) {
56+
if (a.day != b.day) return a.day < b.day;
57+
return a.slot < b.slot;
58+
});
59+
60+
cout << "\n===== Optimized Timetable =====\n";
61+
for (auto &s : sorted) {
62+
string slotLabel = (s.slot >= 0 && s.slot < (int)slotLabels.size() && !slotLabels[s.slot].empty())
63+
? slotLabels[s.slot]
64+
: ("Slot " + to_string(s.slot + 1));
65+
66+
cout << "Day " << s.day + 1 << ", " << slotLabel
67+
<< " | " << s.courseName
68+
<< " | Instructor: " << s.instructor
69+
<< " | Room: " << s.room << "\n";
70+
}
71+
cout << "===============================\n";
72+
}
416 KB
Binary file not shown.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef TIMETABLE_H
2+
#define TIMETABLE_H
3+
4+
#include <bits/stdc++.h>
5+
using namespace std;
6+
7+
struct Course {
8+
string name;
9+
string instructor;
10+
int sessionsPerWeek;
11+
vector<int> allowedSlots; // Optional preferred slots (0-based index)
12+
};
13+
14+
struct Room {
15+
string name;
16+
};
17+
18+
struct Session {
19+
string courseName;
20+
string instructor;
21+
string room;
22+
int day;
23+
int slot;
24+
};
25+
26+
class Timetable {
27+
public:
28+
int numDays;
29+
int slotsPerDay;
30+
vector<string> slotLabels; // Custom time labels
31+
vector<Room> rooms;
32+
vector<Course> courses;
33+
vector<Session> sessions;
34+
35+
Timetable() {}
36+
Timetable(int d, int s, const vector<Room>& r, const vector<Course>& c,
37+
const vector<string>& labels)
38+
: numDays(d), slotsPerDay(s), rooms(r), courses(c), slotLabels(labels) {}
39+
40+
void generateRandom();
41+
int computeConflicts() const;
42+
void print() const;
43+
};
44+
45+
#endif

Src/Time_table_Generator/utils.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#ifndef UTILS_H
2+
#define UTILS_H
3+
4+
#include "timetable.h"
5+
6+
Timetable getUserInput() {
7+
int days, slots, numRooms, numCourses;
8+
cout << "Enter number of days in week: ";
9+
cin >> days;
10+
cout << "Enter slots per day: ";
11+
cin >> slots;
12+
13+
cout << "\nEnter a label or time for each slot (e.g., 9:00-10:00):\n";
14+
vector<string> slotLabels(slots);
15+
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // flush buffer
16+
for (int i = 0; i < slots; ++i) {
17+
cout << "Slot " << i + 1 << " label: ";
18+
getline(cin, slotLabels[i]);
19+
if (slotLabels[i].empty()) slotLabels[i] = "Slot " + to_string(i + 1);
20+
}
21+
22+
cout << "\nEnter number of rooms: ";
23+
cin >> numRooms;
24+
vector<Room> rooms(numRooms);
25+
for (int i = 0; i < numRooms; ++i) {
26+
cout << "Room " << i + 1 << " name: ";
27+
cin >> rooms[i].name;
28+
}
29+
30+
cout << "\nEnter number of courses: ";
31+
cin >> numCourses;
32+
vector<Course> courses(numCourses);
33+
for (int i = 0; i < numCourses; ++i) {
34+
cout << "\nCourse " << i + 1 << " name: ";
35+
cin >> courses[i].name;
36+
cout << "Instructor name: ";
37+
cin >> courses[i].instructor;
38+
cout << "Sessions per week: ";
39+
cin >> courses[i].sessionsPerWeek;
40+
41+
// Preferred slots
42+
cout << "Enter number of preferred slots for this course (0 for no preference): ";
43+
int prefCount;
44+
cin >> prefCount;
45+
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // flush leftover newline
46+
47+
courses[i].allowedSlots.clear();
48+
for (int j = 0; j < prefCount; ++j) {
49+
int slot;
50+
cout << "Preferred slot index (1-" << slots << "): ";
51+
cin >> slot;
52+
courses[i].allowedSlots.push_back(slot - 1); // 0-based index
53+
}
54+
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // flush after the loop
55+
56+
}
57+
58+
return Timetable(days, slots, rooms, courses, slotLabels);
59+
}
60+
61+
#endif

0 commit comments

Comments
 (0)