Guest User

Swiss competition using PHP

a guest
Jul 15th, 2014
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.60 KB | None | 0 0
  1. <?php
  2.  
  3. /*
  4.  * Bart Brinkman <[email protected]> wrote this code. As long as you
  5.  * retain this notice you can do whatever you want with this stuff. If we meet
  6.  * some day, and you think this stuff is worth it, you can buy me a beer in return.
  7.  */
  8.  
  9. class Player
  10. {
  11.     public $name;
  12.     public $results = array();
  13.    
  14.     public function __construct($name)
  15.     {
  16.         $this->name = $name;
  17.     }
  18.    
  19.     public function getPoints()
  20.     {
  21.         $points = 0;
  22.         foreach($this->results as $result) {
  23.             $points += $result->points;
  24.         }
  25.         return $points;
  26.     }
  27.    
  28.     public function getPointsUntilRound($roundNumber)
  29.     {
  30.         $points = 0;
  31.         for ($i = 0; $i < $roundNumber; $i ++) {
  32.             if (isset($this->results[$i])) {
  33.                 $points += $this->results[$i]->points;
  34.             }
  35.         }
  36.         return $points;
  37.     }
  38.    
  39.     public function hasBye()
  40.     {
  41.         foreach($this->results as $result) {
  42.             if (is_a($result, 'Bye')) return true;
  43.         }
  44.         return false;
  45.     }
  46.    
  47.     public function hasPlayedAgainst(Player $player) {
  48.         foreach($this->results as $result) {
  49.             if ($result->against === $player) return true;
  50.         }
  51.         return false;
  52.     }
  53. }
  54.  
  55. class Competition
  56. {
  57.     public $players = array();
  58.     public $rounds = array();
  59.    
  60.     public function __construct($players)
  61.     {
  62.         $this->players = $players;
  63.     }
  64.    
  65.     public function getNumberOfRounds()
  66.     {
  67.         return (int) log(count($this->players), 2);
  68.     }
  69. }
  70.  
  71. class Pair
  72. {
  73.     public $player1;
  74.     public $player2;
  75.    
  76.     public function __construct($player1, $player2)
  77.     {
  78.         $this->player1 = $player1;
  79.         $this->player2 = $player2;
  80.     }
  81. }
  82.  
  83. class Round
  84. {
  85.     public $competition;
  86.     public $pairs = array();
  87.    
  88.     public function __construct(Competition $competition)
  89.     {
  90.         $this->competition = $competition;
  91.     }
  92.    
  93.     public function pair($noRulesRandom)
  94.     {
  95.         $players = $this->competition->players;
  96.         if ($noRulesRandom) {
  97.             shuffle($players);
  98.             while (count($players) > 0) {
  99.                 $player1 = array_shift($players);
  100.                 $player2 = array_pop($players);
  101.                 $this->pairs[] = new Pair($player1, $player2);
  102.             }
  103.         }
  104.         else {             
  105.             while (count($players) > 0) {
  106.                
  107.                 // sort players by ranking
  108.                
  109.                 usort($players, function($a, $b) {
  110.                     if ($a->getPoints() == $b->getPoints()) return 0;
  111.                     return ($a->getPoints() > $b->getPoints()) ? -1 : 1;
  112.                 });
  113.                
  114.                 // make sure the last Player (in an odd numbered group) doesn't have a buy (see next section why)
  115.                 // NOTE following section might mess with equally ranked players
  116.                
  117.                 if (count($players) & 1) { // check only of odd number of players
  118.                     $cond = false;
  119.                     while (!$cond) {
  120.                         $lastPlayer = end($players);
  121.                         if ($lastPlayer->hasBye()) {
  122.                             array_unshift($players, array_pop($players)); // move last element to top
  123.                         }
  124.                         else $cond = true;
  125.                     }
  126.                 }
  127.                
  128.                 // pair players and make sure they haven't played against eachother before
  129.                
  130.                 $player1 = array_shift($players);
  131.                 $player2 = array_shift($players); // will return null if array was empty (odd number of elements only)
  132.                 if (is_a($player2, 'Player')) {
  133.                     while ($player1->hasPlayedAgainst($player2)) {
  134.                         $players[] = $player2;
  135.                         $player2 = array_shift($players);
  136.                     }
  137.                 }
  138.                 $this->pairs[] = new Pair($player1, $player2);
  139.             }
  140.         }
  141.     }
  142. }
  143.  
  144. abstract class Result {
  145.     public $points;
  146.     public $against;
  147. }
  148.  
  149. class Win extends Result
  150. {
  151.     public $points = 3;
  152.    
  153.     public function __construct(Player $player) {
  154.         $this->against = $player;
  155.     }
  156. }
  157.  
  158. class Tie extends Result
  159. {
  160.     public $points = 1;
  161.    
  162.     public function __construct(Player $player) {
  163.         $this->against = $player;
  164.     }
  165. }
  166.  
  167. class Loss extends Result
  168. {
  169.     public $points = 0;
  170.    
  171.     public function __construct(Player $player) {
  172.         $this->against = $player;
  173.     }
  174. }
  175.  
  176. class Bye extends Result
  177. {
  178.     public $points = 3;
  179. }
  180.  
  181. // lifecycle simulation starts here, replace with persistent storage or something to that effect
  182.  
  183. class MockCompetition extends Competition
  184. {
  185.     public function run()
  186.     {
  187.         for ($i = 1; $i <= $this->getNumberOfRounds(); $i ++) {
  188.             $round = new MockRound($this);
  189.             $round->pair($i == 1 ? true : false);
  190.             $round->play();
  191.             $this->rounds[] = $round;
  192.         }
  193.     }
  194. }
  195.  
  196. class MockRound extends Round
  197. {
  198.     public function __construct(Competition $competition)
  199.     {
  200.         parent::__construct($competition);
  201.     }
  202.    
  203.     public function play()
  204.     {
  205.         foreach($this->pairs as $pair) {
  206.            
  207.             $player1 = $pair->player1;
  208.             $player2 = $pair->player2;
  209.            
  210.             $decision = rand(1, 3);
  211.            
  212.             if ($player2 == null) $decision = 4;
  213.             if ($player1 == null) $decision = 5; // not sure if needed, trace Round::pair to be sure
  214.            
  215.             switch($decision) {
  216.                 case 1:
  217.                     $player1->results[] = new Win($player2);
  218.                     $player2->results[] = new Loss($player1);
  219.                     break;
  220.                
  221.                 case 2:
  222.                     $player1->results[] = new Loss($player2);
  223.                     $player2->results[] = new Win($player1);
  224.                     break;
  225.                
  226.                 case 3:
  227.                     $player1->results[] = new Tie($player2);
  228.                     $player2->results[] = new Tie($player1);
  229.                     break;
  230.                
  231.                 case 4:
  232.                     $player1->results[] = new Bye;
  233.                     break;
  234.                
  235.                 case 5:
  236.                     $player2->results[] = new Bye;
  237.                     break;
  238.             }
  239.         }
  240.     }
  241. }
  242.  
  243. // start
  244.  
  245. $players = array(
  246.     new Player('Luis'),      //1
  247.     new Player('Ian'),       //2
  248.     new Player('Arman'),     //3
  249.     new Player('Jakob'),     //4
  250.     new Player('Murad'),     //5
  251.     new Player('Samir'),     //6
  252.     new Player('Alexander'), //7
  253.     new Player('Mohamed'),   //8
  254.     new Player('Arthur'),    //9
  255.     new Player('Lars'),      //10
  256.     new Player('Hugo'),      //11
  257.     new Player('Mehdi'),     //12
  258.     new Player('Adjin'),     //13
  259.     new Player('Ayoub'),     //14
  260.     new Player('Louis'),     //15
  261.     //new Player('Mathis'),    //16
  262. );
  263.  
  264. $competition = new MockCompetition($players);
  265. $competition->run();
  266.  
  267. // output results (note that Competition::$rounds and Player::$results array keys match up)
  268.  
  269. foreach($competition->rounds as $roundNumber => $round) {
  270.     echo '<h2>Round ' . ($roundNumber + 1) . '</h2>';
  271.     foreach($round->pairs as $pair) {
  272.         echo '<ul>';
  273.         echo '<li>' . $pair->player1->name . ' (' . $pair->player1->getPointsUntilRound($roundNumber) . ') (<em>' . get_class($pair->player1->results[$roundNumber]) . '</em>)</li>';
  274.         echo $pair->player2 == null ? '' : '<li>' . $pair->player2->name . ' (' . $pair->player2->getPointsUntilRound($roundNumber) . ') (<em>' . get_class($pair->player2->results[$roundNumber]) . '</em>)</li>';
  275.         echo '</ul>';
  276.     }
  277. }
  278.  
  279. usort($players, function($a, $b) {
  280.     if ($a->getPoints() == $b->getPoints()) return 0;
  281.     return ($a->getPoints() > $b->getPoints()) ? -1 : 1;
  282. });
  283.  
  284. echo '<h2>Results</h2>';
  285. foreach($players as $player) {
  286.     echo '<li>' . $player->name . ': ' . $player->getPoints() . '</li>';
  287. }
Advertisement
Add Comment
Please, Sign In to add comment