How to Generate a Round Robin Tournament in PHP and MySQL

Expanding Round-robin tournament 1v1 to a 1v1v1v1

Your foreach() with the selection of the other 3 teams is wrong. One of them have to make steps with a multiple of 4. If you don't, you will select the teams at the beginning more than one and don't select the teams at the end of the array at all. This will result in wrong team matchups like this (teams are letters here):

abcd
bcde
cdef
defg

And then your break; hits.

Instead it should look something like this:

for ($i=0; $i<4; $i++) {
$matchup = array();
for ($j=0; $j<4; $j++) {
$matchup[] = $teams[4*$i+$j];
}
$schedule[$round][] = $matchup ;
}

This way you get the following pairing (again, using letters as teams):

abcd
efgh
ijkl
mnop

This algorithm will split the team list in four groups:

abcd|efgh|ijkl|mnop

Keep in mind that depending on the shuffling of the $teams array for the next round you might get the same opponent twice.

adei|klnf|gjmc|pobh

Here the teams ad, kl and op will face again.

Simple algorithm to create round robin league in PHP

Here is a generic algorithm, that works for all numbers of teams.
It is a standard algorithm that follows the explanations described in the wikipedia article

$teams = array('A', 'B', 'C', 'D') ;
create_round_robin_tournament($teams);

function create_round_robin_tournament($teams)
{
if(count($teams) < 2) throw new Exception("At least 2 teams needed to build tournament");

if( count($teams) % 2 == 1 )
$teams[] = "dummy" ; // if number of teams is even, add a dummy team that means 'this team don't play this round'

for($round = 0 ; $round < count($teams)-1 ; ++$round)
{
echo "=== Round " . ($round+1) . " ===" . PHP_EOL ;
displayRoundPairs($teams);
echo PHP_EOL ;
$teams = rotateCompetitors($teams);
}
}

function displayRoundPairs($teams)
{
for($i = 0 ; $i < count($teams)/2 ; ++$i)
{
$opponent = count($teams) - 1 - $i ;

if($teams[$i] == 'dummy')
echo "Team " . $teams[$opponent] . " don't play this round" . PHP_EOL ;
elseif($teams[$opponent] == 'dummy')
echo "Team " . $teams[$i] . " don't play this round" . PHP_EOL ;
else
echo $teams[$i] . ' - ' . $teams[$opponent] . PHP_EOL ;
}
}

// rotate all competitors but the first one
function rotateCompetitors($teams)
{
$result = $teams ;

$tmp = $result[ count($result) - 1 ] ;
for($i = count($result)-1 ; $i > 1 ; --$i)
{
$result[$i] = $result[$i-1] ;
}
$result[1] = $tmp ;

return $result ;

}

Is there any algorithm to make round robin schedule having each round unique combinations?

Yes, there is rather simple algorithm to generate all possible pairs ((N-1)*N/2)

Put items into two rows.

At every round player from the top row plays with corresponding player from bottom row.

Fix the first one.

Shift all others in cyclic manner.

Note that you can work with indexes of array, not changing it's contents

A  B
D C
pairs A-D, B-C

A D
C B
pairs A-C, D-B

A C
B D
pairs A-B, C-D

My naive implementation in PHP (ideone) outputs indexes of players:

function GenPairs($N) {
for ($i=0; $i<$N-1;$i++){
echo(0).":";
echo($N - 1 - $i)."\n";
for ($j=1; $j<$N/2;$j++){
echo(1 + (($N - $i + $j - 2) % ($N - 1))).":";
echo(1 + ((2*$N - $i - $j - 3) % ($N - 1)))."\n";
}
echo("\n");
}
}

GenPairs(6);

0:5
1:4
2:3

0:4
5:3
1:2

0:3
4:2
5:1

0:2
3:1
4:5

0:1
2:5
3:4

Is there a way in SQL (MySQL) to do a round robin ORDER BY on a particular field?

What you can do is create a temporary column in which you create sets to give you something like this:

+-------+------+-----+
| group | name | tmp |
+-------+------+-----+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+-------+------+-----+

To learn how to create the sets, have a look at this question/answer.

Then its a simple

ORDER BY tmp, group, name

Round Robin Scheduler Filling in byes

if ($conn->query($sql) === TRUE) is not true if you use it for a select statement, see documentation:

Returns FALSE on failure. For successful SELECT, SHOW, DESCRIBE or EXPLAIN queries mysqli_query() will return a mysqli_result object. For other successful queries mysqli_query() will return TRUE.

Since you are doing it twice anyway, you can complete remove this line and just use

$sql = "SELECT * FROM `temp` 
WHERE (Home = '$home' and Away = '$away')
or (Home = '$away' and Away = '$home')";
if ($result=mysqli_query($conn,$sql)) {
...

Alternatively, since you have your full schedule in your variable $round already, you could use this to check for existing matches.

And you can try a different strategy:

For round robin with an uneven number of teams and an even number of days, there will be exactly one day in the future where the subset of teams that have had a bye already will play against a team that had a bye already, and all teams that have had no bye yet will either have a bye that day or play against a team that have had no bye yet.

All you need to do is keep generating the round robin table until you find this day and use the matches of that day.

How can generate rounds of permute

For the sake of completeness (on SO), here is the code posted from another answer (thanks to m69's comment above):

/****************************************************************************** 
* Round Robin Pairing Generator
* Author: Eugene Wee
* Date: 23 May 2005
* Last updated: 13 May 2007
* Based on an algorithm by Tibor Simko.
*
* Copyright (c) 2005, 2007 Eugene Wee
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/

function generateRoundRobinPairings($num_players) {
// Do we have a positive number of players? If not, default to 4.
$num_players = ($num_players > 0) ? (int)$num_players : 4;

// If necessary, round up number of players to nearest even number.
$num_players += $num_players % 2;

// Format for pretty alignment of pairings across rounds.
$format = "%0" . ceil(log10($num_players)) . "d";
$pairing = "$format-$format ";

// Set the return value
$ret = $num_players . " Player Round Robin:\n-----------------------";

// Generate the pairings for each round.
for ($round = 1; $round < $num_players; $round++) {
$ret .= sprintf("\nRound #$format : ", $round);
$players_done = array();

// Pair each player except the last.
for ($player = 1; $player < $num_players; $player++) {
if (!in_array($player, $players_done)) {
// Select opponent.
$opponent = $round - $player;
$opponent += ($opponent < 0) ? $num_players : 1;

// Ensure opponent is not the current player.
if ($opponent != $player) {
// Choose colours.
if (($player + $opponent) % 2 == 0 xor $player < $opponent) {
// Player plays white.
$ret .= sprintf($pairing, $player, $opponent);
} else {
// Player plays black.
$ret .= sprintf($pairing, $opponent, $player);
}

// This pair of players are done for this round.
$players_done[] = $player;
$players_done[] = $opponent;
}
}
}

// Pair the last player.
if ($round % 2 == 0) {
$opponent = ($round + $num_players) / 2;
// Last player plays white.
$ret .= sprintf($pairing, $num_players, $opponent);
} else {
$opponent = ($round + 1) / 2;
// Last player plays black.
$ret .= sprintf($pairing, $opponent, $num_players);
}
}

return $ret;
}


Related Topics



Leave a reply



Submit