Play with Election, Candidate & Vote objects
Condorcet PHP allow you to get some abstractions. All you inputs are objects : The Candidates and Votes object. An election is also an Election object.
You can get multiples Election, sharing fully ou partially the same Candidate and Votes object. Update one of them have repercussion on all elections. Voting may also be incomplete, and thus participate in the elections with an alternative candidate list.
Create Elections and Manage Candidates
php
<?php
use CondorcetPHP\Condorcet\Election;
use CondorcetPHP\Condorcet\Candidate;
// Create Election
$myElection1 = new Election;
$myElection2 = new Election;
// Manage Candidate
// Add candidates
// A string
$myElection1->addCandidate('A');
// An objet
$myElection1->addCandidate( new Candidate ('Koechlin') );
$myElection1->addCandidate( new Candidate ('Caplet') );
$myElection1->addCandidate( new Candidate ('Debussy') );
$myElection1->addCandidate( new Candidate ('Olivier Messiaen') );
$myElection1->addCandidate( new Candidate ('Ligeti') );
// Automatic name
$myAutomaticCandidate = $myElection1->addCandidate();
$myAutomaticCandidate->name; // 'C'
// Follow this one
$myLutoCandidate = new Candidate('Lutoslawski');
$myElection1->addCandidate($myLutoCandidate);
// Change your mind?
$myElection1->removeCandidates('A');
$myElection1->removeCandidates($myAutomaticCandidate);
// Lutoslawski change his name
$myLutoCandidate->setName('Wiltod Lutoslawski'); # Done !
// What was his old names?
$myLutoCandidate->nameHistory; // return the full history with timestamp of this Candidate naming
// Check your candidate list, if you forget it
$myElection1->getCandidatesList(); // Return an array pupulate by each Candidate objet
$myElection1->getCandidatesList(true); // Return an array pupulate by each Candidate name as String.
// OK, I need my Debussy (want his candidate object)
$myDebussyCandidate = $myElection1->getCandidateObjectFromName('Debussy');
Add Votes
php
<?php
use CondorcetPHP\Condorcet\Vote;
require 'play_with_candidates.php';
$VoteModel = [
$myDebussyCandidate,
'Caplet',
['Olivier Messiaen', 'Ligeti'],
'Koechlin'
]; // Messiaen & Ligeti are at equallity. $myLutoCandidate is not here, but it will be automatically detect in $myElection1 objet a add at the last rank.
for ($i = 0 ; $i < 95 ; $i++) {
shuffle($VoteModel);
$myElection1->addVote( $VoteModel );
}
// How Many Vote could I Have now ?
$myElection1->countVotes(); // Return 95 (int)
// More fun way to add Vote from full string input !
$myVote96 = $myElection1->addVote('Debussy > Olivier Messiaen = Ligeti > Wiltod Lutoslawski');
//Add some tags
$myVote97 = $myElection1->addVote( [$myDebussyCandidate, 'Koechlin'],
['greatFrenchVote','strangeVote'] // You can also pu your tags for this vote
);
// Parse multiple Votes
$myElection1->parseVotes("
tag1,frenchies,tag3 || Olivier Messiaen > Debussy = Caplet > Ligeti # Tags at first, vote at second, separated by '||'
Ligeti > Caplet # Line break to start a new vote. Tags are optionals.
strangeVote,tag3 || Debussy=Koechlin= Ligeti = Wiltod Lutoslawski = Olivier Messiaen>Caplet * 11 # This vote and his tag will be register 11 times
");
// Creating self Vote object
$myVote111 = new Vote ( [$myDebussyCandidate, $myLutoCandidate, 'Caplet'], 'customeVoteTag,AnAnotherTag' );
$myVote112 = new Vote ( 'Olivier Messiaen = Caplet > Wiltod Lutoslawski', ['customVoteTag','AnAnotherTag'] );
$myElection1->addVote($myVote111);
$myElection1->addVote($myVote112);
Manage Votes
php
<?php
require 'play_with_candidates.php';
$myElection1->parseVotes('strangeVote || Koechlin > Debussy * 12');
$myElection1->getVotesList(); // Returns an array of all votes as object.
// How many Vote with tag "strangeVote" ?
expect($myElection1->countVotes('strangeVote'))->toBe(12);
// Return the 12 votes !
$myElection1->getVotesList('strangeVote');
// Or without this tags and get the first of them
$voteWithoutTag = $myElection1->addVote('Caplet = Ligeti');
$votesListWithoutStrangeTag = $myElection1->getVotesList('strangeVote', false);
$oneVoteToDelete = reset($votesListWithoutStrangeTag);
expect($voteWithoutTag === $oneVoteToDelete)->toBe(true);
// Vote objet
$oneVote = $myElection1->getVotesList('strangeVote')[0]; // Return the current ranking
$oneVote->getRanking(); // Return the current ranking
$oneVote->getRanking(context: $myElection1); // Return the full ranking in the context of election 1 (with 6 candidates)
// Change the vote
$oneVote->setRanking([
$myLutoCandidate,
$myDebussyCandidate,
$myElection1->getCandidateObjectFromName('Caplet'),
$myElection1->getCandidateObjectFromName('Ligeti')]
);
// Note that when a Vote object is linked to one or more elections, you can can only change his ranking by passing Candidate object.
// Check the vote history
$oneVote->rankingHistory; // Return the full history of this vote ranking
// Delete Votes
// Delete a specific vote object
$myElection1->removeVote($oneVoteToDelete);
// Delete all vote with tag "strangeVote" or "frenchies"
$myElection1->removeVotesByTags( ['strangeVote','frenchies'] );
// Delete all vote without tag 'Wagnerian'
# $myElection1->removeVotesByTags( ['strangeVote','frenchies'], false ); // Here, if uncomment, all the vote will be deleted.
Get Results
php
use CondorcetPHP\Condorcet\Utils\CondorcetUtil;
$electionWithVotes->getWinner(); // Return NULL if there is not, else return the winner candidate object
$electionWithVotes->getWinner('Schulze'); // Same thing, but try to resolve by Schulze method if there is not one. Can return an array of winners if there are multiple.
// Natural Condorcet Loser
$electionWithVotes->getLoser(); // Return NULL if there is not, else return the winner candidate object
// Advanced Method
$electionWithVotes->getResult(); // Result set for defaut method (Should be Schulze Winning)
$electionWithVotes->getResult('Copeland'); // Do it with the Copeland method
// Get an easy game outcome to read and understand (Table populated by string)
$easyResult = CondorcetUtil::format($electionWithVotes->getResult());
Advanced Condorcet Objects
php
<?php
use CondorcetPHP\Condorcet\Election;
use CondorcetPHP\Condorcet\Vote;
// Create a second election
$election1 = new Election;
$election2 = new Election;
// Create four candidates
$election1->parseCandidates('Debussy;Caplet;Messiaen;Lutoslawski');
$lutoCandidate = $election1->getCandidateObjectFromName('Lutoslawski');
$debussyCandidate = $election1->getCandidateObjectFromName('Debussy');
// Add two participating candidates from $myElection1
$election2->addCandidate($lutoCandidate);
$election2->addCandidate($debussyCandidate);
// And, I can change again theirs name. The new name is now applied in the two elections and their votes. If namesake in another election, an exception is throw.
$lutoCandidate->setName('W.Lutoslawski');
// Have a look on $myLutoCandidate history
$lutoCandidate->nameHistory;
// In what elections, this candidates have a part ?
$lutoCandidate->getLinks(); // Get Condorcet objects
expect($lutoCandidate->getLinks())->toBe([$election1, $election2]);
// The same vote applied to multiple elections.
$myNewVote = new Vote([$lutoCandidate, 'Debussy', 'Messiaen']);
// Add it on election 1 and 2
$election1->addVote($myNewVote); // Note that Vote has been altered. 'Debussy' string become a reference to $myElection1->getCandidateObjectFromName('Debussy'); Cause there are namesake and there was not any conflict.
$election2->addVote($myNewVote);
// In what election, this candidates have a part ?
$myNewVote->getLinks(); // Get Condorcet objects
expect($myNewVote->getLinks())->toBe([$election1, $election2]);
// Get the vote ranking in context of each elections
$contextualRankingInElection1 = $myNewVote->getRankingAsString(context: $election1);
$contextualRankingInElection2 = $myNewVote->getRankingAsString(context: $election2);
expect($contextualRankingInElection1)->toBe('W.Lutoslawski > Debussy > Messiaen > Caplet');
expect($contextualRankingInElection2)->toBe('W.Lutoslawski > Debussy');
// Now we can change vote ranking
$myNewVote->setRanking([$election1->getCandidateObjectFromName('Debussy'),$lutoCandidate]); // If these votes are already engaged in the election, you must use compatible Candidate objects with all relevant elections. Else, get a nice exception.
// Get Ranking history
$myNewVote->rankingHistory; // Get the full history of this vote ranking