Skip to content

Commit

Permalink
Update sort algorithm for "most compact" (#167)
Browse files Browse the repository at this point in the history
### Summary

Resolves #160 

Updates the "most compact" sorting option to account for custom blocks

### Checklist

- [x] Combinations are sorted appropriately for each setting.
- [x] Related components (if any) are updated if this change affects
them (`Calendar` is an example). -- I don't think anything was impacted
by this change

### How to Test
Create a few custom blocks, check how the ordering of the combinations
changes as a result

---------

Co-authored-by: Nghi Ho <[email protected]>
  • Loading branch information
nathangong and nhatnghiho authored Feb 23, 2023
1 parent a6a84e6 commit efac436
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 10 deletions.
4 changes: 2 additions & 2 deletions src/components/CombinationContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export default function CombinationContainer(): React.ReactElement {
[oscar, desiredCourses, pinnedCrns, excludedCrns, events]
);
const sortedCombinations = useMemo(
() => oscar.sortCombinations(combinations, sortingOptionIndex),
[oscar, combinations, sortingOptionIndex]
() => oscar.sortCombinations(combinations, sortingOptionIndex, events),
[oscar, combinations, sortingOptionIndex, events]
);

return (
Expand Down
34 changes: 29 additions & 5 deletions src/data/beans/Oscar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,35 @@ export default class Oscar {
});

this.sortingOptions = [
new SortingOption('Most Compact', (combination) => {
new SortingOption('Most Compact', (combination, events) => {
const { startMap, endMap } = combination;

const eventStartMap = new Map<string, number>();
const eventEndMap = new Map<string, number>();
events.forEach((event) => {
const { start, end } = event.period;
for (const day of event.days) {
if (!eventStartMap.has(day)) {
eventStartMap.set(day, start);
}
eventStartMap.set(
day,
Math.min(start, eventStartMap.get(day) ?? Infinity)
);

if (!eventEndMap.has(day)) {
eventEndMap.set(day, end);
}
eventEndMap.set(day, Math.max(end, eventEndMap.get(day) ?? -1));
}
});
const diffs = Object.keys(startMap).map((day) => {
const end = endMap[day];
const start = startMap[day];
let end = endMap[day];
let start = startMap[day];
if (end == null || start == null) return 0;
end = Math.max(end, eventEndMap.get(day) ?? -1);
start = Math.min(start, eventStartMap.get(day) ?? Infinity);

return end - start;
});
const sum = diffs.reduce((tot, min) => tot + min, 0);
Expand Down Expand Up @@ -312,7 +335,8 @@ export default class Oscar {

sortCombinations(
combinations: Combination[],
sortingOptionIndex: number
sortingOptionIndex: number,
events: Immutable<Event[]>
): Combination[] {
const sortingOption = this.sortingOptions[sortingOptionIndex];
if (sortingOption === undefined) {
Expand All @@ -329,7 +353,7 @@ export default class Oscar {
return combinations
.map((combination) => ({
...combination,
factor: sortingOption.calculateFactor(combination),
factor: sortingOption.calculateFactor(combination, events),
}))
.sort((a, b) => a.factor - b.factor);
}
Expand Down
11 changes: 8 additions & 3 deletions src/data/beans/SortingOption.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Combination } from '../../types';
import { Immutable } from 'immer';

import { Combination, Event } from '../../types';

export default class SortingOption {
label: string;

calculateFactor: (combo: Combination) => number;
calculateFactor: (combo: Combination, events: Immutable<Event[]>) => number;

constructor(label: string, calculateFactor: (combo: Combination) => number) {
constructor(
label: string,
calculateFactor: (combo: Combination, events: Immutable<Event[]>) => number
) {
this.label = label;
this.calculateFactor = calculateFactor;
}
Expand Down

0 comments on commit efac436

Please sign in to comment.