-
Notifications
You must be signed in to change notification settings - Fork 0
/
model.pde
300 lines (246 loc) · 7.3 KB
/
model.pde
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/**
* Data modeling and data loading logic for the CU Boulder catalog visualization.
*
* @license MIT, A Samuel Pottinger
*/
/**
* Hashable and comprable object which describes the combination of school, name, and year.
*
* Hashable and comprable object which describes the combination of school, name, and year that
* identifies a group of courses in a related area of study. For example, Computer Science area of
* study in the College of Engineering and Applied Sciences for 2020.
*/
class Key implements Comparable<Key> {
private final String school;
private final String name;
private final int year;
/**
* Create a new key for a collection of related areas of study.
*
* @param newSchool The name of the school as it appears in the dataset like Engineering.
* @param newName The name of the area of study like Computer Science.
* @param newYear The integer year like 2020.
*/
public Key(String newSchool, String newName, int newYear) {
school = newSchool;
name = newName;
year = newYear;
}
/**
* Get the school or college to which this key refers.
*
* @returns The name of the school as it appears in the dataset like Engineering.
*/
public String getSchool() {
return school;
}
/**
* Get the name of the area of study to which this key refers.
*
* @returns The name of the area of study like Computer Science.
*/
public String getName() {
return name;
}
/**
* Get the year to which this key refers.
*
* @returns The integer year like 2020.
*/
public int getYear() {
return year;
}
/**
* Get a string uniquely describing this key.
*
* @returns Tab separated concat of school, name, and year.
*/
public String toString() {
return school + "\t" + name + "\t" + year;
}
/**
* Get a hash code semi-uniquely describing this key.
*
* @returns Hash of string cnotaining tab separated concat of school, name, and year.
*/
public int hashCode() {
return toString().hashCode();
}
/**
* Determine if this key refers to the same set of courses as another key.
*
* @param other The other key to which to compare.
* @returns True if they refer to the same set of courses and false otherwise.
*/
public boolean equals(Object other) {
if (!(other instanceof Key)) {
return false;
}
return toString().equals(other.toString());
}
/**
* Determine if this key alphanumerically apperas before another key.
*
* @param other The other key to which to compare.
* @returns A negative number if this comes before, 0 if they are the same, and a positive number
* otherwise.
*/
public int compareTo(Key other) {
return toString().compareTo(other.toString());
}
}
class Area implements Comparable<Area> {
private final Key key;
private final boolean hasPrior;
private final boolean hasSpring;
private final boolean hasFall;
private final List<Key> nextKeys;
public Area(boolean newHasPrior, Key newKey, boolean newHasSpring, boolean newHasFall, List<Key> newNextKeys) {
key = newKey;
hasPrior = newHasPrior;
hasSpring = newHasSpring;
hasFall = newHasFall;
nextKeys = newNextKeys;
}
public Key getKey() {
return key;
}
public String getSchool() {
return key.getSchool();
}
public String getName() {
return key.getName();
}
public int getYear() {
return key.getYear();
}
public boolean hasSpring() {
return hasSpring;
}
public boolean hasFall() {
return hasFall;
}
public boolean hasBothSemesters() {
return hasSpring && hasFall;
}
public boolean hasPrior() {
return hasPrior;
}
public boolean isInner() {
return hasPrior && nextKeys.size() == 1;
}
public boolean isTerminal() {
return nextKeys.size() == 0;
}
public List<Key> getNextKeys() {
return nextKeys;
}
public int hashCode() {
return key.hashCode();
}
public boolean equals(Object other) {
if (!(other instanceof Area)) {
return false;
}
return key.equals(((Area)other).getKey());
}
public int compareTo(Area other) {
return key.compareTo(other.getKey());
}
}
/**
* Dataset on course availability.
*/
class Dataset {
private final Map<Key, Area> areasByKey;
private final Map<Integer, Map<String, List<Area>>> areasByYearSchool;
/**
* Create a new dataset.
*
* @param areas List of areas to study in any order that make up this dataset.
*/
public Dataset(List<Area> areas) {
areasByKey = new HashMap<>();
areasByYearSchool = new HashMap<>();
Set<Area> uniqueAreas = new HashSet<>();
for (Area area : areas) {
if (uniqueAreas.contains(area)) {
throw new RuntimeException("Area duplicate: " + area.getKey());
} else {
uniqueAreas.add(area);
}
areasByKey.put(area.getKey(), area);
int year = area.getYear();
if(!areasByYearSchool.containsKey(year)) {
areasByYearSchool.put(year, new HashMap<>());
}
String school = area.getSchool();
Map<String, List<Area>> areasBySchool = areasByYearSchool.get(year);
if (!areasBySchool.containsKey(school)) {
areasBySchool.put(school, new ArrayList<>());
}
List<Area> targetList = areasBySchool.get(school);
targetList.add(area);
}
}
/**
* Get an area by key (pair of year, school / college, and area name).
*
* @param key The key to look up.
*/
public Area getByKey(Key key) {
return areasByKey.get(key);
}
/**
* Get all of the areas of study in a school or college for a year.
*
* @param year Integer year for which areas should be returned.
* @param school The name of the school as it appears in the dataset like Engineering.
* @return List of matching areas.
*/
public List<Area> getForYearSchool(int year, String school) {
Map<String, List<Area>> areasBySchool = areasByYearSchool.get(year);
if (areasBySchool.containsKey(school)) {
return areasBySchool.get(school);
} else {
return new ArrayList<>();
}
}
}
/**
* Load a global dataset for this sketch.
*
* @returns Dataset loaded from catalog.csv
*/
Dataset loadDataset() {
Table targetTable = loadTable("catalog.csv", "header");
List<Area> areas = new ArrayList<>();
Set<Key> priorKeys = new HashSet<>();
for (TableRow row : targetTable.rows()) {
String semesters = row.getString("Semester");
int year = row.getInt("Year");
String school = row.getString("School");
String name = row.getString("Area");
String nextSchool = row.getString("Next School");
String nextArea = row.getString("Next Area");
Key key = new Key(school, name, year);
boolean hasPrior = priorKeys.contains(key);
boolean hasSpring = semesters.contains("Spring");
boolean hasFall = semesters.contains("Fall");
List<Key> nextKeys = new ArrayList<>();
String[] nextNames = nextArea.split(";");
boolean hasNext = !nextNames[0].equals("");
if (hasNext) {
for (String nextName : nextNames) {
Key newKey = new Key(nextSchool, nextName, year + 5);
nextKeys.add(newKey);
// Connect but treat as new if in new school
if (nextSchool.equals(school)) {
priorKeys.add(newKey);
}
}
}
areas.add(new Area(hasPrior, key, hasSpring, hasFall, nextKeys));
}
return new Dataset(areas);
}