private EliminationNode MakeSiblings(EliminationNode nodeA, EliminationNode nodeB)
        {
            var oldParent = nodeA.PrimaryParent as ContinuationDecider;

            var newDecider = new ContinuationDecider(nodeA, nodeB);
            var newNode    = new WinnerNode(newDecider);

            newDecider.PrimaryParent = newNode;
            nodeA.PrimaryParent      = nodeB.PrimaryParent = newDecider;

            newNode.PrimaryParent = oldParent;
            if (oldParent != null)
            {
                if (oldParent.ChildA == nodeA)
                {
                    oldParent.ChildA = newNode;
                }
                else if (oldParent.ChildB == nodeA)
                {
                    oldParent.ChildB = newNode;
                }
            }

            return(newNode);
        }
        private EliminationNode MakeSiblings(EliminationNode nodeA, EliminationNode nodeB)
        {
            var oldParent = nodeA.PrimaryParent as ContinuationDecider;

            var newDecider = new ContinuationDecider(nodeA, nodeB);
            var newNode = new WinnerNode(newDecider);
            newDecider.PrimaryParent = newNode;
            nodeA.PrimaryParent = nodeB.PrimaryParent = newDecider;

            newNode.PrimaryParent = oldParent;
            if (oldParent != null)
            {
                if (oldParent.ChildA == nodeA)
                {
                    oldParent.ChildA = newNode;
                }
                else if (oldParent.ChildB == nodeA)
                {
                    oldParent.ChildB = newNode;
                }
            }

            return newNode;
        }
        private EliminationNode BuildTree(IEnumerable<TournamentTeam> teams)
        {
            List<EliminationNode> nodes = new List<EliminationNode>();

            if (teams.Count() >= 2)
            {
                int ranking = 0;
                var teamsOrder = from team in teams
                                 orderby team.Rating.HasValue ? team.Rating : 0 descending
                                 select new TeamRanking
                                 {
                                     Team = team,
                                     Ranking = ranking++,
                                 };

                int i = 0;
                int nextRoundAt = 2;
                int roundNumber = 0;
                int mask = (1 << roundNumber) - 1;
                var teamRankings = teamsOrder.ToList();
                foreach (var teamRanking in teamRankings)
                {
                    if (i == nextRoundAt)
                    {
                        nextRoundAt *= 2;
                        roundNumber += 1;
                        mask = (1 << roundNumber) - 1;
                    }

                    var newDecider = new TeamDecider(teamRanking.Team);
                    var newNode = new WinnerNode(newDecider);
                    newDecider.PrimaryParent = newNode;

                    if (nodes.Count > 0)
                    {
                        var match = (from n in nodes
                                     let d = n.Decider as TeamDecider
                                     where d != null
                                     where (teamRankings.Where(tr => tr.Team == n.Team).Single().Ranking & mask) == (teamRanking.Ranking & mask)
                                     select n).Single();

                        nodes.Add(MakeSiblings(match, newNode));
                    }

                    nodes.Add(newNode);
                    i++;
                }

                // Add in byes to even out the left side of the bracket.
                for (ranking = teamRankings.Count; ranking < nextRoundAt; ranking++)
                {
                    var match = (from n in nodes
                                 let d = n.Decider as TeamDecider
                                 where d != null
                                 where (teamRankings.Where(tr => tr.Team == n.Team).Single().Ranking & mask) == (ranking & mask)
                                 select n).Single();

                    var newDecider = new ByeDecider();
                    var newNode = new WinnerNode(newDecider);
                    newDecider.PrimaryParent = newNode;

                    nodes.Add(newNode);
                    nodes.Add(MakeSiblings(match, newNode));
                }
            }

            var rootNode = (from n in nodes
                            where n.Level == 0
                            select n).SingleOrDefault();

            if (eliminations == 1 || rootNode == null)
            {
                return rootNode;
            }

            var maxLevel = nodes.Max(n => n.Level) - 1;

            var deciders = rootNode.FindDeciders(d => d.Level == maxLevel);
            var loserNodes = BuildLoserNodes(deciders);

            while (true)
            {
                maxLevel--;
                deciders = rootNode.FindDeciders(d => d.Level == maxLevel);

                if (deciders.Count() == 0)
                {
                    break;
                }

                var newLosers = BuildLoserNodes(deciders);

                while (loserNodes.Count() > newLosers.Count())
                {
                    loserNodes = SimplifyNodes(loserNodes);
                }

                loserNodes = InterleaveNodes(newLosers, loserNodes);
            }

            while (loserNodes.Count > 1)
            {
                loserNodes = SimplifyNodes(loserNodes);
            }

            var loserRoot = loserNodes[0];

            var winnersDecider = new ContinuationDecider(rootNode, loserRoot);
            var winnersWinner = new WinnerNode(winnersDecider);
            winnersDecider.PrimaryParent = winnersWinner;

            var passthrough = new PassThroughDecider(rootNode);
            var replay = new WinnerNode(passthrough);
            passthrough.PrimaryParent = replay;

            var stayDecider = new StayDecider(winnersWinner, replay);
            var finalWinner = new WinnerNode(stayDecider);
            stayDecider.PrimaryParent = finalWinner;

            return finalWinner;
        }
        private EliminationNode BuildTree(IEnumerable <User> teams)
        {
            List <EliminationNode> nodes = new List <EliminationNode>();

            if (teams.Count() >= 2)
            {
                int ranking    = 0;
                var teamsOrder = from team in teams
                                 orderby team.BotScore.HasValue ? team.BotScore : 0 descending
                                 select new TeamRanking
                {
                    Team    = team,
                    Ranking = ranking++,
                };

                int i            = 0;
                int nextRoundAt  = 2;
                int roundNumber  = 0;
                int mask         = (1 << roundNumber) - 1;
                var teamRankings = teamsOrder.ToList();
                foreach (var teamRanking in teamRankings)
                {
                    if (i == nextRoundAt)
                    {
                        nextRoundAt *= 2;
                        roundNumber += 1;
                        mask         = (1 << roundNumber) - 1;
                    }

                    var newDecider = new TeamDecider(teamRanking.Team);
                    var newNode    = new WinnerNode(newDecider);
                    newDecider.PrimaryParent = newNode;

                    if (nodes.Count > 0)
                    {
                        var match = (from n in nodes
                                     let d = n.Decider as TeamDecider
                                             where d != null
                                             where (teamRankings.Where(tr => tr.Team == n.Team).Single().Ranking & mask) == (teamRanking.Ranking & mask)
                                             select n).Single();

                        nodes.Add(MakeSiblings(match, newNode));
                    }

                    nodes.Add(newNode);
                    i++;
                }

                // Add in byes to even out the left side of the bracket.
                for (ranking = teamRankings.Count; ranking < nextRoundAt; ranking++)
                {
                    var match = (from n in nodes
                                 let d = n.Decider as TeamDecider
                                         where d != null
                                         where (teamRankings.Where(tr => tr.Team == n.Team).Single().Ranking & mask) == (ranking & mask)
                                         select n).Single();

                    var newDecider = new ByeDecider();
                    var newNode    = new WinnerNode(newDecider);
                    newDecider.PrimaryParent = newNode;

                    nodes.Add(newNode);
                    nodes.Add(MakeSiblings(match, newNode));
                }
            }

            var rootNode = (from n in nodes
                            where n.Level == 0
                            select n).SingleOrDefault();

            if (eliminations == 1 || rootNode == null)
            {
                return(rootNode);
            }

            var maxLevel = nodes.Max(n => n.Level) - 1;

            var deciders   = rootNode.FindDeciders(d => d.Level == maxLevel);
            var loserNodes = BuildLoserNodes(deciders);

            while (true)
            {
                maxLevel--;
                deciders = rootNode.FindDeciders(d => d.Level == maxLevel);

                if (deciders.Count() == 0)
                {
                    break;
                }

                var newLosers = BuildLoserNodes(deciders);

                while (loserNodes.Count() > newLosers.Count())
                {
                    loserNodes = SimplifyNodes(loserNodes);
                }

                loserNodes = InterleaveNodes(newLosers, loserNodes);
            }

            while (loserNodes.Count > 1)
            {
                loserNodes = SimplifyNodes(loserNodes);
            }

            var loserRoot = loserNodes[0];

            var winnersDecider = new ContinuationDecider(rootNode, loserRoot);
            var winnersWinner  = new WinnerNode(winnersDecider);

            winnersDecider.PrimaryParent = winnersWinner;

            var passthrough = new PassThroughDecider(rootNode);
            var replay      = new WinnerNode(passthrough);

            passthrough.PrimaryParent = replay;

            var stayDecider = new StayDecider(winnersWinner, replay);
            var finalWinner = new WinnerNode(stayDecider);

            stayDecider.PrimaryParent = finalWinner;

            return(finalWinner);
        }