def addExtras(quintuplets: list, leftoverStudents: list, matchBefore: dict): for student in leftoverStudents: index = -1 #The index of the group the student will add onto maxScore = -20000 #The max score group that the student would like for i in range(len(quintuplets)): if len(quintuplets[i]) != 5: #Skip this index because its not a valid group of five continue #Test whether the group has matched before tempList = [student] tempList.extend(quintuplets[i]) if isValidGroup(matchBefore, tempList) == 0: #The group is valid so you may commence tempScore = scoreGroupByOne(student, quintuplets[i], matchBefore) if tempScore > maxScore: index = i maxScore = tempScore if index == -1: print("Error: literally could not find student a group to match to, so I stuck the student in the first group") index = 0 quintuplets[index].append(student) return quintuplets
def makeQuads(students: dict, matchDict: dict, pairs: list): #Make a copy that won't change the orignal students extraStudents = [] for pair in pairs: extraStudents.append(pair) quads = [] #Control mechanisms for the loop: check if all the pairs been put into quads finished = False if len(extraStudents) == 0: finished = True i = 0 #You don't want to loop too many times, but run five times at most to find good matches that have not matched before while(not finished and i < 10): preferenceList = preferenceSymmetricalSort(extraStudents, "TwoByTwo", matchDict) game = StableRoommates.create_from_dictionary(preferenceList) ans = game.solve() #remove the students who did not find matches out, delete them from the ans dict extraStudents = removeImpossibleTwo(ans, matchDict, students, pairs, extraStudents) #Take the remaining, succesful students, and place them into pairs moveStudentsTwo(ans, quads, students, pairs) #Update your controls if len(extraStudents) == 0: finished = True i = i + 1 for index in range(5): listUsedIndexes = list() pairsToMake = list() for index1 in range(len(extraStudents)): for index2 in range(len(extraStudents)): if index1 != index2 and (index1 not in listUsedIndexes) and (index2 not in listUsedIndexes): if isValidGroup(matchDict, [extraStudents[index1][0], extraStudents[index1][1], extraStudents[index2][0], extraStudents[index2][1]]) == 0: listUsedIndexes.append(index1) listUsedIndexes.append(index2) pairsToMake.append([index1, index2]) usedStudents = list() for pairToMake in pairsToMake: quads.append([extraStudents[pairToMake[0]][0], extraStudents[pairToMake[0]][1], extraStudents[pairToMake[1]][0], extraStudents[pairToMake[1]][1]]) usedStudents.extend([extraStudents[pairToMake[0]], extraStudents[pairToMake[1]]]) for student in usedStudents: extraStudents.remove(student) #Now do random for index in range(0, len(extraStudents), 2): quads.append([extraStudents[index][0], extraStudents[index][1], extraStudents[index+1][0], extraStudents[index+1][1]]) extraStudents.clear() return quads
def removeImpossibleTwo(game: dict, matchDict: dict, students: dict, pairs: list, studentSupposedToBeMatched: list): #create an empty list to store all the removed students extraStudents = [] #I can't change the dict size while its going, so I need to record all the keys to take out in the iteration keysToTakeOut = [] #The game ignores people it did not match, so if someone is supposed to matched and isn't, move them back into extra students for pair in studentSupposedToBeMatched: flag = False for key in game: if students[int(str(key))] in pair: flag = True break if not flag: extraStudents.append(pair) for key in game: if key != None and game[key]!= None: #only want to make a list of both students if they exist tempList = [0] * 4 student1 = students[int(str(key))] student2 = students[int(str(game[key]))] for pair in pairs: flag1 = False flag2 = False if student1 in pair: flag1 = True tempList[0] = pair[0] tempList[1] = pair[1] if student2 in pair: flag2 = True tempList[2] = pair[0] tempList[3] = pair[1] if flag1 and flag2: break #If the two people cannot be in the group, then we are going to remove the first person if isValidGroup(matchDict, tempList) != 0: #Delete both people from the list and move them into extraStudents keysToTakeOut.append(key) for key in keysToTakeOut: #Need to add back both students in the pair for pair in pairs: #Find the pair that corresponds to this key #Should probably make pair into a dictionary later if students[int(str(key))] in pair: extraStudents.append(pair) break game.pop(key) return extraStudents
def scoreOneByOne(student1: Student, student2: Student, matchDict: dict): #Assign weights to the priorty list scoreWeights = [50, 30, 15, 5, 0] score = 0 if matchPartner(student1, student2) > 0 and matchPartner( student2, student1) > 0: score += 40000 for i in range(4): #IF the priority list hits default, score no further if student1.priorityList[i] == "default": break #If the student priority is matched, add its weight to the score elif student1.priorityList[i] == "International": if matchInternational(student1, student2): score = score + scoreWeights[i] elif student1.priorityList[i] == "Language": if matchLanguage(student1, student2): score = score + scoreWeights[i] elif student1.priorityList[i] == "Matching Time to Meet": if matchTime(student1, student2): score = score + scoreWeights[i] elif student1.priorityList[i] == "What They Want to Do": if matchActivity(student1, student2): score = score + scoreWeights[i] elif student1.priorityList[i] == "Gender": if matchGender(student1, student2): score = score + scoreWeights[i] else: print( "Error, this index of the priority list does not meet any acceptable criteria", student1.name, i) #If the two students have matched before, punish it harshly in score #The punishment needs to be high enough to make groups with only one match still poor tempList = [student1, student2] score = score - 2000 * isValidGroup(matchDict, tempList) return score
def removeImpossibleOne(game: dict, matchDict: dict, students: dict, studentsSupposedToBeMatched: list): #create an empty list to store all the removed students extraStudents = [] #I can't change the dict size while its going, so I need to record all the keys to take out in the iteration keysToTakeOut = [] #The game ignores people it did not match, so if someone is supposed to matched and isn't, move them back into extra students for student in studentsSupposedToBeMatched: flag = False for key in game: if students[int(str(key))] == student: flag = True break if not flag: extraStudents.append(student) for key in game: if game[key] == "": keysToTakeOut.append(key) continue #only want to make a list of both students if they exist if key != None and game[key] != None: listStudents = [ students[int(str(key))], students[int(str(game[key]))] ] #If the two people cannot be in the group, then we are going to remove the first person if isValidGroup(matchDict, listStudents) != 0: #Delete both people from the list and move them into extraStudents keysToTakeOut.append(key) continue #For each key to take out, add that student to extraStudents for key in keysToTakeOut: extraStudents.append(students[int(str(key))]) game.pop(key) return extraStudents
def removeImpossibleQuin(ans: dict, matchDict: dict, students: dict, aloneStudents:dict, aloneSupposedToBeMatched:list, quadSupposedToBeMatched: list): remainingAlone = [] remainingQuads = [] #If the remaing along and quads from supposed to be matching do not show up in the ans, place them back to be matched for student in aloneSupposedToBeMatched: for key in ans: flag = False if aloneStudents[int(str(key))] == student: flag = True break if not flag: remainingAlone.append(student) for quad in quadSupposedToBeMatched: for key in ans: flag = False if students[int(str(ans[key]))] in quad: flag = True break if not flag: remainingQuads.append(quad) keysToTakeOut = [] #For the rest, check to make sure the pairing is valid for key in ans: if key != None and ans[key] != None: tempList = [aloneStudents[int(str(key))]] quadStudent = students[int(str(ans[key]))] flagQuad = False for quad in quadSupposedToBeMatched: if quadStudent in quad: tempList.extend(quad) flagQuad = True break if flagQuad == False: print("Could not find quad in removeimpossible") if isValidGroup(matchDict, tempList) != 0: keysToTakeOut.append(key) for key in keysToTakeOut: #Find the students that correspond to these keys remainingAlone.append(aloneStudents[int(str(key))]) quadStudent = students[int(str(ans[key]))] for quad in quadSupposedToBeMatched: if quadStudent in quad: remainingQuads.append(quad) break ans.pop(key) aloneSupposedToBeMatched.clear() quadSupposedToBeMatched.clear() aloneSupposedToBeMatched.extend(remainingAlone) quadSupposedToBeMatched.extend(remainingQuads) return
def makePairs(students: dict, matchDict: dict): #Make a copy that won't change the orignal students extraStudents = [] for student in students: extraStudents.append((students[student])) pairs = [] #Control mechanisms for the loop: check if all the students have been paired, and that the list has not been finished = False if len(extraStudents) == 0: finished = True i = 0 #You don't want to loop too many times, but run five times at most to find good matches that have not matched before while(not finished and i < 10): preferenceList = preferenceSymmetricalSort(extraStudents, "OneByOne", matchDict) game = StableRoommates.create_from_dictionary(preferenceList) ans = game.solve() #remove the students who did not find matches out, delete them from the ans dict extraStudents = removeImpossibleOne(ans, matchDict, students, extraStudents) #Take the remaining, succesful students, and place them into pairs moveStudentsOne(ans, pairs, students) #Update your controls if len(extraStudents) == 0: finished = True break i = i + 1 for index in range(5): listUsedIndexes = list() pairsToMake = list() for index1 in range(len(extraStudents)): for index2 in range(len(extraStudents)): if index1 != index2 and (index1 not in listUsedIndexes) and (index2 not in listUsedIndexes): if isValidGroup(matchDict, [extraStudents[index1], extraStudents[index2]]) == 0: listUsedIndexes.append(index1) listUsedIndexes.append(index2) pairsToMake.append([index1, index2]) usedStudents = list() for pairToMake in pairsToMake: pairs.append([extraStudents[pairToMake[0]], extraStudents[pairToMake[1]]]) usedStudents.extend([extraStudents[pairToMake[0]], extraStudents[pairToMake[1]]]) for student in usedStudents: extraStudents.remove(student) if len(extraStudents)%2 == 1: print("Problem: odd number of students in extraStudents") #Match the rest of the students randomly and print that the matching sucked for index in range(0, len(extraStudents), 2): if (index+1) < len(extraStudents): pairs.append([extraStudents[index], extraStudents[index+1]]) extraStudents.clear() #Return the pairs list (list[Student, Student]) return pairs
def makeQuintuplets(quads: list, aloneStudents: dict, singles: dict, matchBefore: dict): #Each quad needs to match with one alone Student #make an empty list to avoid changing quads and aloneStudents extraStudentsQuads = [] extraStudentsAlone = [] for quad in quads: extraStudentsQuads.append(quad) for key in aloneStudents: extraStudentsAlone.append(aloneStudents[key]) quintuplets = [] finished = False if len(extraStudentsAlone) != len(extraStudentsQuads): print("Error: size mismatch in makeQuintuplets") if len(extraStudentsAlone) == 0: finished = True i = 0 while (not finished) and i < 5: preferenceListOnes = preferenceAsymmetricalSort(extraStudentsAlone, extraStudentsQuads, "GroupByOne", matchBefore) preferenceListQuads = preferenceAsymmetricalSort(extraStudentsQuads, extraStudentsAlone, "OneByGroup", matchBefore) game = StableMarriage.create_from_dictionaries(preferenceListOnes, preferenceListQuads) ans = game.solve() removeImpossibleQuin(ans, matchBefore, singles, aloneStudents, extraStudentsAlone, extraStudentsQuads) moveStudentsGroups(quintuplets, ans, singles, aloneStudents, quads) if len(extraStudentsAlone) == 0: finished = True i = i+ 1 if len(extraStudentsAlone) != len(extraStudentsQuads): print("Errror: size mismatch in makeQuintuplets") listUsedIndexesAlone = list() listUsedIndexesQuads = list() groupsToMake = list() for index1 in range(len(extraStudentsAlone)): for index2 in range(len(extraStudentsQuads)): if index1 not in listUsedIndexesAlone and index2 not in listUsedIndexesQuads: tempList = [(extraStudentsAlone[index1])] tempList.extend(extraStudentsQuads[index2]) if isValidGroup(matchBefore, tempList) == 0: listUsedIndexesAlone.append(index1) listUsedIndexesQuads.append(index2) groupsToMake.append([index1, index2]) usedAlone = list() usedQuads = list() for groupToMake in groupsToMake: tempList = [extraStudentsAlone[groupToMake[0]]] tempList.extend(extraStudentsQuads[groupToMake[1]]) quintuplets.append(tempList) usedAlone.append(extraStudentsAlone[groupToMake[0]]) usedQuads.append(extraStudentsQuads[groupToMake[1]]) for student in usedAlone: extraStudentsAlone.remove(student) for student in usedQuads: extraStudentsQuads.remove(student) for index in range(0, len(extraStudentsAlone)): tempList = extraStudentsQuads[index] tempList.append(extraStudentsAlone[index]) quintuplets.append(tempList) extraStudentsAlone.clear() extraStudentsQuads.clear() return quintuplets
def gradeGroups(groups: list, matchBefore: dict): #Count the number of students who did or did not take the survey defaultStudents = 0 studentsTakeSurvey = 0 #Count the number of students who succesfully got a gender match out of the ones who wanted it studentsGenderMatch = 0 studentsWantGenderMatch = 0 #Count the number of students who wanted asynch/synch and got a match in their group studentsWantTime = 0 studentsGotTime = 0 #Count the number of groups and the valid groups numGroups = 0 numValidGroups = 0 #Count the number of groups with a leader personality groupsGotLeader = 0 #Count the number of students who wanted another international student and got it studentsWantInternational = 0 studentsGotInternational = 0 #Count all the students who got their preferred language studentsGotLanguage = 0 #Count all the students who got their preferred activity studentsGotOption = 0 #Count which priority the students got first #If both second choice and first are met on one student, only firstChoice increases studentGotChoice = [0, 0, 0, 0, 0, 0] #Count the number of groups where there are people of multiple confidence levels numGroupsMixConfidence = 0 #Iterate through each group for group in groups: #Increment the number of overall Groups numGroups = numGroups + 1 #increment valid group if the groups are valid if isValidGroup(matchBefore, group) == 0: numValidGroups = numValidGroups + 1 #increment confidenceLevels if group has a mixture of high to low confidence if scoreAtLeastOneConfidenceLevel(group) > 0: numGroupsMixConfidence = numGroupsMixConfidence + 1 #a flag that becomes true if anyone in the group is a leader flagLeader = False #The others are by person for person in group: #Flags to control what the person does and does not get flagGender = False flagTime = False flagInternational = False flagLanguage = False flagOption = False #Default students should not affect stats if person.pronouns == "default/defaults": defaultStudents = defaultStudents + 1 continue else: studentsTakeSurvey = studentsTakeSurvey + 1 #if anyone in the group is a leader, the whole group gets a leader if person.preferLeader == True: flagLeader = True #check this person based on the rest of the group for person2 in group: #Don't check a person against themself if person != person2: #Gender if matchGender(person, person2): flagGender = True #Time if matchTime(person, person2): flagTime = True #International if matchInternational(person, person2): flagInternational = True #Language if person.language == person2.language: flagLanguage = True #Option if person.option1 == person2.option1: flagOption = True #Only count the person if the person wanted to match on gender if person.preferSame != 1: studentsWantGenderMatch = studentsWantGenderMatch + 1 if flagGender: studentsGenderMatch = studentsGenderMatch + 1 #Only count the person if the person wanted to match on time if person.preferAsy != 1: studentsWantTime = studentsWantTime + 1 if flagTime: studentsGotTime = studentsGotTime + 1 #Only count the person if the person wanted to match on international if person.international == 2: studentsWantInternational = studentsWantInternational + 1 if flagInternational: studentsGotInternational = studentsGotInternational + 1 #The student matched at least one other person on language if flagLanguage: studentsGotLanguage = studentsGotLanguage + 1 #The student matched at least one other person on activity if flagOption: studentsGotOption = studentsGotOption + 1 #Find the highest priority that the student managed to get for i in range(5): #If at any point, they default, ignore the rest of their opinions if person.priorityList[i] == "default": break elif person.priorityList[i] == "Gender": if flagGender: studentGotChoice[i] = studentGotChoice[i] + 1 break elif person.priorityList[i] == "International": if flagInternational: studentGotChoice[i] = studentGotChoice[i] + 1 break elif person.priorityList[i] == "Language": if flagLanguage: studentGotChoice[i] = studentGotChoice[i] + 1 break elif person.priorityList[i] == "What They Want to Do": if flagOption: studentGotChoice[i] = studentGotChoice[i] + 1 break elif person.priorityList[i] == "Matching Time to Meet": if flagTime: studentGotChoice[i] = studentGotChoice[i] + 1 break #If any student flagged as a leader, the group has a leader if flagLeader: groupsGotLeader = groupsGotLeader + 1 print(studentsTakeSurvey, " of students took the survey while ", defaultStudents, " did not take it.") print("Group who got leader: " + str((100 * (groupsGotLeader / numGroups))) + "%") print("Group who got confidence: " + str((100 * (numGroupsMixConfidence / numGroups))) + "%") print("Students who got gender match: " + str((100 * (studentsGenderMatch / studentsWantGenderMatch))) + "%") print("Students who got time: " + str((100 * (studentsGotTime / studentsWantTime))) + "%") print("Students who got international: " + str((100 * (studentsGotInternational / studentsWantInternational))) + "%") print("Students who got language: " + str((100 * (studentsGotLanguage / studentsTakeSurvey))) + "%") print("Students who got activity: " + str((100 * (studentsGotOption / studentsTakeSurvey))) + "%") print() print("First choice: ", studentGotChoice[0]) print("Second choice: ", studentGotChoice[1]) print("Third choice: ", studentGotChoice[2]) print("Fourth choice: ", studentGotChoice[3]) print("Fifth choice: ", studentGotChoice[4]) studentGotNoChoice = studentsTakeSurvey - sum(studentGotChoice) print("\nGroups that are valid: " + str(numValidGroups / numGroups * 100) + "%") print()