Author: humbedooh
Date: Sun Mar 22 21:48:53 2015
New Revision: 1668487
URL: http://svn.apache.org/r1668487
Log:
first stab at an STV calculator. This may be filled with errors, what do I know
:)
Modified:
steve/trunk/pysteve/www/cgi-bin/lib/election.py
Modified: steve/trunk/pysteve/www/cgi-bin/lib/election.py
URL:
http://svn.apache.org/viewvc/steve/trunk/pysteve/www/cgi-bin/lib/election.py?rev=1668487&r1=1668486&r2=1668487&view=diff
==============================================================================
--- steve/trunk/pysteve/www/cgi-bin/lib/election.py (original)
+++ steve/trunk/pysteve/www/cgi-bin/lib/election.py Sun Mar 22 21:48:53 2015
@@ -32,6 +32,16 @@ def getIssue(electionID, issueID):
issuedata['APIURL'] = "https://%s/steve/voter/view/%s/%s" %
(config.get("general", "rooturl"), electionID, issueID)
issuedata['prettyURL'] = "https://%s/steve/ballot?%s/%s" %
(config.get("general", "rooturl"), electionID, issueID)
return issuedata
+
+def getVotes(electionID, issueID):
+ issuepath = os.path.join(homedir, "issues", electionID, issueID) +
".json.votes"
+ issuedata = {}
+ if os.path.isfile(issuepath):
+ with open(issuepath, "r") as f:
+ data = f.read()
+ f.close()
+ issuedata = json.loads(data)
+ return issuedata
def listIssues(election):
issues = []
@@ -80,4 +90,110 @@ def deleteIssue(electionID, issueID):
os.unlink(issuepath + ".votes")
return True
else:
- raise Exception("No such election")
\ No newline at end of file
+ raise Exception("No such election")
+
+
+debug = []
+
+def getproportion(votes, winners, step, surplus):
+ "Proportionally move votes"
+ prop = {}
+ tvotes = 0
+ for key in votes:
+ vote = votes[key]
+ xstep = step
+ char = vote[xstep]
+ # Step through votes till we find a non-winner vote
+ while (xstep < len(vote) and vote[xstep] in winners):
+ xstep += 1
+ if xstep >= step:
+ tvotes += 1
+ # We found it? Good, let's add that to the tally
+ if not vote[xstep] in winners:
+ char = vote[xstep]
+ prop[char] = (prop[char] if char in prop else 0) + 1
+
+ # If this isn't the initial 1st place tally, do the proportional math:
+ # surplus votes / votes with an Nth preference * number of votes in that
preference for the candidate
+ if step > 0:
+ for c in prop:
+ prop[c] = surplus / tvotes * prop[c]
+
+ debug.append("Proportional move: %s" % json.dumps(prop))
+ return prop
+
+
+def stv(candidates, votes, numseats):
+ "Calculate N winners using STV"
+
+ # Set up letters for mangling
+ letters = [chr(i) for i in range(ord('a'),ord('a') + len(candidates))]
+ cc = "".join(letters)
+
+ # Keep score of votes
+ points = {}
+
+ # Set all scores to 0 at first
+ for c in cc:
+ points[c] = 0
+
+ # keep score of winners
+ winners = []
+ turn = 0
+
+ # Find quota to win a seat
+ quota = ( len(votes) / (numseats +1) ) + 1
+ debug.append("Votes required to win a seat: %u" % quota)
+
+ # While we still have seats to fill
+ if not len(candidates) < numseats:
+ while len(winners) < numseats and len(cc) > 0 and turn < 1000: #Don't
run for > 1000 iterations, that's a bug
+ turn += 1
+
+ s = 0
+ y = 0
+ # Get votes
+ xpoints = getproportion(votes, winners, y, 0)
+ for x in xpoints:
+ points[x] += xpoints[x]
+ mq = 0
+
+ # For each candidate letter, find if someone won a seat
+ for c in cc:
+ if len(winners) >= numseats:
+ break
+ if points[c] >= quota and not c in winners:
+ debug.append("WINNER: %s got elected in with %u votes! %u
seats remain" % (c, points[c], numseats - len(winners)))
+ winners.append(c)
+ cc.replace(c, "")
+ mq += 1
+ #break
+
+ # If we found no winners in this round, eliminate the lowest
scorer and retally
+ if mq < 1:
+ lowest = 99999999
+ lowestC = None
+ for c in cc:
+ if points[c] < lowest:
+ lowest = points[c]
+ lowestC = c
+
+ debug.append("DRAW: %s is eliminated" % lowestC)
+ if lowestC:
+ cc.replace(lowestC, "")
+ else:
+ debug.append("No more canididates?? buggo?")
+ break
+
+ # Everyone's a winner!!
+ else:
+ winners = letters
+
+ # Compile list of winner names
+ winnernames = []
+ for c in winners:
+ i = ord(c) - ord('a')
+ winnernames.append(candidates[i]['name'])
+
+ # Return the data
+ return winners, winnernames, debug
\ No newline at end of file