3 # Does STV according to
4 # http://www.rosenstiel.co.uk/stvrules/av/index.htm
19 our $places = shift @ARGV;
20 die unless $places eq ($places + 0);
24 m/^(\w+) ([A-Z]+)$/ or die "$_ ?";
29 Prefs => [ split //, $prefs ],
31 push @allvotes, $vote;
36 return sprintf "%10.6f=%-10s", $f, $f;
41 push @{ $vote->{Log} }, "stage $stage: $m";
45 my ($cand, $why) = @_;
46 foreach my $vote (@allvotes) {
47 my $oldprefs = $vote->{Prefs};
48 my @prefs = grep { $_ ne $cand } $oldprefs;
49 next if @prefs == @$oldprefs;
50 votelog $vote, "crossed out candidate $cand: $why";
58 # $sorted{firstpref}{Votes} = [ $vote, ... ]
59 # $sorted{firstpref}{Total} = [ $vote, ... ]
60 for my $vote (@allvotes) {
61 next unless @{ $vote->{Prefs} };
62 my $firstpref = $vote->{Prefs}[0];
63 push @{ $sorted{$firstpref}{Votes} }, $vote;
65 foreach my $firstpref (sort keys %sorted) {
66 foreach my $vote (@{ $sorted{$firstpref}{Votes} }) {
67 votelog $vote, "counted $vote->{Weight} for $firstpref";
68 $sorted{$firstpref}{Total} += $vote->{Weight};
72 $sorted{$b}{Total} <=> $sorted{$a}{Total};
76 foreach my $firstpref (@sorted) {
77 $sorted{$firstpref}{Total} += $_->{Weight}
78 foreach @{ $sorted{$firstpref}{Votes} };
79 printf "%10s %s\n", $firstpref, pr $sorted{$firstpref}{Total};
80 $totalvalid += $sorted{$firstpref}{Total};
82 printf "%10s %s\n", 'TOTAL', pr $totalvalid;
84 last unless $totalvalid > 0;
86 my $quota = $totalvalid / ($places + 1);
87 printf "\nquota = %10s\n", pr $quota;
89 my $topfirst = $sorted[0];
90 my $topvoters = $sorted{$topfirst}{Weight};
91 my $surplus = $topvoters - $quota;
93 printf "%10s ELECTED\n", $sorted[0];
95 # transfer the surplus
96 my $weightmult = $surplus / $topvoters;
97 foreach my $vote (@{ $sorted{$topfirst}{Votes} }) {
98 votelog $vote, "part of surplus of weight $weightmult";
99 $vote->{Weight} *= $weightmult;
101 filterout $topfirst, "candidate was elected";
103 my $elim = $sorted{ $#sorted };
104 printf "%10s eliminated\n", $elim;
105 filterout $elim, "candidate was eliminated";