55import edu .uga .devdogs .sampledataparser .records .Class ;
66import edu .uga .devdogs .sampledataparser .records .HConstraints ;
77
8+ //import edu.uga.devdogs.course_information.service;
9+ //import org.springframework.beans.factory.annotation.Autowired;
10+
811import java .util .ArrayList ;
912import java .util .List ;
1013import java .util .Map ;
1114import java .util .TreeSet ;
15+ import java .util .EnumMap ;
1216import java .util .Set ;
1317
18+ import java .time .DayOfWeek ;
19+ import java .time .LocalTime ;
20+
21+
1422
1523/**
1624 * Utility class for performing operations and calculations related to a Schedule.
2230 */
2331public class ScheduleUtil {
2432
33+ // Used for bootstrap getting coords
34+ //@Autowired
35+ //private CourseInformationService courseInformationService;
36+
2537 /**
2638 * Validates the given schedule by checking for any time conflicts between classes.
2739 * A time conflict occurs when two classes overlap in their scheduled times.
@@ -86,7 +98,7 @@ public static double computeAverageProfessorQuality(Schedule schedule) {
8698
8799 /**
88100 * Checks if schedule or constraints is null and throws an exception if it is.
89- *
101+ *
90102 * @param schedule the schedule to validate
91103 * @param constraints the constraints to validate
92104 */
@@ -115,22 +127,46 @@ public static double computeMaxDistance(Schedule schedule, Map<String, Map<Strin
115127 // Iterates over each day in the schedule
116128 for (TreeSet <Class > day : schedule .days ().values ()) {
117129 // Converts the TreeSet to List for direct indexing
118- // TODO: Replace TreeSet with a sorted List for days in Schedule
119130 List <Class > dayList = new ArrayList <>(day );
120131
121132 // Iterates over consecutive class pairs
122133 for (int i = 0 ; i < dayList .size () - 1 ; i ++) {
123134 Class currClass = dayList .get (i );
124135 Class nextClass = dayList .get (i + 1 );
125- double distance = distances .get (currClass .buildingName ()).get (nextClass .buildingName ());
136+
137+ double lat1 = 0.0 ;//courseInformationService.getLatitude(currClass.buildingNumber());
138+ double lon1 = 0.0 ; //courseInformationService.getLongitude(currClass.buildingNumber());
139+ double lon2 = 0.0 ; //courseInformationService.getLongitude(nextClass.buildingNumber());
140+ double lat2 = 0.0 ; //courseInformationService.getLatitude(nextClass.buildingNumber());
141+
142+ // distance between latitudes and longitudes
143+ double dLat = Math .toRadians (lat2 - lat1 );
144+ double dLon = Math .toRadians (lon2 - lon1 );
145+
146+ // convert to radians
147+ lat1 = Math .toRadians (lat1 );
148+ lat2 = Math .toRadians (lat2 );
149+
150+ // apply Haversine formula
151+ double a = Math .pow (Math .sin (dLat / 2 ), 2 ) +
152+ Math .pow (Math .sin (dLon / 2 ), 2 ) *
153+ Math .cos (lat1 ) *
154+ Math .cos (lat2 );
155+
156+ // Earth's radius in miles
157+ double rad = 3960 ;
158+ double c = 2 * Math .asin (Math .sqrt (a ));
159+ double distance = rad * c ;
126160
127161 if (distance > maxDistance ) {
128162 maxDistance = distance ;
129163 }
130164 }
131165 }
132166
133- return maxDistance ;
167+ // dimensional analysis. Average human walking speed is 3 miles per hour.
168+ // miles * (hours/miles) * (minutes/hours)
169+ return maxDistance * (1 /3 ) * (60 );
134170 }
135171
136172 /**
@@ -174,6 +210,63 @@ public static double computeAverageIdleTime(Schedule schedule) {
174210 return (double ) sumOfTimeGaps / countOfClassGaps ;
175211 }
176212
213+
214+
215+ /**
216+ * Computes the earliest start time of all classes in a schedule
217+ *
218+ * @param schedule the schedule for which to compute the earliest start time
219+ * @return the earliest start time (in hours) as a double. For example, 4:30 pm would be represented as 16.5
220+ */
221+ public static double computeStartTime (Schedule schedule ) {
222+ LocalTime earliestStartTime = LocalTime .of (23 ,59 ,59 );
223+ for (Section eachSection : schedule .sections ()) {
224+ for (Class eachClass : eachSection .classes ()) {
225+ if (eachClass .startTime ().isBefore (earliestStartTime )) {
226+ earliestStartTime = eachClass .startTime ();
227+ }
228+ }
229+ }
230+ return earliestStartTime .getHour () + (double ) earliestStartTime .getMinute () / 60 ;
231+ }
232+
233+
234+
235+ /**
236+ * Computes the latest start time of all classes in a schedule
237+ *
238+ * @param schedule the schedule for which to compute the latest start time
239+ * @return the latest start time (in hours) as a double. For example, 4:30 pm would be represented as 16.5
240+ */
241+ private static double computeEndTime (Schedule schedule ) {
242+ LocalTime latestStartTime = LocalTime .of (0 ,0 ,0 );
243+ for (Section eachSection : schedule .sections ()) {
244+ for (Class eachClass : eachSection .classes ()) {
245+ if (eachClass .startTime ().isAfter (latestStartTime )) {
246+ latestStartTime = eachClass .startTime ();
247+ }
248+ }
249+ }
250+ return latestStartTime .getHour () + (double ) latestStartTime .getMinute () / 60 ;
251+ }
252+
253+
254+
255+ /**
256+ * Determines whether a given schedule has zero classes on a given day
257+ *
258+ * @param schedule the schedule for which to compute whether it has a gap day or not
259+ * @param gapDay the day that is being checked as a gap day or not
260+ * @return {@code true} if the given schedule has no classes on the given day, {@code false} if it has at least one class
261+ */
262+ private static boolean computeGapDay (Schedule schedule , DayOfWeek gapDay ) {
263+ EnumMap <DayOfWeek , TreeSet <Class >> days = schedule .days ();
264+ TreeSet <Class > classes = days .get (gapDay );
265+ return classes .isEmpty ();
266+ }
267+
268+
269+
177270 /**
178271 * Computes the overall objective score for the given schedule based on weighted objectives.
179272 * This method computes each objective, normalizes their values using min-max normalization, and computes a weighted sum.
@@ -185,10 +278,10 @@ public static double computeAverageIdleTime(Schedule schedule) {
185278 * @return the overall objective score for the schedule
186279 */
187280 public static double computeOverallObjective (Schedule schedule , Map <String , Map <String , Double >> distances ) {
188- // Checks if the parameters are valid
189- if (schedule == null || distances == null ) {
190- throw new IllegalArgumentException ("Parameters cannot be null" );
191- }
281+ // Checks if the parameters are valid
282+ if (schedule == null || distances == null ) {
283+ throw new IllegalArgumentException ("Parameters cannot be null" );
284+ }
192285
193286 // The minimum rating on rate my professor is 1.0(if they have ratings).
194287 final double professorQualityMinimum = 1.0 ;
@@ -251,7 +344,7 @@ public static double computeOverallObjectiveExtended(Schedule schedule, Map<Stri
251344 possSConstraintsCount ++;
252345 }
253346 if (softConstraints .prefStartTime () != null ) {
254- possSConstraintScore += normalizeValue (computeStartTime (schedule ), prefTimeMinimum , prefTimeMaximum );;
347+ possSConstraintScore += normalizeValue (computeStartTime (schedule ), prefTimeMinimum , prefTimeMaximum );
255348 possSConstraintsCount ++;
256349 }
257350 if (softConstraints .prefEndTime () != null ) {
@@ -310,4 +403,4 @@ public static int[] sectionsToInts(Set<Section> sections) {
310403 return output ;
311404 }
312405
313- }
406+ }
0 commit comments