Example #1
0
            public BalanceTeam Clone()
            {
                var clone = new BalanceTeam();

                clone.Items  = new List <BalanceItem>(Items);
                clone.AvgElo = AvgElo;
                clone.EloSum = EloSum;
                clone.Count  = Count;
                return(clone);
            }
            public BalanceTeam Clone()
            {
                var clone = new BalanceTeam();

                clone.Items     = new List <BalanceItem>(Items);
                clone.EloAvg    = EloAvg;
                clone.EloVarSum = EloVarSum;
                clone.EloVar    = EloVar;
                clone.Count     = Count;
                clone.EloStdev  = EloStdev;
                return(clone);
            }
Example #3
0
        BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, BattleContext b, params List <Account>[] unmovablePlayers)
        {
            var ret = new BalanceTeamsResult();

            try {
                ret.CanStart = true;
                ret.Players  = b.Players.ToList();

                var db          = new ZkDataContext();
                var nonSpecList = b.Players.Where(y => !y.IsSpectator).Select(y => (int?)y.LobbyID).ToList();
                var accs        =
                    db.Accounts.Where(x => nonSpecList.Contains(x.AccountID)).ToList();
                if (accs.Count < 1)
                {
                    ret.CanStart = false;
                    return(ret);
                }
                if (teamCount < 1)
                {
                    teamCount = 1;
                }
                if (teamCount > accs.Count)
                {
                    teamCount = accs.Count;
                }
                if (teamCount == 1)
                {
                    foreach (var p in ret.Players)
                    {
                        p.AllyID = 0;
                    }
                    return(ret);
                }

                maxTeamSize = (int)Math.Ceiling(accs.Count / (double)teamCount);

                teams.Clear();
                for (var i = 0; i < teamCount; i++)
                {
                    var team = new BalanceTeam();
                    teams.Add(team);
                    if (unmovablePlayers != null && unmovablePlayers.Length > i)
                    {
                        var unmovables = unmovablePlayers[i];
                        team.AddItem(new BalanceItem(unmovablePlayers[i].ToArray())
                        {
                            CanBeMoved = false
                        });
                        accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID));
                    }
                }

                balanceItems = new List <BalanceItem>();
                if (mode == BalanceMode.ClanWise)
                {
                    var clanGroups = accs.GroupBy(x => x.ClanID ?? x.AccountID).ToList();
                    if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize))
                    {
                        mode = BalanceMode.Normal;
                    }
                    else
                    {
                        balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(x.ToArray())));
                    }
                }
                if (mode == BalanceMode.FactionWise)
                {
                    balanceItems.Clear();
                    var factionGroups = accs.GroupBy(x => x.FactionID ?? x.AccountID).ToList();
                    balanceItems.AddRange(factionGroups.Select(x => new BalanceItem(x.ToArray())));
                }

                if (mode == BalanceMode.Normal)
                {
                    balanceItems.Clear();
                    balanceItems.AddRange(accs.Select(x => new BalanceItem(x)));
                }

                var sw = new Stopwatch();
                sw.Start();
                RecursiveBalance(0);
                sw.Stop();

                if (bestTeams == null)
                {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return(fallback);
                }

                var minSize    = bestTeams.Min(x => x.Count);
                var maxSize    = bestTeams.Max(x => x.Count);
                var sizesWrong = maxSize / (double)minSize > MaxTeamSizeDifferenceRatio;

                // cbalance failed, rebalance using normal
                if (mode == BalanceMode.ClanWise && (bestTeams == null || GetTeamsDifference(bestTeams) > MaxCbalanceDifference || sizesWrong))
                {
                    return(new Balancer().LegacyBalance(teamCount, BalanceMode.Normal, b, unmovablePlayers));
                }
                // cbalance failed, rebalance using normal

                if (sizesWrong && mode == BalanceMode.FactionWise)
                {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return(fallback); // fallback standard balance if PW balance fails

                    /*ret.CanStart = false;
                     * ret.Message = string.Format("Failed to balance - too many people from same faction");
                     * return ret;*/
                }

                if (unmovablePlayers != null && unmovablePlayers.Length > 0)
                {
                    var minElo = bestTeams.Min(x => x.AvgElo);
                    var maxElo = bestTeams.Max(x => x.AvgElo);
                    if (maxElo - minElo > GlobalConst.MaxPwEloDifference)
                    {
                        var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                        fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                        return(fallback); // fallback standard balance if PW balance fails

                        /*
                         * ret.CanStart = false;
                         * ret.Message = string.Format("Team difference is too big - win chance {0}% - spectate some or wait for more people",
                         *                          Utils.GetWinChancePercent(maxElo - minElo));
                         * return ret;*/
                    }
                }

                if (bestTeams == null)
                {
                    ret.CanStart = false;
                    ret.Message  =
                        string.Format(
                            "Failed to balance {0} - too many people from same clan or faction (in teams game you can try !random and !forcestart)");
                    return(ret);
                }
                else
                {
                    if (unmovablePlayers == null || unmovablePlayers.Length == 0)
                    {
                        bestTeams = bestTeams.Shuffle();                                                           // permute when not unmovable players present
                    }
                    var text = "( ";

                    var lastTeamElo = 0.0;
                    var allyNum     = 0;
                    foreach (var team in bestTeams)
                    {
                        if (allyNum > 0)
                        {
                            text += " : ";
                        }
                        text += string.Format("{0}", (allyNum + 1));
                        if (allyNum > 0)
                        {
                            text += string.Format("={0}%)", Utils.GetWinChancePercent(lastTeamElo - team.AvgElo));
                        }
                        lastTeamElo = team.AvgElo;

                        foreach (var u in team.Items.SelectMany(x => x.LobbyId))
                        {
                            ret.Players.Single(x => x.LobbyID == u).AllyID = allyNum;
                        }
                        allyNum++;
                    }
                    text += ")";

                    ret.Message = String.Format("{0} players balanced {2} to {1} teams {3}. {4} combinations checked, spent {5}ms of CPU time",
                                                bestTeams.Sum(x => x.Count),
                                                teamCount,
                                                mode,
                                                text,
                                                iterationsChecked,
                                                sw.ElapsedMilliseconds);
                }
            } catch (Exception ex) {
                Trace.TraceError(ex.ToString());
                ret.Message  = ex.ToString();
                ret.CanStart = false;
            }
            return(ret);
        }
        /// <summary>
        ///     The function that actually moves players arounds
        /// </summary>
        /// <param name="teamCount"></param>
        /// <param name="mode"></param>
        /// <param name="b"></param>
        /// <param name="unmovablePlayers"></param>
        /// <returns></returns>
        BalanceTeamsResult LegacyBalance(int teamCount, BalanceMode mode, LobbyHostingContext b, params List<Account>[] unmovablePlayers)
        {
            var ret = new BalanceTeamsResult();

            if (b.IsMatchMakerGame) mode = BalanceMode.Party; // override, for matchmaker mode is always party
            
            try
            {
                ret.CanStart = true;
                ret.Players = b.Players.ToList();

                var db = new ZkDataContext();
                var nonSpecList = b.Players.Where(y => !y.IsSpectator).Select(y => (int?)y.LobbyID).ToList();
                var accs = db.Accounts.Where(x => nonSpecList.Contains(x.AccountID)).ToList();
                if (accs.Count < 1)
                {
                    ret.CanStart = false;
                    return ret;
                }
                if (teamCount < 1) teamCount = 1;
                if (teamCount > accs.Count) teamCount = accs.Count;
                if (teamCount == 1)
                {
                    foreach (var p in ret.Players) p.AllyID = 0;
                    return ret;
                }

                maxTeamSize = (int)Math.Ceiling(accs.Count / (double)teamCount);

                teams.Clear();
                for (var i = 0; i < teamCount; i++)
                {
                    var team = new BalanceTeam();
                    teams.Add(team);
                    if (unmovablePlayers != null && unmovablePlayers.Length > i)
                    {
                        var unmovables = unmovablePlayers[i];
                        team.AddItem(new BalanceItem(b.IsMatchMakerGame, unmovablePlayers[i].ToArray()) { CanBeMoved = false });
                        accs.RemoveAll(x => unmovables.Any(y => y.AccountID == x.AccountID));
                    }
                }

                balanceItems = new List<BalanceItem>();
                if (mode == BalanceMode.Party)
                {
                    var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? x.AccountID).ToList();
                    if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) mode = BalanceMode.Normal;
                    else balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray())));
                }

                if (mode == BalanceMode.ClanWise)
                {
                    var clanGroups = accs.GroupBy(x => b.Players.First(p => p.Name == x.Name).PartyID ?? x.ClanID ?? x.AccountID).ToList();
                    if (teamCount > clanGroups.Count() || clanGroups.Any(x => x.Count() > maxTeamSize)) mode = BalanceMode.Normal;
                    else balanceItems.AddRange(clanGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray())));
                }
                if (mode == BalanceMode.FactionWise)
                {
                    balanceItems.Clear();
                    var factionGroups = accs.GroupBy(x => x.FactionID ?? x.AccountID).ToList();
                    balanceItems.AddRange(factionGroups.Select(x => new BalanceItem(b.IsMatchMakerGame, x.ToArray())));
                }

                if (mode == BalanceMode.Normal)
                {
                    balanceItems.Clear();
                    balanceItems.AddRange(accs.Select(x => new BalanceItem(b.IsMatchMakerGame, x)));
                }

                var sw = new Stopwatch();
                sw.Start();
                RecursiveBalance(0);
                sw.Stop();

                if (bestTeams == null)
                {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return fallback;
                }

                var minSize = bestTeams.Min(x => x.Count);
                var maxSize = bestTeams.Max(x => x.Count);
                var sizesWrong = maxSize / (double)minSize > MaxTeamSizeDifferenceRatio;

                // cbalance failed, rebalance using normal
                if (mode == BalanceMode.ClanWise && (bestTeams == null || GetTeamsDifference(bestTeams) > MaxCbalanceDifference || sizesWrong)) return new Balancer().LegacyBalance(teamCount, BalanceMode.Normal, b, unmovablePlayers);
                // cbalance failed, rebalance using normal

                if (sizesWrong && mode == BalanceMode.FactionWise)
                {
                    var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                    fallback.Message += "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                    return fallback; // fallback standard balance if PW balance fails
                    /*ret.CanStart = false;
                    ret.Message = string.Format("Failed to balance - too many people from same faction");
                    return ret;*/
                }

                if (unmovablePlayers != null && unmovablePlayers.Length > 0)
                {
                    var minElo = bestTeams.Min(x => x.AvgElo);
                    var maxElo = bestTeams.Max(x => x.AvgElo);
                    if (maxElo - minElo > GlobalConst.MaxPwEloDifference)
                    {
                        var fallback = new Balancer().LegacyBalance(teamCount, BalanceMode.ClanWise, b, null);
                        fallback.Message +=
                            "\nWarning: STANDARD TEAM BALANCE USED, PlanetWars not possible with those teams, too many from one faction";
                        return fallback; // fallback standard balance if PW balance fails
                        /*
                        ret.CanStart = false;
                        ret.Message = string.Format("Team difference is too big - win chance {0}% - spectate some or wait for more people",
                                                    Utils.GetWinChancePercent(maxElo - minElo));
                        return ret;*/
                    }
                }

                if (bestTeams == null)
                {
                    ret.CanStart = false;
                    ret.Message =
                        string.Format(
                            "Failed to balance {0} - too many people from same clan or faction (in teams game you can try !random and !forcestart)");
                    return ret;
                }
                if (unmovablePlayers == null || unmovablePlayers.Length == 0) bestTeams = bestTeams.Shuffle(); // permute when not unmovable players present

                var text = "( ";

                var lastTeamElo = 0.0;
                var allyNum = 0;
                foreach (var team in bestTeams)
                {
                    if (allyNum > 0) text += " : ";
                    text += string.Format("{0}", (allyNum + 1));
                    if (allyNum > 0) text += string.Format("={0}%)", Utils.GetWinChancePercent(lastTeamElo - team.AvgElo));
                    lastTeamElo = team.AvgElo;

                    foreach (var u in team.Items.SelectMany(x => x.LobbyId)) ret.Players.Single(x => x.LobbyID == u).AllyID = allyNum;
                    allyNum++;
                }
                text += ")";

                ret.Message = string.Format(
                    "{0} players balanced {2} to {1} teams {3}. {4} combinations checked, spent {5}ms of CPU time",
                    bestTeams.Sum(x => x.Count),
                    teamCount,
                    mode,
                    text,
                    iterationsChecked,
                    sw.ElapsedMilliseconds);
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.ToString());
                ret.Message = ex.ToString();
                ret.CanStart = false;
            }
            return ret;
        }
 public BalanceTeam Clone()
 {
     var clone = new BalanceTeam();
     clone.Items = new List<BalanceItem>(Items);
     clone.AvgElo = AvgElo;
     clone.EloSum = EloSum;
     clone.Count = Count;
     return clone;
 }