Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Ok, a new answer having re-examined the issue. The algorithm, I think, should be thus:</p> <ul> <li>Iterate over unallocated players (noting that this list reduces 2 at a time).</li> <li>Find the school with the most available remaining players which is not the school the current iteration of player is in.</li> <li>If the above check does not find a school with any players, resort to using the same school as the current iteration of player is in. This has the effect that players in the same school can play eachother if no other players remain in the allocation pool.</li> <li>Allocate an arbitrary player from the school we just found</li> <li>Pair the currently iterated player and the arbitrary player</li> <li>Remove both players from the pool</li> </ul> <p>Implementation-wise, I found it easier to maintain 2 indexes - one of schools and 1 of players. I bundled it into a couple of classes because the inherently referential nature of objects makes life easier. My code is below... it works out of the box but may need some tweaking.</p> <pre><code>&lt;?php class School { protected $name; protected $players = []; public function __construct($name) { $this-&gt;name = $name; } public function get_name() { return $this-&gt;name; } public function add_player($name) { $this-&gt;players[] = $name; } public function del_player($name) { if (($index = array_search($name, $this-&gt;players)) !== false) { unset($this-&gt;players[$index]); } } public function player_count() { return count($this-&gt;players); } public function get_player() { if (!reset($this-&gt;players)) { return false; } return [ 'school' =&gt; $this-&gt;name, 'name' =&gt; reset($this-&gt;players), ]; } } class Players { protected $schools_index = []; protected $player_index = []; public function add_player($school, $player) { // Create school if not exists if (!isset($this-&gt;schools_index[$school])) { $this-&gt;schools_index[$school] = new School($school); } // Add player to school and own index $this-&gt;schools_index[$school]-&gt;add_player($player); $this-&gt;player_index[$player] = $school; } public function del_player($school, $player) { // From school index $this-&gt;schools_index[$school]-&gt;del_player($player); // From own index if (isset($this-&gt;player_index[$player])) { unset($this-&gt;player_index[$player]); } } public function biggest_school($exclude = null) { $rtn = null; // Find school excluding the exclude. Don't get schools with nobody left in them. foreach ($this-&gt;schools_index as $name=&gt;$school) { if ((!$exclude || $name != $exclude) &amp;&amp; ($school-&gt;player_count()) &amp;&amp; (!$rtn || $rtn-&gt;player_count() &lt; $school-&gt;player_count())) { $rtn = $school; } } // If we didn't get a school, shitcan the exclude and try the excluded school if (!$rtn &amp;&amp; $exclude) { if ($this-&gt;schools_index[$exclude]-&gt;player_count()) { $rtn = $this-&gt;schools_index[$exclude]; } } return $rtn; } public function get_player() { if (!reset($this-&gt;player_index)) { return false; } return [ 'school' =&gt; reset($this-&gt;player_index), 'name' =&gt; key($this-&gt;player_index), ]; } public static function from_players_arr(array $players) { $obj = new static(); foreach ($players as $player) { // Add to indexes $obj-&gt;add_player($player['school'], $player['name']); } return $obj; } } $players = array( array('name' =&gt; 'juan', 'school' =&gt; 'ABC'), array('name' =&gt; 'leo', 'school' =&gt; 'ABC'), array('name' =&gt; 'arnold', 'school' =&gt; 'ABC'), array('name' =&gt; 'simon', 'school' =&gt; 'ABC'), array('name' =&gt; 'luke', 'school' =&gt; 'ABC'), array('name' =&gt; 'alan', 'school' =&gt; 'JKL'), array('name' =&gt; 'jeff', 'school' =&gt; 'BAR'), array('name' =&gt; 'paul', 'school' =&gt; 'FOO'), ); $players_obj = Players::from_players_arr($players); $pairs = []; while ($player = $players_obj-&gt;get_player()) { $players_obj-&gt;del_player($player['school'], $player['name']); $opponent = $players_obj-&gt;biggest_school($player['school'])-&gt;get_player(); $pairs[] = [ $player['name'], $opponent['name'], ]; $players_obj-&gt;del_player($opponent['school'], $opponent['name']); } var_dump($pairs); </code></pre> <p>Output is below:</p> <pre><code>array(4) { [0] =&gt; array(2) { [0] =&gt; string(4) "juan" [1] =&gt; string(4) "alan" } [1] =&gt; array(2) { [0] =&gt; string(3) "leo" [1] =&gt; string(4) "jeff" } [2] =&gt; array(2) { [0] =&gt; string(6) "arnold" [1] =&gt; string(4) "paul" } [3] =&gt; array(2) { [0] =&gt; string(5) "simon" [1] =&gt; string(4) "luke" } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload