Hi!

Here is the new (and as far as I am concerned now, ready) version of my
little voting program.
It is designed to be used in a village meeting where there is only one
computer, and too much people to cast votes one by one.
In the rows of the "vote" tab you give the candidates, and the number of
voters who prefer the candidate above the one corresponding to the column.
You click on the result tab and see the result.
On the config tab you can configure the number of candidates and the font
size for the other two tabs.

On some places it talks Hungarian, but you will understand it :)

It depends on python, and its gtk and pango package.

Copyright GNU GPL, any comments or criticism are welcome.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright [email protected] GNU GPL
import pygtk
pygtk.require('2.0')
import gtk
import pango

class Configuration:
    def __init__(self):
        self.rownum=5
        self.fontsize=20
        self.fd=pango.FontDescription("Sans %d"%self.fontsize)

class MainWin:
    def delete_event(self,widget,event,data=None):
        return False

    def destroy(self,widget,data=None):
        gtk.main_quit()

    def __init__(self,children):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
        self.window.set_border_width(10)

        self.notebook = gtk.Notebook()
        self.window.add(self.notebook)
        self.notebook.show()
        self.window.show()
        self.children=children
        for w,n in children:
            self.add(w.widget,n)

    def main(self):
        gtk.main()

    def add(self,widget,name):
        self.notebook.add(widget)
        self.notebook.set_tab_label_text(widget,name)
        widget.show()
    
class Config:
    def __init__(self,config=None):
        self.config=config
        self.widget=gtk.Table(rows=3,columns=2)
        label=gtk.Label("# of candidates")
        self.widget.attach(label,0,1,0,1)
        self.rownumentry=gtk.Entry()
        self.rownumentry.insert_text('5')
        self.widget.attach(self.rownumentry,1,2,0,1)
        label2=gtk.Label("Font size")
        self.widget.attach(label2,0,1,1,2)
        self.fontsizentry=gtk.Entry()
        self.fontsizentry.insert_text('20')
        self.widget.attach(self.fontsizentry,1,2,1,2)
        self.button=gtk.Button("Legyen")
        self.button.connect('clicked',self.configure,None)
        self.widget.attach(self.button,2,3,0,2)
        label.show()
        label2.show()
        self.rownumentry.show()
        self.fontsizentry.show()
        self.button.show()

    def configure(self,widget,data=None):
        ns=self.rownumentry.get_chars(0,-1)
        if ns == '':
            ns = '0'
        n=int(ns)
        print ns,n
        self.config.rownum=n
        ns=self.fontsizentry.get_chars(0,-1)
        if ns == '':
            ns = '0'
        n=int(ns)
        print ns,n
        self.config.fontsize=n
        self.config.fd=pango.FontDescription("Sans %d"%n)

class Entries:
    def __init__(self, config=None):
        self.config=config
        self.widget=gtk.Table(rows=self.config.rownum,columns=self.config.rownum+1)
        self.widget.connect('map',self.configure,None)
        self.populate()
        self.widget.show()

    def populate(self,fr=0):
        fd=self.config.fd
        for e in self.widget.get_children():
            e.destroy()
        self.children=[]
        for i in range(fr,self.config.rownum):
            cs=[]
            e=gtk.Entry()
            e.modify_font(fd)
            cs.append(e)
            e.set_property("width-chars",30)
            e.show()
            self.widget.attach(e,0,1,i,i+1)
            for j in range(fr,self.config.rownum):
                if i == j:
                    e=gtk.Label(' - ')
                else:
                    e=gtk.Entry()
                    e.set_property("width-chars",3)
                cs.append(e)
                e.modify_font(fd)
                e.show()
                self.widget.attach(e,1+j,2+j,i,i+1,xoptions=0)
            self.children.append(cs)
    def harvest(self):
        l=[]
        for i in self.children:
            ll=[]
            for j in i:
                if j.__class__ == gtk.Label:
                    ll.append("0")
                else:
                    ll.append(j.get_chars(0,-1))
            l.append(ll)
        return l
    def configure(self,widget=None,data=None):
        l=self.harvest()
        self.widget.resize(rows=self.config.rownum,columns=self.config.rownum+1)
        self.populate()
        x=0
        for i in l[:self.config.rownum]:
            y=0
            for j in i[:self.config.rownum+1]:
                k=self.children[x][y]
                if k.__class__ != gtk.Label:
                    k.insert_text(j)
                y += 1
            x += 1

class Result:
    def __init__(self,entries,config=None):
        self.config=config
        self.widget=gtk.Label("ide jon\n az eredmeny")
        self.widget.connect('map',self.compute,None)
        self.entries=entries

    def printmat(self,m):
        l=[]
        for i in range(len(self.candidates)):
            ll=[]
            for j in range(len(self.candidates)):
                if i == j:
                    ll.append('-')
                else:
                    ll.append('%s'%m[i,j])
            l.append(','.join(ll))
        print '\n'.join(l)

    def compute_old(self,widget,data=None):
        self.widget.set_text('computing result')
        self.getdata()
        self.floyd_warshall()
        print self.candidates
        self.printmat(self.d)
        self.printmat(self.p)
        C = len(self.candidates)
        winners=[]
        hasnew = True
        while hasnew:
            hasnew = False
            for i in range(C):
                if i not in winners:
                    isnew = True
                    for j in range(C):
                        if j not in winners:
                            if i != j:
                                if self.p[i,j] < self.p[j,i]:
                                    isnew = False
                    if isnew:
                        winners.append(i)
                        hasnew = True
        print winners
        s=""
        for i in range(len(winners)):
            s += self.candidates[winners[i]]
            if i > 0:
                s += ",by %s:%s"%(self.p[winners[i],winners[i-1]],self.p[winners[i-1],winners[i]])
            s += "\n"
        print s
        self.widget.set_text(s)

    def getdata(self):
        l=self.entries.harvest()
        candidates=[]
        d={}
        x=0
        for line in l:
            candidates.append(line[0])
            y=0
            for pr in line[1:]:
                if pr == '':
                    pr = '0'
                d[x,y]=int(pr)
                y+=1
            x+=1
        self.candidates=candidates
        self.d=d

    def floyd_warshall(self):
        candidates=self.candidates
        C=len(candidates)
        d=self.d
        p={}
        for i in range(C):
            for j in range(C):
                if i != j:
                    if d[i,j] > d[j,i]:
                        p[i,j] = d[i,j]
                    else:
                        p[i,j] = 0
        for i in range(C):
            for j in range(C):
                if i != j:
                    for k in range(C):
                        if i != k:
                            if j != k:
                                p[j,k] = max(p[j,k],min(p[j,i],p[i,k]))
        self.p = p

    def winners(self,ignore):
        n=len(self.candidates)
        winner=[]
        for i in range(n):
            if not ignore.has_key(i):
                won = True
                for j in range(n):
                    if not (ignore.has_key(j) or (i == j)):
                        if self.p[i,j] < self.p[j,i]:
                            won = False
                            break
                if won:
                    winner.append(i)
        return winner

    def rank_candidates(self):
        n=len(self.candidates)
        ignore={}
        num_ranked=0
        result=[]
        while (num_ranked < n):
            winner_list=self.winners(ignore)
            result.append(winner_list)
            for j in winner_list:
                ignore[j] = 1
                num_ranked += 1
        return result

    def _losenum(self,i,j):
        s=" %s: %d "%(self.candidates[j],self.p[j,i])
        #print i,j,s
        return s
    def loosedata(self,ranking,now,n):
        l = []
        if n > 0:
            l +=ranking[n-1]
        if n > 1:
            l +=ranking[n-2]
        s=''
        print l
        for c in l:
            if c != now:
                s += self._losenum(now,c)
        return s
    def compute(self,widget,data=None):
        fd=self.config.fd
        self.widget.modify_font(fd)
        self.widget.set_text('computing result')
        self.getdata()
        self.floyd_warshall()
        print self.candidates
        self.printmat(self.d)
        self.printmat(self.p)
        ranking=self.rank_candidates()
        print ranking
        s="Sorrend:\n"
        n=0
        for r in ranking:
            s += " %d. hely:"%(n+1)
            if len(r) > 1:
                s += "  holtverseny:\n"
            for i in r:
                s+= "    %s (%s)\n"%(self.candidates[i],self.loosedata(ranking,i,n))
            n+=1
        print s        
        self.widget.set_text(s)


                    
def main(go=False):
    conf=Configuration()
    e=Entries(config=conf)
    c=Config(config=conf)
    r=Result(e,config=conf)
    mainwin = MainWin([(c,'config'),(r,"result"),(e,'vote')])
    if go:
        mainwin.main()


if __name__ == "__main__":
    main(True)

----
Election-Methods mailing list - see http://electorama.com/em for list info

Reply via email to