meeat/utils/instantrunoff

83 lines
1.9 KiB
Python
Executable File

#!/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)