diff --git a/utils/instantrunoff b/utils/instantrunoff new file mode 100755 index 0000000..a8a5428 --- /dev/null +++ b/utils/instantrunoff @@ -0,0 +1,82 @@ +#!/usr/bin/python3 + +import argparse + +import psycopg +import psycopg.rows + +def get_args(): + ap = argparse.ArgumentParser() + ap.add_argument("meet", type=int) + ap.add_argument("kind") + + args = ap.parse_args() + return args + +def get_ballots(): + db = psycopg.connect(dbname="meeat", user="www-meeat") + + csr = db.cursor(row_factory=psycopg.rows.namedtuple_row) + + kind = args.kind + q = f""" + select {kind}.*, bod, position + from {kind} join {kind}_vote on {kind}.id = {kind}_vote.{kind} + where meet = %s + order by bod, position + """ + csr.execute(q, (args.meet,)) + + last_bod = None + ballots = [] + for r in csr: + if r.bod != last_bod: + ballot = [] + ballots.append(ballot) + last_bod = r.bod + ballot.append(r) + return ballots + +def dump_ballots(ballots): + for ballot in ballots: + print ("---") + for r in ballot: + print(r) + +def runoff(ballots): + count = {} + candidates = {} + for ballot in ballots: + for r in ballot: + count[r.id] = 0 + candidates[r.id] = r + for ballot in ballots: + # The votes are sorted by position, so the first entry is the favourite + count[ballot[0].id] += 1 + result = sorted(count.keys(), key=lambda i: count[i]) + print("result of this round:") + for r in result: + print(r, count[r]) + print("striking", result[0]) + loser = candidates[result[0]] + new_ballots = [ + [ + r for r in ballot if r.id != loser.id + ] for ballot in ballots + ] + return loser, new_ballots + +if __name__ == "__main__": + args = get_args() + + ballots = get_ballots() + + result = [] + while max(len(b) for b in ballots): + dump_ballots(ballots) + loser, ballots = runoff(ballots) + result.append(loser) + result = reversed(result) + print("final result") + for r in result: + print(r)