<?php
$rowlength = 40;
// --------------------------------------------------------------------
// Step 0: Grab the category details from the database.
// Nothing special here: each category in this case is a position.
$sql = "SELECT * FROM Categories WHERE id=".$category;
$result = mysql_query($sql);
$row = mysql_fetch_array($result, MYSQL_ASSOC);
$output .= "<h2>".$row['name']."</h2>";
// Step 1: Grab the nominees
$sql = "SELECT * FROM Nominees WHERE category=".$category;
$numberOfNominees = 0;
$result = mysql_query($sql);
if ($result && mysql_num_rows($result) > 0)
{
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
$nomineeID[$numberOfNominees] = $row['id'];
$nomineeDescription[$numberOfNominees] = $row['description'];
$nomineePrecluded[$numberOfNominees] = 0;
$numberOfNominees++;
}
}
$output .= "<ol>";
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
$output .= "<li>".$nomineeDescription[$nominee]."</li>";
}
$output .= "</ol>";
// Step 2: Let's load all the votes into an array.
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
$sql = "SELECT * FROM Votes, Voters WHERE voterid = Voters.id AND approved = 1 AND nomineeid = ".$nomineeID[$nominee];
$result = mysql_query($sql);
if ($result && mysql_num_rows($result) > 0)
{
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
{
$vote[$row['voterid']][$row['nomineeid']] = $row['vote'];
}
}
}
// ------------------------------------------------------------------------------------
// Ok. It is possible that we need to preclude nominees from the election results.
// This code drops them from the election.
$finalNominees = 0;
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if ($_REQUEST[$nomineeID[$nominee]."_checked"] == "on")
{
$vote = removeNominee($vote,$nomineeID[$nominee]);
$output .= "<li>".$nomineeDescription[$nominee]." has been removed from the election.</li>";
$nomineePrecluded[$nominee] = 1;
}
else
{
$finalNominees++;
}
}
$round = 0;
$finished = false;
// ------------------------------------------------------------------------------------
// Calculate the required quota.
$output .= "<h3>Calculating Quota</h3>\n";
$output .= "<p>Total non-precluded nominees: ".$finalNominees."</p>\n";
$positions = stripslashes($_REQUEST['positions']);
$output .= "<p>Positions available: ".$positions."</p>\n";
// Check for valid votes
$validVotes = 0;
foreach ($vote as $voterID => $votes)
{
if (checkValidity($votes,1) == "valid") $validVotes++;
$voterWeight[$voterID] = 1;
}
$output .= "<p>Valid votes: ".$validVotes."</p>\n";
if ($validVotes > 0 && $positions > 0 && $finalNominees > 0)
{
$output .= "<p>Quota: Quota = (valid votes / (positions + 1)) + 1 (Droop’s Quota)<br />\n";
$output .= "Quota: Quota = (".$validVotes." / (".$positions." + 1)) + 1<br />\n";
$quota = ceil(($validVotes / ($positions + 1)) + 1);
$output .= "Quota: ".$quota."</p>\n";
// ------------------------------------------------------------------------------------
$output .= "<h3>Calculating Result</h3>\n";
while (!$finished)
{
if (++$roundCount > 50) ($finished = 1);
$output .= "<h3>Round ".($round + 1)."</h3>\n";
// Step 3: We need to confirm that the votes are good.
// This checks for bad votes.
foreach ($vote as $voterID => $votes)
{
$vote[$voterID]['Valid'] = checkValidity($votes,1);
}
$votercount = 0;
$tablecount = 0;
$tables = "";
// I need to list the voter IDs so that they can be checked. This displays them,
// and also initialises the tables I'll need for display - I want to show all the results,
// but don't want to do a next/previous thing as it want it possible to print everything,
// so this breaks them up into separate tables based on a preset number of voters per table.
$tables[$tablecount] .= "<tr bgcolor=\"#cccccc\">\n";
$tables[$tablecount] .= "<td><br /></td>\n";
foreach ($vote as $voterID => $votes)
{
if (($votercount > 0) && (($votercount % $rowlength) == 0))
{
$tables[$tablecount] .= "</tr>\n";
$tablecount++;
$tables[$tablecount] .= "<tr><td colspan=\"".($rowlength + 1)."\"><br /></td></tr><tr bgcolor=\"#cccccc\">\n";
$tables[$tablecount] .= "<td><br /></td>\n";
}
$tables[$tablecount] .= "<td>".$voterID."</td>\n";
$votercount++;
}
$tables[$tablecount] .= "</tr>\n";
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
$tablecount = -1;
$votercount = 0;
$nomineeCount[$nominee][$round] = 0;
foreach ($vote as $voterID => $votes)
{
if ((($votercount % $rowlength) == 0))
{
$tables[$tablecount] .= "</tr>\n";
$tablecount++;
$tables[$tablecount] .= "<tr>\n<td bgcolor=\"#cccccc\">".($nominee + 1)."</td>\n";
}
$colour = "#ffffff";
if ($votes[$nomineeID[$nominee]] == 1 && $vote[$voterID]['Valid'] == "valid")
{
$colour = "#33ff66";
$nomineeCount[$nominee][$round] += 1 * $voterWeight[$voterID];
if ($voterWeight[$voterID] != 1)
{
$colour = "#ffff00";
}
}
if ($vote[$voterID]['Valid'] == "invalid")
{
$colour = "#ff9900";
}
$tables[$tablecount] .= "<td bgcolor=\"".$colour."\">".$votes[$nomineeID[$nominee]]."</td>\n";
$votercount++;
}
$tables[$tablecount] .= "</tr>\n";
}
$output .= '<table cellpadding="2" cellspacing="0" border="1">'."\n";
for ($table = 0; $table <= $tablecount; $table++)
{
$output .= $tables[$table];
}
$output .= "</table>\n";
//Step : Work out if we have a winner.
$biggest = 0;
$noscoreCount = 0;
$biggestCount = 0;
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if($nomineeCount[$nominee][$round] > $biggest)
{
$biggest = $nomineeCount[$nominee][$round];
$biggestCount = 1;
}
else if ($nomineeCount[$nominee][$round] == $biggest)
{
$biggestCount++;
}
if ($nomineeCount[$nominee][$round] == 0)
{
$noscoreCount++;
}
}
$lowest = $biggest;
$lowestCount = 0;
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if ($nomineePrecluded[$nominee])
{
// Used for debugging to confirm that a nominee is now precluded
}
else if($nomineeCount[$nominee][$round] < $lowest)
{
$lowest = $nomineeCount[$nominee][$round];
$lowestCount = 1;
}
else if ($nomineeCount[$nominee][$round] == $lowest)
{
$lowestCount++;
}
}
$output .= '<br \><table cellpadding="2" cellspacing="0" border="1">'."\n<tr>\n<td><br /></td>\n";
$round++;
for ($roundnumber = 0; $roundnumber < $round; $roundnumber++)
{
$output .= "<td bgcolor=\"#cccccc\">Round ".($roundnumber + 1)."</td>\n";
}
$output .= "</tr>\n";
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
$output .= "<tr><td bgcolor=\"#cccccc\">".$nomineeDescription[$nominee]."</td>\n";
for ($roundnumber = 0; $roundnumber < $round; $roundnumber++)
{
$output .= "<td";
if ($roundnumber == $round - 1)
{
if ($nomineePrecluded[$nominee])
{
$output .= " bgcolor=\"#ff0000\"";
}
else
{
if ($nomineeCount[$nominee][$roundnumber] == $biggest) { $output .= " bgcolor=\"#33ff66\""; }
if ($nomineeCount[$nominee][$roundnumber] == $lowest) { $output .= " bgcolor=\"#ff9900\""; }
}
}
$output .= ">".$nomineeCount[$nominee][$roundnumber]."</td>\n";
}
$output .= "</tr>\n";
}
$output .= "</table>\n";
//Step : Report on the end of the first round.
$output .= "<p>At the end of Round ".$round.", ";
// See if anyone passed the quota
if ($biggest >= $quota)
{
$output .= "there is a winner.</p>";
$output .="<h3>Winner</h3>\n";
$output .= "<ul>";
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if ($nomineeCount[$nominee][$round-1] >= $quota)
{
$output .= "<li>".$nomineeDescription[$nominee]."</li>\n";
// Increase the winners count
$winners++;
// Have we enough winners to stop now?
if ($winners == $positions)
{
$finished = true;
}
else
{
$nomineeWon[$nominee] = 1;
$voteWeight = ($nomineeCount[$nominee][$round-1] - $quota) / $nomineeCount[$nominee][$round-1];
foreach ($vote as $voterID => $votes)
{
if ($vote[$voterID]['Valid'] == "valid" AND $votes[$nomineeID[$nominee]] == 1)
{
$voterWeight[$voterID] = $voteWeight;
}
}
$vote = removeNominee($vote, $nomineeID[$nominee]);
$nomineePrecluded[$nominee] = 1;
}
}
}
$output .= "</ul>\n";
$output .= "<p>As there are still positions to fill, preferences for successful voters have been reallocated.</p>";
}
/*
else if ($biggestCount + $noscoreCount == $numberOfNominees)
{
if ($biggestCount == 1) { $output .= "there is a winner.</p>"; }
if ($biggestCount > 1) { $output .= "there are ".$biggestCount." winners.</p>"; }
$output .="<h3>Winner</h3>\n";
$output .= "<ul>";
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if ($nomineeCount[$nominee][$round-1] == $biggest)
{
$output .= "<li>".$nomineeDescription[$nominee]."</li>\n";
}
}
$output .= "</ul>\n";
$finished = true;
}
*/
else
{
$output .= " there is no clear winner.</p>";
if ($lowestCount >= 1)
{
$lowestID = -1;
$target = 0; // By default, we are going to remove the only nominee to get the lowest score.
$targetCount = 0;
if ($lowestCount > 1)
{
$output .= "<p>As there were ".$lowestCount." nominees with the lowest score, one will randomly be removed.<p>";
$target = rand(0,$lowestCount-1);
}
for ($nominee = 0; $nominee < $numberOfNominees; $nominee++)
{
if ($nomineeCount[$nominee][$round-1] == $lowest && !$nomineePrecluded[$nominee])
{
if ($targetCount == $target)
{
$lowestID = $nominee;
}
$targetCount++;
}
}
$output .= "<p>Removing votes for ".$nomineeDescription[$lowestID].".</p>";
$nomineePrecluded[$lowestID] = 1; // Removes them from the count.
$output .= "<p>Reset the weighting, as a candidate has been excluded.</p>";
foreach ($vote as $voterID => $votes)
{
if (checkValidity($votes,1) == "valid") $validVotes++;
$voterWeight[$voterID] = 1;
}
// Code to remove votes.
foreach ($vote as $voterID => $votes)
{
if ($vote[$voterID]['Valid'] == "invalid")
{
unset($vote[$voterID]);
}
else
{
$found = false;
$target = $votes[$nomineeID[$lowestID]];
if ($target > 0)
{
$vote[$voterID][$nomineeID[$lowestID]] = 0;
foreach($votes as $voteNomineeID => $voteScore)
{
if ($vote[$voterID][$voteNomineeID] >= $target)
{
$vote[$voterID][$voteNomineeID]--;
}
if ($vote[$voterID][$voteNomineeID] <= 0)
{
unset($vote[$voterID][$voteNomineeID]);
}
}
}
}
}
$output .= "<h4>Calculating new quota</h4>\n";
$output .= "<p>Positions remaining: ".($positions - $winners)."</p>\n";
// Check for valid votes
$validVotes = 0;
foreach ($vote as $voterID => $votes)
{
if (checkValidity($votes,1) == "valid") $validVotes++;
}
$output .= "<p>Valid votes: ".$validVotes."</p>\n";
if ($validVotes > 0 && $positions > 0)
{
$output .= "<p>Quota: Quota = (valid votes / (positions + 1)) + 1 (Droop’s Quota)<br />\n";
$output .= "Quota: Quota = (".$validVotes." / (".($positions - $winners)." + 1)) + 1<br />\n";
$quota = ceil(($validVotes / (($positions - $winners) + 1)) + 1);
$output .= "Quota: ".$quota."</p>\n";
}
}
}
}
}
// --------------------------------------------------------------------------------------
function removeNominee($vote, $nominee)
{
// Code to remove votes.
foreach ($vote as $voterID => $votes)
{
if ($vote[$voterID]['Valid'] == "invalid")
{
unset($vote[$voterID]);
}
else
{
$found = false;
$target = $votes[$nominee];
if ($target > 0)
{
$vote[$voterID][$nominee] = 0;
foreach($votes as $voteNomineeID => $voteScore)
{
if ($vote[$voterID][$voteNomineeID] >= $target)
{
$vote[$voterID][$voteNomineeID]--;
}
if ($vote[$voterID][$voteNomineeID] <= 0)
{
unset($vote[$voterID][$voteNomineeID]);
}
}
}
}
}
return $vote;
}
// --------------------------------------------------------------------------------------
function checkValidity($votes, $value)
{
$validvotes = 0;
foreach ($votes as $key => $vote)
{
if ($vote == $value)
{
++$validvotes;
}
}
$result = "invalid";
if ($validvotes == 1)
{
$result = "valid";
}
return $result;
}
?>