Posted: 14 Jan 2007, 15:24
Relative, yeah, it's possible to port it. However tasclient is in pascal, so someone has to rewrite it with different containers and stuff..
Also algorithm for cbalance is now needlessly complex (I think), because it evolved slowly and I changed how priorities work for it..
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);
}