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);
23 m/^(\w+) ([A-Z]+)$/ or die;
28 Prefs => (split //, $prefs),
30 push @allvotes, $vote;
35 return sprintf "%10.6f=%-10s", $f, $f;
40 push @{ $vote->{Log} }, "stage $stage: $m";
44 my ($cand, $why) = @_;
45 foreach my $vote (@allvotes) {
46 my $oldprefs = $vote->{Prefs};
47 my @prefs = grep { $_ ne $cand } $oldprefs;
48 next if @prefs == @$oldprefs;
49 votelog $vote, "crossed out candidate $cand: $why";
57 # $sorted{firstpref}{Votes} = [ $vote, ... ]
58 # $sorted{firstpref}{Total} = [ $vote, ... ]
59 for my $vote (@allvotes) {
60 next unless @{ $vote->{Prefs} };
61 my $firstpref = $vote->{Prefs}[0];
62 push @{ $sorted{$firstpref}{Votes} }, $vote;
64 foreach my $firstpref (sort keys %sorted) {
65 foreach my $vote (@{ $sorted{$firstpref}{Votes} }) {
66 votelog $vote, "counted $vote->{Weight] for $firstpref";
67 $sorted{$firstpref}{Total} += $vote->{Weight};
71 $sorted{$b}{Total} <=> $sorted{$a}{Total};
75 foreach my $firstpref (@sorted) {
76 $sorted{$firstpref}{Total} += $_->{Weight}
77 foreach @{ $sorted{$firstpref}{Votes} };
78 printf "%10s %s\n", $firstpref, pr $sorted{$firstpref}{Total};
79 $totalvalid += $sorted{$firstpref}{Total};
81 printf "%10s %s\n", 'TOTAL', pr $totalvalid;
83 last unless $totalvalid > 0;
85 my $quota = $totalvalid / ($places + 1);
86 printf "\nquota = %10s\n", pr $quota;
88 my $topfirst = $sorted[0];
89 my $topvoters = $sorted{ }{Weight};
90 my $surplus = $topvoters - $quota;
92 printf "%10s ELECTED\n", $sorted[0];
94 # transfer the surplus
95 my $weightmult = $surplus / $topvoters;
96 foreach my $vote (@{ $sorted{$topfirst}{Votes} }) {
97 votelog $vote, "part of surplus of weight $weightmult";
98 $vote->{Weight} *= $weightmult;
100 filterout $topfirst, "candidate was elected";
102 my $elim = $sorted{ $#sorted };
103 printf "%10s eliminated\n", $elim;
104 filterout $elim, "candidate was eliminated";