I've updated my voting system to allow preferential voting (the previous method uses approval voting). It gives a score to each candidate based on its rank. E.g. if there are 10 candidates, and you give a candidate 1st preference, it gets 10 points, second preference gets 9 points, etc.
It's therefore functionally equivalent to "range voting".
<?php
/* How to use:
Put all emails in an array with values in $emails["text"] and $emails["user_id"];
Put the list of valid candidates in the function valid_candidate();
Put the check for user-authorisation in function valid_user();
Enjoy.
*/$emails_array = array(
array("user_id"=>234, "text"=>"
option1 = 1
option3 = 2
optionwhatever = 3
"),
// Duplicate user, will be handled correctly.
array("user_id"=>234, "text"=>"
Oops forgot one I like:
Optionfour = 2
// Did I mention:
option1=1
"
),
array("user_id"=>1234,
"text"=>"
// I hate option1
Option1 = 6
option2 = 1
")
);function valid_user($user_id){return true;} // put user filter in here if necessary
function valid_candidate($name){ return true;} // is the name one of the candidates?$number_of_options = 6;
// Process all emails
foreach ($emails_array as $email)
{// Is it a valid registered user?
if (valid_user($email["user_id"]))
{// Process each line of the email
$email_lines = explode("\n", trim($email["text"]));
foreach ($email_lines as $this_line)
{
// Does it have an '=' sign and only one = sign
$equals_sign = strpos($this_line, "=");
if ($equals_sign !== false)
{
$cleaned_up_line_text = trim($this_line, ";.!\t\n\r\0");
$parts_of_line = explode("=", $cleaned_up_line_text);
if (count($parts_of_line) == 2)
{
// Is it a valid candidate and rank?
// Candidate is in lower case.
$candidate = strtolower(trim($parts_of_line[0]));
$rank = intval(trim($parts_of_line[1]));
if (valid_candidate($candidate) && ($rank > 0) && ($rank <= $number_of_options))
{
// Get the score for this candidate.
// The score is the number of options - how far it is ranked below 1.
// e.g. a rank of 1 would give it a score of $number_of_options.
// a rank of 2 gives it a score of $number_of_options -1.
// See "range voting".
$score = $number_of_options - ($rank-1);// Make sure this vote for this user hasn't already been cast
if (!isset($user_votes[$email["user_id"]]) ||
!isset($user_votes[$email["user_id"]][$candidate]))
{
// Remember this user has voted for this name already.
$user_votes[$email["user_id"]][$candidate] = true;// Count the vote towards the total
if (!isset($candidate_votes[$candidate]))
$candidate_votes[$candidate]=$score;
else $candidate_votes[$candidate]+= $score;
}
} // end of check for valid vote values.
} // of check for correctly formatted vote
} // of check for equals sign
} // End of for loop for lines of email
} // of check for valid user.
} // end of for loop for all emails.print "votes:<br>";
print_r($user_votes);
print "<br><Br>";
print "candiate_votes<Br>";
print_r($candidate_votes);?>
(Score: 2) by martyb on Thursday March 27 2014, @11:06AM
First off, let me say: "Nicely done!" Although I know your intention was to support voting via e-mail, I suspect that the code could be re-purposed to process results from an updated poll-booth source. Maybe replace the term "e-mail" with "ballot"?
It's been quite a while since I coded perl, so please bear with me.
It seems to me that a user could vote multiple choices at the same preference level...
Case 0:
1 foo
2 bar
3 bazz
Case 1:
3 foo
1 bar
2 bazz
Case 2:
1 foo
2 bar
2 bazz
Case 3:
1 foo
3 bar
3 bazz
Case 4:
1 foo
1 bar
1 bazz
Case 5:
3 foo
3 bar
3 bazz
Case 6:
3 foo
7 bar
7 bazz
7 buzz
7 fizz
7 fizz-buzz
7 bizz-fuzz
Cases (0) and (1) are what I'd consider "normal" cases.
Case (2) suggests a clear preference for one candidate, and an ambivalence about two others. Okay, I can understand that.
Case (3) is just like case (2), but the ambivalent choice is lower-weighted... Hrmmm!? I can, kind of, understand that.
Case (4) is just as ambivalent as case (5), but if I read things correctly, case (4) gives every candidate max points, but case (5) gives no points to any candidate?
Case (6) is, admittedly, pathological. But, do we process it? Give an error?
Questions:
And, of course, I'm assuming there are no write-in candidates. Right?
So, in general, it looks really good!