Also algorithm for cbalance is now needlessly complex (I think), because it evolved slowly and I changed how priorities work for it..
Code: Select all
// user and rank info
private class UsRank
{
public int id;
public int rank;
public string clan;
public UsRank(int id, int rank, string clan)
{
this.id = id;
this.rank = rank;
this.clan = clan;
}
}
private static string GetClan(string name)
{
string[] parts = name.Split(new char[] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 2) {
if (parts[0].Length > parts[1].Length) return parts[1]; else return parts[0];
} return "";
}
private void BalanceTeams(int teamCount, bool clanwise)
{
List<UserBattleStatus> actUsers = new List<UserBattleStatus>();
List<UsRank> ranker = new List<UsRank>();
Battle b = tas.GetBattle();
foreach (UserBattleStatus u in b.Users) {
if (!u.IsSpectator) {
actUsers.Add(u);
User p;
if (tas.GetExistingUser(u.name, out p)) ranker.Add(new UsRank(ranker.Count, p.rank, GetClan(u.name))); else ranker.Add(new UsRank(ranker.Count, 0, GetClan(u.name))); // cannot find user, assume rank 0
}
}
Random rand = new Random();
List<UsRank> tempList = new List<UsRank>(ranker);
ranker.Clear();
while (tempList.Count > 0) {
// find max rank value
int maxval = int.MinValue;
foreach (UsRank u in tempList) {
if (u.rank > maxval) {
maxval = u.rank;
}
}
List<UsRank> l2 = new List<UsRank>(); // pick pieces with max rank to l2
int j = 0;
while (j < tempList.Count) {
if (tempList[j].rank == maxval) {
l2.Add(tempList[j]);
tempList.RemoveAt(j);
j = 0;
}
j++;
}
while (l2.Count > 0) { // randomly add pieces from l2 to ranker
int ind = rand.Next(l2.Count);
ranker.Add(l2[ind]);
l2.RemoveAt(ind);
}
}
if (teamCount < 2 || teamCount > ranker.Count) teamCount = 2;
List<UsRank>[] teamUsers = new List<UsRank>[teamCount];
for (int i = 0; i < teamUsers.Length; ++i) teamUsers[i] = new List<UsRank>();
int[] teamSums = new int[teamCount];
List<string>[] teamClans = new List<string>[teamCount];
for (int i = 0; i < teamClans.Length; ++i) teamClans[i] = new List<string>();
if (clanwise) {
string clans = "";
// remove clans that have less than 2 members - those are irelevant
foreach (UsRank u in ranker) {
if (u.clan != "") {
if (ranker.FindAll(delegate(UsRank x) { return x.clan == u.clan; }).Count < 2) {
u.clan = "";
} else {
clans += u.clan + ", ";
}
}
}
if (clans != "") SayBattle("those clan are being balanced: " + clans);
}
// this cycle performs actual user adding to teams
int cnt = 0;
while (ranker.Count > 0) {
int minsum = int.MaxValue;
int minid = 0;
for (int i = 0; i < teamCount; ++i) {
List<UsRank> l = teamUsers[i];
// pick only current "row" and find the one with least sum
if (l.Count == cnt / teamCount) {
if (teamSums[i] < minsum) {
minid = i;
minsum = teamSums[i];
}
}
}
int picked_user = 0;
if (clanwise) { // clanwise balancing - attempt to pick someone with same clan
// selected team already has some clan
int rank = ranker[0].rank;
List<int> temp = new List<int>();
// get list of clans assigned to other teams
List<string> assignedClans = new List<string>();
for (int i = 0; i < teamClans.Length; ++i) {
if (i != minid) {
foreach (string clanName in teamClans[i]) {
assignedClans.Add(clanName);
}
}
}
// first try to get some with same clan
if (teamClans[minid].Count > 0) {
for (int i = 0; i < ranker.Count; ++i) {
if (temp.Count > 0 && ranker[i].rank != rank) break;
if (ranker[i].clan != "" && teamClans[minid].Contains(ranker[i].clan)) temp.Add(i);
}
}
if (temp.Count == 0 && assignedClans.Count > 0) {
// we dont have any candidates try to get clanner from unassigned clan
for (int i = 0; i < ranker.Count; ++i) {
if (temp.Count > 0 && ranker[i].rank != rank) break;
if (ranker[i].clan != "" && !assignedClans.Contains(ranker[i].clan)) temp.Add(i);
}
}
if (temp.Count == 0) {
// we still dont have any candidates try to get non-clanner
for (int i = 0; i < ranker.Count; ++i) {
if (temp.Count > 0 && ranker[i].rank != rank) break;
if (ranker[i].clan == "") temp.Add(i);
}
}
// if we have some candidates pick one randomly
if (temp.Count > 0) picked_user = temp[rand.Next(temp.Count)]; ;
}
UsRank usr = ranker[picked_user];
teamUsers[minid].Add(usr);
teamSums[minid] += usr.rank;
if (clanwise && usr.clan != "") { // if we work with clans add user's clan to clan list for his team
if (!teamClans[minid].Contains(usr.clan)) teamClans[minid].Add(usr.clan);
}
ranker.RemoveAt(picked_user);
cnt++;
}
// alliances for allinace permutations
List<int> allys = new List<int>();
for (int i = 0; i < teamCount; ++i) allys.Add(i);
for (int i = 0; i < teamCount; ++i) {
// permute one alliance
int rdindex = rand.Next(allys.Count);
int allynum = allys[rdindex];
allys.RemoveAt(rdindex);
foreach (UsRank u in teamUsers[i]) {
tas.ForceAlly(actUsers[u.id].name, allynum);
}
}
string t = string.Format("{0} players balanced to {1} teams (ranks ", actUsers.Count, teamCount);
for (int i = 0; i < teamSums.Length; ++i) {
if (i > 0) t += ":";
t += teamSums[i].ToString();
}
t += ")";
if (clanwise) t += " respecting clans";
SayBattle(t);
}