Subversion Repositories Local Hare Voting

Rev

Rev 75 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#!/usr/bin/env python

import optparse
import cgi
import string
import sys

import parseinput
import tally

fHTML = 1
formaction = string.split(sys.argv[0],"/")[-1]

def emitPreHTML(formaction):
    emitHTML("""Content-type: text/html\n
<html>
<body>
<title>Hare Ballot Calculation</title>
    <h1>Hare Ballot Calculation</h1>
    <form enctype="multipart/form-data" method=POST action=%s>
        <table>
        <tr><td>CSV file of ballots:
                <td><input type=file size=70 name=name>
        </table>
        <p>
        <input type=submit name="run1" value="Run 1 Time">
        <!-- <input type=submit name="run500" value="Run 500 Times"> -->
        <input type=submit name="runparallel" value="Run All Ways">
    </form>
    <p>
Input is a CSV/spreadsheet file with the number of winners to be
selected in the first cell.  On subsequent lines, the first column contains the names of the candidates (no blanks), with each additional column representing a ballot.  Details are given 
<a href="http://www.bikmort.com/dokuwiki/hare_voting_procedure">here</a>.
Little error checking is done, so be sure to review the trace output.
The source code is available <a href="%s?fetch=yes">here</a>.
<p>
<small>%s</small>
<hr>
<pre>
""" % (formaction, formaction, "$Id: vote.py 77 2016-04-24 13:50:12Z jtkorb $"))
    return

def emitPostHTML():
    emitHTML("""</pre>
</body>
</html>
""")
    return

def emitHTML(s):
    global fHTML
    if fHTML: print s
    return

def doone(nWinners, ballots):
    tally.traceLevel = 1
    tally.fParallel = 0
    results = tally.dotally(nWinners, ballots)

def domany(nTimes, nWinners, ballots):
    tally.traceLevel = 0
    tally.fParallel = 0
    summary = {}
    for i in range(nTimes):
        results = str(tally.dotally(nWinners, ballots))
        if not summary.has_key(results):
            summary[results] = 0
        summary[results] = summary[results] + 1
    tally.trace(0, "\nSUMMARY AFTER %d TIMES" % nTimes)
    l = summary.items()
    l.sort(lambda x,y: cmp(y[1], x[1]))
    for pair in l:
        tally.trace(0, "%3d %s" % (pair[1], pair[0]))

def doparallel(nWinners, ballots):
    tally.traceLevel = 0
    tally.fParallel = 1
    results = tally.dotally(nWinners, ballots)

def doweb():
    emitPreHTML(formaction)
    form = cgi.FieldStorage()

    if not form:
        emitHTML("Enter file name and press a button to see results.")
    elif form.has_key("fetch"):
        filename = string.replace(formaction, "vote.py", "tally.py")
        source = open(filename).read()
        print cgi.escape(source)
    elif not form.has_key("name"):
        emitHTML("Error: no file received")
    elif not form["name"].filename:
        emitHTML("Error: file name missing")
    else:
        name = form["name"].filename
        contents = form["name"].value

        tally.trace(0, "INPUT FILE")
        tally.trace(0, contents)

        nWinners, ballots = parseinput.parsestring(contents)
        if form.has_key("run1"):
            doone(nWinners, ballots)
        elif form.has_key("run1000"):
            domany(1000, nWinners, ballots)
        elif form.has_key("runparallel"):
            doparallel(nWinners, ballots)
        else:
            print "UNEXPECTED SUBMIT BUTTON: %s" % form
                
    emitPostHTML()
    return

def main():
    usage = "usage: %prog [options] filename.csv"
    parser = optparse.OptionParser(usage)
    parser.add_option("-m", "--multiple", dest="multi", action="store_true",
                      help="run process multiple (1000) times")
    parser.add_option("-p", "--parallel", dest="para", action="store_true",
                      help="run process in parallel universes")
    (options, args) = parser.parse_args()

    if len(args) == 0:
        doweb()
    else:
        nWinners, ballots = parseinput.parsefile(args[0])
        if options.multi:
            domany(1000, nWinners, ballots)
        elif options.para:
            doparallel(nWinners, ballots)
        else:
            doone(nWinners, ballots)

if __name__=='__main__':
    main()