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); }
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; }