I am trying to write a competition pairing algorithm to avoid playing the same player twice
so we have a list of players
we take the first player, then the first player they have not played
remove that from the list
send the remaining list to be processed again
if the last pair cant play, the recursion should unroll and the first player get matched against the next player they have not played, and away we go again .
What seems to be happening is that the original list (players) is changing size along with the truncated list that is sent out through the recursive call.
So when the reucrsion unwinds, the list players is down to 2 items rather than the expected 4 or 6. It is like the list is being passed by reference rather than by value.
any thoughts?
edit***
not so much the list being passed by reference, but the list (players) being changed each time the procedure is called, so we end up with the first iteration of the procedure (which should have a list of 6 players) using a list of 2 players when the recursion unwinds ***
Ive shoved the whole code in here (along with the test list set up code)
using System;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
namespace CPair
{
class Program
{
static void Main(string[] args)
{
//create players
List<int> alist = new List<int>() { 2 };
var a = new Player(1, "a", "wk", alist, 10);
List<int> blist = new List<int>() { 1 };
var b = new Player(2, "b", "wa", blist, 9);
List<int> clist = new List<int>() { };
var c = new Player(3, "c", "bc", clist, 8);
List<int> dlist = new List<int>() { };
var d = new Player(4, "d", "wk", dlist, 7);
List<int> elist = new List<int>() { };
var e = new Player(5, "e", "bc", elist, 5);
List<int> flist = new List<int>() { };
var f = new Player(6, "f", "ab", flist, 3);
List<Player> PlayList = new List<Player>();
PlayList.Add(a);
PlayList.Add(b);
PlayList.Add(c);
PlayList.Add(d);
PlayList.Add(e);
PlayList.Add(f);
PlayList.Sort((p, q) => p.Points.CompareTo(q.Points));
foreach (Player p in PlayList)
{
Console.WriteLine(p.PlayerName);
}
List<Player> paired = new List<Player>();
paired = pairing(PlayList);
foreach (Player r in paired)
{
Console.WriteLine(r.PlayerName);
}
}
static List<Player> pairing(List<Player> players)
{
List<Player> pairingList = new List<Player>();
int n = 1;
bool failed = true;
List<Player> returnedList = new List<Player>();
while ((failed) && n <= players.Count - 1)
{
if (PairIsGood(players[0], players[n], 0))
{
Player p1 = new Player();
p1 = players[0];
Player p2 = new Player();
p2 = players[n];
if (players.Count <= 2)
{
returnedList.Add(p1);
returnedList.Add(p2);
failed = false;
}
else
{
List<Player> nextPairs = new List<Player>();
nextPairs = players;
nextPairs.RemoveAt(0);
nextPairs.RemoveAt(n-1);
returnedList = pairing(nextPairs);
Console.WriteLine(players.Count.ToString());
Console.WriteLine(nextPairs.Count.ToString());
if (returnedList.Count == 0)
{
failed = true;
n++;
}
else
{
returnedList.Add(p1);
returnedList.Add(p2);
failed = false;
}
}
}
else
{
n++;
}
}
return returnedList;
}
static bool PairIsGood(Player p1, Player p2, int round)
{
bool good = true;
foreach (int op in p1.OpList)
{
if (op == p2.PlayerID)
{
good = false;
}
}
return good;
}
}
}
Here is your problem:
List<Player> nextPairs = new List<Player>();
nextPairs = players;
nextPairs.RemoveAt(0);
nextPairs.RemoveAt(n-1);
You create a new List<Player>
and assign it to nextPairs
You then effectively throw that new list away, and instead assign nextPairs
to players
.
nextPairs
and players
are now both referencing the same list, and removing from nextPairs
will remove from players
too, since they're the same list.
Take a look at Array.Copy()
if you want a true independent copy.
As an aside, I see you are doing the same redundant creation pattern here:
Player p1 = new Player();
p1 = players[0];
Player p2 = new Player();
p2 = players[n];
This should simply be
Player p1 = players[0];
Player p2 = players[n];
I suspect you need to read up a bit on objects and references and how they work.