def section_find_winner(section): win_threshold = Voter.count_eligible() * section.majority_for_change first_votes = {} for c in section.change_set.all(): first_votes[c] = Vote.do_count(section.id, c.id, 1) while True: lowest_count, lowest_c = None, None tuple_list = list(first_votes.items()) tuple_list.sort(key=lambda x: x[1]) highest_count = tuple_list[len(tuple_list)-1][1] if highest_count >= win_threshold: top = [t[0] for t in tuple_list if t[1] == highest_count] return section_tie_break(section, top) lowest_count = tuple_list[0][1] elim_cands = [t[0] for t in tuple_list if t[1] == lowest_count] lowest_c, _ = section_tie_break(section, elim_cands, find_worst=True) # re-assign votes for lowest_c to next pref - TODO: optimize! for orig_vote in Vote.objects.filter(section=section, change=lowest_c): alternates = Vote.objects.filter(voter=orig_vote.voter, section=section, priority__gt=orig_vote.priority) if len(alternates) > 0: alt = alternates[0].change if alt not in first_votes: first_votes[alt] = 0 first_votes[alt] += 1 # eliminate lowest_c del first_votes[lowest_c] if len(first_votes) == 0: return (None, None)
def section_tie_break(section, change_list, find_worst=False): if len(change_list) == 0: raise Exception('av tie break given empty change_list') #print('section tie break: ' + ' '.join([c.name for c in change_list])) change_tuples = [] for change in change_list: prefs = Vote.do_count(section.id, change.id) change_tuples.append((change, prefs)) #print('section tie break: ' + str(change_tuples)) return tie_break(change_tuples, find_worst)