1. Unbalanced matchups in soloq solution

    So i was kind of ill and was lying on my bed with hight temperature for like 3 days and as nobody sang me "Soft kitty" song, i was barbarically left 1v1 with my thoughts and eventually they, my thoughts i mean, stumbled on your terrific khm, sorry, terrible soloq system which, according to local racist streamers, not only breakes people's lives, but also breakes live's of everybody around them.
    When i think about it i imagine it like this:
    https://www.youtube.com/watch?v=qpFjHdHuDJI

    So comes the question: wtf can be done?
    Btw i like writing walls of text. Fist one who finds the anecdote will get the achievment "Speedreading Hero Understanding Zero"!

    I
    First of all requeueing:
    Even before that mad turbommr change every 10 sec was made, it was quite bad, being forced to requeue every minute to not to get lower mmr, because i dont know how about most of the peasants here but i personnaly dont want to play with or against lower mmr. It is not only that i have to repeat this process every 20 seconds now, it's that you actually loose your higher position in queue when you do it. Thus comes the most simple change - create and option for people to choose a constant mmr range for them.

    So they can queue 1 time and wait until it pops while the queue system looks for enemies and partners in a given mmr range. Not completely given at players discretion but their soloqrating+100-soloq-100*n range where the player can only choose his personal n {ranges from 1 to whatever}.
    You can set it by default on 3 or 4 and add and option to change it ONLY ON THE QUEUEING NPC if you put it on the other npc nobody is gonna find it, half of the players will still not know about this feature half a year from now
    On the queueing npc it's almost impossible to miss additional option {first 2 options are 1) queue solo 2)queue as group or something}

    II
    Secondly "cd" on 3 same players proccing in 1 team:
    Queue system now has that thingy that 3 people can't get the same comb, after fist game several members of that team have to play another game before they can get queued together again.
    Well, look how it worked out:1 guy just waits while 2 others play with someone else or log in on another character, reset the thingy and go again.
    So in the end it gives basically nothing. And it's kind of pretty predictable because it prefers to group one team of higher rated players and another lower, so people on high rating just snipe it all like in 2s.
    What you could've done instead is to randomly take player combinations for teams and dont pop queue when there's only 1 (or not 1 but too few) combinations possible.
    When there only 2 healers and 4 dd are queued (it happens all the time on high ratings) there are 6 combinations to group players up (although it's lower when there are people of the same class).
    That predictable combination control reminds me of some "smart random" critical strikes mechanics in dota or something like that.
    As a result people were waiting for a set of noncrit attacks and got a guaranted critical attack on next hit. Don't remember much about it but it's a terrible thing.
    Random is random, and soloqueue is basically the biggest lottery, don't put this predictable mechanism in here, leave it fully randomized.

    III
    And the main topic of discussion: unballanced matchups (e.g. tsg vs priest/shaman teams):
    Maybe it's okey, in other brackets people also get unfair matchups you will say: well in soloq like half of the games seem to be decided bofore they start and you cant avoid it, that is very irritating, they will probably bring you or get away from you 0 rating in the very long run, but what's the point of this "noise" which represents half of the games if you can just remove/rework it.

    It seems that the only solution anybody thought before is to either make it melee-caster-healer and there's constanly a cry about making it mhc on forum.
    But you could do so many things here actually:
    1)You could forbid sertain matchups: for example tsg with pala cant get matched to tsg with priest and so on.
    2)Or you could permit those matchups but reduce the rating change after the game: for example ts with pala would get +3 for win or -21 for loss instead of +12 -12 given that both teams are same rating.
    3)You could actually do all of this based on win-loss statistics af countless games played each season in soloq. You already have all the games being saved with lots of valuable information about them.
    Very simlified example:
    By the end of the season when top ratings are around 3k and top100 is at like 2600-2700, get the statistic on all tsg with priest agaist tsg with pala games.
    Gamse have to be above 2700 and within 100 rating (this way skill will be almost even, or it's also probably possible to fix the rating difference by "correcting the statistic" based on rating difference in each game) to get in statistics. Statistics for matchups have to contain a big sample (may have trouble with rare combs/matchups).
    Then we forbid all matchups that are below 60% winrate: 60% winrate means you win 1.5 more times more often than loose, quite a good point to cut it off (66.6% is alrady 2 times higher chance for a win and it's too much).
    Or we don't forbid it and change the rating you get for it based on this statistic:
    If win-loss ration we recieved here is 20-80 (20%) then games that should have been +12 -12 would be {FORMULAS1 0.2*(x)-0.8*(24-x)=0 => x=19.2} +19.2 -4.8
    This way the average rating you get from this is 0.The problem with this system is that 19.2 is not integer, but it's still better that nothing.
    Afterall, you can even mix both systems:for example games with less than 25% winrate are completely forbidden, and those from 25% to 50% adjusted by rating.Another interesting though is to prioritase matchups that you can get and prefer those ones that are closer to 50% (as i said earlier even when you have strictly 6 people queued what is minimum for 1 game, there are up to 6 possibles matchups and it greatly grows with each extra player in queue)


    IV
    Ok Ideas themselves are mosly over here, and since i was bored i also wrote a kind of realization of the queueing system with the traits i described above.
    1 simple C++ application in one cpp file:
    Spoiler: Show
    #include <iostream> //cin cout
    #include <vector> //vector
    #include <ctime> //time() for srand()
    #include <cstdlib> //rand()

    using namespace std;

    class Plyr
    {
    public:
    string name;
    int max;
    int min;
    int classlol;
    int specid;

    Plyr(string name1,int rating1,int drop1,string classlol1,string specid1)
    {
    name = name1;
    max = rating1 + 100;
    min = rating1 - 100 * (drop1 + 1);

    if (classlol1=="priest")
    classlol = 0;
    else if (classlol1=="druid")
    classlol = 1;
    else if (classlol1=="paladin")
    classlol = 2;
    else if (classlol1=="shaman")
    classlol = 3;
    else if (classlol1=="hunter")
    classlol = 4;
    else if (classlol1=="warrior")
    classlol = 5;
    else if (classlol1=="rogue")
    classlol = 6;
    else if (classlol1=="deathknight")
    classlol = 7;
    else if (classlol1=="warlock")
    classlol = 8;
    else if (classlol1=="mage")
    classlol = 9;
    else
    classlol = -1;
    // healerspecs first then the rest otherwise matchuptonumber function will produce higher numbers
    if (specid1=="discpri")
    specid = 0;
    else if (specid1=="hpal")
    specid = 1;
    else if (specid1=="rsham")
    specid = 2;
    else if (specid1=="rdru")
    specid = 3;
    else if (specid1=="holypri")
    specid = 4;
    else if (specid1=="protpalheal")
    specid = 5;

    else if (specid1=="shadowpri")
    specid = 6;
    else if (specid1=="protpaldd")
    specid = 7;
    else if (specid1=="retripal")
    specid = 8;
    else if (specid1=="feraldru")
    specid = 9;
    else if (specid1=="moonkindru")
    specid = 10;
    else if (specid1=="elesham")
    specid = 11;
    else if (specid1=="enhsham")
    specid = 12;

    else if (specid1=="armswar")
    specid = 13;
    else if (specid1=="protwar")
    specid = 14;
    else if (specid1=="furywar")
    specid = 15;
    else if (specid1=="unholydk")
    specid = 16;
    else if (specid1=="frostdk")
    specid = 17;
    else if (specid1=="bloodk")
    specid = 18;
    else if (specid1=="mmhunt")
    specid = 19;
    else if (specid1=="survhunt")
    specid = 20;
    else if (specid1=="bmhunt")
    specid = 21;
    else if (specid1=="sdrogue")
    specid = 22;
    else if (specid1=="mutirogue")
    specid = 23;
    else if (specid1=="combatrogue")
    specid = 24;
    else if (specid1=="frostmage")
    specid = 25;
    else if (specid1=="firemage")
    specid = 26;
    else if (specid1=="arcanemage")
    specid = 27;
    else if (specid1=="afflilock")
    specid = 28;
    else if (specid1=="demolock")
    specid = 29;
    else if (specid1=="destrolock")
    specid = 30;

    else
    specid = -1;

    if (specid == -1 || classlol == -1)
    cout<<"YOU BLIND MORON "<<classlol<<" "<<specid<<endl;
    }
    };

    class Matchup
    {
    public:
    string dd1name;
    string dd2name;
    string heal1name;
    string dd3name;
    string dd4name;
    string heal2name;

    Matchup(string d1name,string d2name,string h1name,string d3name,string d4name,string h2name)
    {
    dd1name = d1name;
    dd2name = d2name;
    heal1name = h1name;
    dd3name = d3name;
    dd4name = d4name;
    heal2name = h2name;
    }
    };

    int globalcount;
    bool queuechanged = true;
    bool queuefound = false;
    const long bannedmatchupnumbers[] = {
    1000000,1000001,1000002,1000003,1000004,1000005,10 00006,1000007,1000008,1000009,1000010,1000011,1000 012,1000013,
    2000000,2000001,2000002,2000003,2000004,2000005,20 00006,2000007,2000008,2000009,2000010,2000011,2000 012,2000013,
    3000000,3000001,3000002,3000003,3000004,3000005,30 00006,3000007,3000008,3000009,3000010,3000011,3000 012,3000013,
    4000000,4000001,4000002,4000003,4000004,4000005,40 00006,4000007,4000008,4000009,4000010,4000011,4000 012,4000013,
    5000000,5000001,5000002,5000003,5000004,5000005,50 00006,5000007,5000008,5000009,5000010,5000011,5000 012,5000013,
    6000000,6000001,6000002,6000003,6000004,6000005,60 00006,6000007,6000008,6000009,6000010,6000011,6000 012,6000013,
    7000000,7000001,7000002,7000003,7000004,7000005,70 00006,7000007,7000008,7000009,7000010,7000011,7000 012,7000013,
    8000000,8000001,8000002,8000003,8000004,8000005,80 00006,8000007,8000008,8000009,8000010,8000011,8000 012,8000013,
    9000000,9000001,9000002,9000003,9000004,9000005,90 00006,9000007,9000008,9000009,9000010,9000011,9000 012,9000013
    }; // just blanket numbers, probably none of those are equal to a real matchcomb id. it has to be sorted
    vector<Matchup> viablematchups;
    vector<long> uniquematchupsfound;
    vector<Plyr> erasedlist;

    void printlist(vector<Plyr> &list,char param)
    {
    if (param=='d')
    cout<<"\nQueued DD:"<<endl;
    else if (param=='h')
    cout<<"\nQueued Healers:"<<endl;

    for (int i=0; i<list.size(); i++)
    cout<<list[i].name<<endl;
    cout<<endl;
    }

    long matchuptonumber(int d1, int d2, int h1, int d3, int d4, int h2)
    {
    long res;
    int t1,t2;

    if (d1>d2) //war dk hpal is the same as dk war hpal
    t1 = d1+d2*25+h1*625; //this is why healer specids should go first, so max possible value of t1 is much less
    else
    t1 = d1*25+d2+h1*625; //25 is the abount of different dps specids, 24*25+24=624

    if (d3>d4)
    t2 = d3+d4*25+h2*625;
    else
    t2 = d3*25+d4+h2*625;

    if (t1>t2) //war dk hpal - rog mag rdru is the same as rog mag rdru - war dk hpal
    res = t1+t2*3750; //max possible value of t1/t2 is 24+24*25+5*625=3749
    else if (t1<t2)
    res = t1*3750+t2;
    else
    res = 0; //this means it's a mirror
    return res; //max possible return value is 3749*3750+3749=14062499
    }

    // will do search in sorted array size of n=max-min in only log2(n) steps
    void lnsearch(long x,int min, int max,bool &foundlol)
    {
    if (min<max)
    if (x < bannedmatchupnumbers[(min+max)/2])
    lnsearch(x,min,(min+max)/2-1,foundlol);
    else if (x > bannedmatchupnumbers[(min+max)/2])
    lnsearch(x,(min+max)/2+1,max,foundlol);
    else
    foundlol = true;
    else if (min==max)
    if (x == bannedmatchupnumbers[min])
    foundlol = true;
    }

    void savematchup(const Plyr &d1,const Plyr &d2,const Plyr &h1,const Plyr &d3,const Plyr &d4,const Plyr &h2)
    {
    viablematchups.push_back(Matchup(d1.name,d2.name,h 1.name,d3.name,d4.name,h2.name));
    }

    void matchupcheck(const Plyr &d1,const Plyr &d2,const Plyr &h1,const Plyr &d3,const Plyr &d4,const Plyr &h2)
    {
    if (d1.classlol == d2.classlol || d1.classlol == h1.classlol || d2.classlol == h1.classlol ||
    d3.classlol == d4.classlol || d3.classlol == h2.classlol || d4.classlol == h2.classlol)
    return; // only 1 of each class in a team

    long z = matchuptonumber(d1.specid,d2.specid,h1.specid,d3.s pecid,d4.specid,h2.specid);
    int num = sizeof(bannedmatchupnumbers) / sizeof(bannedmatchupnumbers[0]);
    bool foundlol = false;

    lnsearch(z,0,num-1,foundlol);

    if (!foundlol)
    {
    bool isunique = true;
    for (int i=0; i<uniquematchupsfound.size(); i++)
    {
    if (uniquematchupsfound[i] == z)
    isunique = false;
    }

    if (isunique)
    {
    globalcount++;
    uniquematchupsfound.push_back(z);
    }

    savematchup(d1,d2,h1,d3,d4,h2);
    }
    }

    //covers all possible matchup combinations of 6 given players
    void matchup6analisys(const Plyr &d1,const Plyr &d2,const Plyr &d3,const Plyr &d4,const Plyr &h1,const Plyr &h2)
    {
    matchupcheck(d1,d2,h1,d3,d4,h2);
    matchupcheck(d1,d2,h2,d3,d4,h1);

    matchupcheck(d1,d3,h1,d2,d4,h2);
    matchupcheck(d1,d3,h2,d2,d4,h1);

    matchupcheck(d1,d4,h1,d2,d3,h2);
    matchupcheck(d1,d4,h2,d2,d3,h1);
    }

    void searchViableMatchups(const vector<Plyr> &list,int flag,int k,int i1,int i2,int i3,int i4,const Plyr &h1,const Plyr &h2)
    {
    if (globalcount > 1) //2 is the minimum amount of possible unique matchups required for queue to pop
    return;

    matchup6analisys(list[i1],list[i2],list[i3],list[i4],h1,h2);

    if (list.size()>4+k)
    {
    k++;
    searchViableMatchups(list,1,k,i1,i2,i3,3+k,h1,h2);
    if (flag >= 2)
    searchViableMatchups(list,2,k,i1,i2,i4,3+k,h1,h2);
    if (flag >= 3)
    searchViableMatchups(list,3,k,i1,i3,i4,3+k,h1,h2);
    if (flag == 4)
    searchViableMatchups(list,4,k,i2,i3,i4,3+k,h1,h2);
    }
    }

    int ddlistcheck(const vector<Plyr> &list,const Plyr &h1,const Plyr &h2)
    {
    int res=0;
    int speccount[25]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0};

    vector<Plyr> viableddlist;
    for (int i=0; i<list.size(); i++)
    {
    int maxposspecs=2;
    if (list[i].classlol == h1.classlol || list[i].classlol == h2.classlol)
    maxposspecs--;
    if (speccount[list[i].specid-6]<maxposspecs && list[i].max >= max(h1.min,h2.min) and list[i].min <= min(h1.max,h2.max))
    {
    speccount[list[i].specid-6]++;
    viableddlist.push_back(list[i]);
    }
    if (viableddlist.size() >= 48)
    break;
    }

    globalcount = 0;
    uniquematchupsfound.clear();
    if (viableddlist.size() >= 4)
    searchViableMatchups(viableddlist,4,0,0,1,2,3,h1,h 2);

    if (globalcount > 1)
    return 1;
    else
    return 0;
    }

    void erasebyname(vector<Plyr> &list,string name1)
    {
    for (int i=0; i<list.size(); i++)
    if (list[i].name == name1)
    {
    erasedlist.push_back(list[i]);
    list.erase(list.begin()+i);
    }
    queuechanged = true;
    }

    void requeueerased(vector<Plyr> &hlist,vector<Plyr> &dlist)
    {
    for (int i=0; i<erasedlist.size(); i++)
    {
    if (erasedlist[i].specid<=5)
    hlist.push_back(erasedlist[i]);
    else
    dlist.push_back(erasedlist[i]);
    }
    erasedlist.clear();
    queuechanged = true;
    }

    void popqueue(vector<Plyr> &hlist,vector<Plyr> &dlist)
    {
    cout<<"\nViable Matchups found:"<<endl;
    for (int i=0; i<viablematchups.size(); i++)
    {
    cout<<viablematchups[i].dd1name<<" "<<viablematchups[i].dd2name<<" "<<viablematchups[i].heal1name<<" - "<<
    viablematchups[i].dd3name<<" "<<viablematchups[i].dd4name<<" "<<viablematchups[i].heal2name<<endl;
    }
    cout<<endl;


    int chosenindex = rand() % viablematchups.size(); //once we got more than 2 possible matchups, choose one of them


    string d1name = viablematchups[chosenindex].dd1name;
    string d2name = viablematchups[chosenindex].dd2name;
    string h1name = viablematchups[chosenindex].heal1name;
    string d3name = viablematchups[chosenindex].dd3name;
    string d4name = viablematchups[chosenindex].dd4name;
    string h2name = viablematchups[chosenindex].heal2name;

    cout<<"Chosen Matchup: \n"<<d1name<<" "<<d2name<<" "<<h1name<<" - "<<d3name<<" "<<d4name<<" "<<h2name<<endl<<endl;
    //cout<<d1name<<" "<<d2name<<" "<<h1name<<" - "<<d3name<<" "<<d4name<<" "<<h2name<<endl;

    viablematchups.clear();

    erasebyname(dlist,d1name); //remove players from queue
    erasebyname(dlist,d2name);
    erasebyname(dlist,d3name);
    erasebyname(dlist,d4name);

    erasebyname(hlist,h1name);
    erasebyname(hlist,h2name);
    }

    void healerlistcheck(const vector<Plyr> &hlist,const vector<Plyr> &dlist)
    {
    for (int i=1; i<hlist.size(); i++) //the cycle is organized to go 01 02 12 03 13 23 04 14 24 34 and so on
    {
    for (int j=0; j<i; j++)
    {
    if (hlist[i].max >= hlist[j].min and hlist[i].min <= hlist[j].max)
    {
    int res = ddlistcheck(dlist,hlist[i],hlist[j]);
    if (res)
    {
    queuefound = true;
    return;
    }
    }
    }
    }
    }

    void filltest1(vector<Plyr> &hlist,vector<Plyr> &dlist)
    {
    hlist.push_back(Plyr("punter",3055,1,"shaman","rsh am"));
    hlist.push_back(Plyr("drass",2854,0,"druid","rdru" ));
    hlist.push_back(Plyr("next",2880,0,"paladin","hpal "));
    hlist.push_back(Plyr("raint",2935,1,"druid","rdru" ));
    hlist.push_back(Plyr("seasun",2822,0,"druid","rdru "));
    hlist.push_back(Plyr("soumi",2946,2,"priest","disc pri"));
    hlist.push_back(Plyr("oddwafle",2914,1,"priest","d iscpri"));

    dlist.push_back(Plyr("worldsbest",2444,0,"rogue"," sdrogue"));
    dlist.push_back(Plyr("ripzy",2988,1,"warlock","aff lilock"));
    dlist.push_back(Plyr("simba",3088,2,"druid","feral dru"));
    dlist.push_back(Plyr("khrystal",3022,1,"priest","s hadowpri"));
    dlist.push_back(Plyr("merce",2988,1,"warlock","des trolock"));
    dlist.push_back(Plyr("onlysd",2444,0,"rogue","sdro gue"));
    dlist.push_back(Plyr("touptite",2849,0,"warlock"," afflilock"));
    dlist.push_back(Plyr("homerjay",2812,0,"hunter","m mhunt"));
    dlist.push_back(Plyr("sebii",2916,1,"warrior","pro twar"));
    dlist.push_back(Plyr("swepy",2714,0,"warrior","arm swar"));
    dlist.push_back(Plyr("preghera",2717,1,"paladin"," retripal"));
    dlist.push_back(Plyr("batysasai",2666,0,"deathknig ht","unholydk"));
    dlist.push_back(Plyr("azk",2810,0,"hunter","mmhunt "));
    dlist.push_back(Plyr("petosatana",2835,1,"shaman", "enhsham"));
    dlist.push_back(Plyr("darthsotek",2788,0,"priest", "shadowpri"));
    dlist.push_back(Plyr("slayermode",2777,1,"mage","f rostmage"));
    dlist.push_back(Plyr("hanry",2705,0,"mage","frostm age"));
    }

    void filltest2(vector<Plyr> &hlist,vector<Plyr> &dlist)
    {
    hlist.push_back(Plyr("2.5hpal",2544,2,"paladin","h pal"));
    hlist.push_back(Plyr("punter",3055,1,"shaman","rsh am"));
    hlist.push_back(Plyr("2.2rdru",2264,3,"druid","rdr u"));
    hlist.push_back(Plyr("2.5disc",2517,2,"priest","di scpri"));
    hlist.push_back(Plyr("2.6disc",2644,1,"priest","di scpri"));
    hlist.push_back(Plyr("drass",2854,0,"druid","rdru" ));
    hlist.push_back(Plyr("1.8rsham",1790,3,"shaman","r sham"));
    hlist.push_back(Plyr("next",2880,0,"paladin","hpal "));
    hlist.push_back(Plyr("2.4rsham",2410,3,"shaman","r sham"));
    hlist.push_back(Plyr("1.5rdru",1537,0,"druid","rdr u"));
    hlist.push_back(Plyr("2.2hpal",2271,2,"paladin","h pal"));
    hlist.push_back(Plyr("2.2disc",2177,2,"priest","di scpri"));
    hlist.push_back(Plyr("raint",2935,1,"druid","rdru" ));
    hlist.push_back(Plyr("2.1rsham",2090,1,"shaman","r sham"));
    hlist.push_back(Plyr("1.3hpal",1374,5,"paladin","h pal"));
    hlist.push_back(Plyr("seasun",2822,0,"druid","rdru "));
    hlist.push_back(Plyr("1.5hpal",1516,1,"paladin","h pal"));
    hlist.push_back(Plyr("2.6rdru",2588,1,"druid","rdr u"));
    hlist.push_back(Plyr("soumi",2946,2,"priest","disc pri"));
    hlist.push_back(Plyr("oddwafle",2914,1,"priest","d iscpri"));
    hlist.push_back(Plyr("2.3hpal",2333,2,"paladin","h pal"));
    hlist.push_back(Plyr("1.8hpal",1844,1,"paladin","h pal"));
    hlist.push_back(Plyr("1.5disc",1488,3,"priest","di scpri"));
    hlist.push_back(Plyr("1.9rdru",1888,0,"druid","rdr u"));
    hlist.push_back(Plyr("1.7rsham",1750,3,"shaman","r sham"));
    hlist.push_back(Plyr("1.8disc",1817,2,"priest","di scpri"));
    hlist.push_back(Plyr("1.9disc",1947,1,"priest","di scpri"));

    dlist.push_back(Plyr("worldsbest",2444,3,"rogue"," sdrogue"));
    dlist.push_back(Plyr("1.8arms",1845,3,"warrior","a rmswar"));
    dlist.push_back(Plyr("ripzy",2988,2,"warlock","aff lilock"));
    dlist.push_back(Plyr("1.6lock",1644,2,"warlock","a fflilock"));
    dlist.push_back(Plyr("simba",3088,2,"druid","feral dru"));
    dlist.push_back(Plyr("1.5rog",1477,4,"rogue","sdro gue"));
    dlist.push_back(Plyr("1.6ele",1615,3,"shaman","ele sham"));
    dlist.push_back(Plyr("2.6hunt",2625,2,"hunter","mm hunt"));
    dlist.push_back(Plyr("khrystal",3022,1,"priest","s hadowpri"));
    dlist.push_back(Plyr("slayermode",2777,1,"mage","f rostmage"));
    dlist.push_back(Plyr("merce",2988,1,"warlock","des trolock"));
    dlist.push_back(Plyr("2.0hunt",2033,2,"hunter","mm hunt"));
    dlist.push_back(Plyr("onlysd",2444,3,"rogue","sdro gue"));
    dlist.push_back(Plyr("1.7shpr",1695,1,"priest","sh adowpri"));
    dlist.push_back(Plyr("touptite",2849,1,"warlock"," afflilock"));
    dlist.push_back(Plyr("1.9mag",1870,2,"mage","frost mage"));
    dlist.push_back(Plyr("1.3rog",1324,2,"rogue","sdro gue"));
    dlist.push_back(Plyr("2.6dk",2577,2,"deathknight", "unholydk"));
    dlist.push_back(Plyr("homerjay",2812,0,"hunter","m mhunt"));
    dlist.push_back(Plyr("1.8lock",1777,3,"warlock","a fflilock"));
    dlist.push_back(Plyr("sebii",2916,2,"warrior","pro twar"));
    dlist.push_back(Plyr("2.4dk",2405,2,"deathknight", "unholydk"));
    dlist.push_back(Plyr("1.5mag",1489,2,"mage","frost mage"));
    dlist.push_back(Plyr("1.9hunt",1921,3,"hunter","mm hunt"));
    dlist.push_back(Plyr("2.4retri",2462,1,"paladin"," retripal"));
    dlist.push_back(Plyr("2.3dk",2354,3,"deathknight", "unholydk"));
    dlist.push_back(Plyr("1.8ele",1855,2,"shaman","ele sham"));
    dlist.push_back(Plyr("swepy",2714,0,"warrior","arm swar"));
    dlist.push_back(Plyr("2.5shpr",2481,2,"priest","sh adowpri"));
    dlist.push_back(Plyr("2.2dk",2177,3,"deathknight", "unholydk"));
    dlist.push_back(Plyr("2.6arms",2628,1,"warrior","a rmswar"));
    dlist.push_back(Plyr("2.4mag",2389,2,"mage","frost mage"));
    dlist.push_back(Plyr("2.6retri",2645,2,"paladin"," retripal"));
    dlist.push_back(Plyr("2.0lock",1980,3,"warlock","a fflilock"));
    dlist.push_back(Plyr("preghera",2717,1,"paladin"," retripal"));
    dlist.push_back(Plyr("1.9ele",1945,2,"shaman","ele sham"));
    dlist.push_back(Plyr("1.6feral",1677,2,"druid","fe raldru"));
    dlist.push_back(Plyr("batysasai",2666,0,"deathknig ht","unholydk"));
    dlist.push_back(Plyr("2.6lock",2584,1,"warlock","a fflilock"));
    dlist.push_back(Plyr("2.5arms",2521,1,"warrior","a rmswar"));
    dlist.push_back(Plyr("2.2retri",2217,2,"paladin"," retripal"));
    dlist.push_back(Plyr("azk",2810,1,"hunter","mmhunt "));
    dlist.push_back(Plyr("2.4feral",2388,2,"druid","fe raldru"));
    dlist.push_back(Plyr("petosatana",2835,1,"shaman", "enhsham"));
    dlist.push_back(Plyr("2.1arms",2104,4,"warrior","a rmswar"));
    dlist.push_back(Plyr("1.8retri",1855,2,"paladin"," retripal"));
    dlist.push_back(Plyr("1.7dk",1754,2,"deathknight", "unholydk"));
    dlist.push_back(Plyr("2.3lock",2341,1,"warlock","a fflilock"));
    dlist.push_back(Plyr("1.6arms",1578,2,"warrior","a rmswar"));
    dlist.push_back(Plyr("2.6ele",2667,1,"shaman","ele sham"));
    dlist.push_back(Plyr("darthsotek",2788,0,"priest", "shadowpri"));
    dlist.push_back(Plyr("2.1shpr",2148,2,"priest","sh adowpri"));
    dlist.push_back(Plyr("2.5hunt",2541,1,"hunter","mm hunt"));
    dlist.push_back(Plyr("1.6retri",1634,3,"paladin"," retripal"));
    dlist.push_back(Plyr("1.7rog",1727,2,"rogue","sdro gue"));
    dlist.push_back(Plyr("2.4ele",2372,2,"shaman","ele sham"));
    dlist.push_back(Plyr("hanry",2705,0,"mage","frostm age"));
    dlist.push_back(Plyr("1.6hunt",1597,2,"hunter","mm hunt"));
    }

    int main()
    {
    string incstr;
    srand(time(0));

    vector<Plyr> healerlist;
    vector<Plyr> ddlist;

    filltest2(healerlist,ddlist);

    while(true)
    {
    cout << "->";
    cin >> incstr;

    if (incstr=="next")
    {
    if (queuechanged)
    {
    healerlistcheck(healerlist,ddlist);
    queuechanged = false;
    }
    else
    cout<<"\nQueue didn't change since last time"<<endl<<endl;

    if (queuefound)
    {
    popqueue(healerlist,ddlist);
    queuefound = false;
    }
    else
    cout<<"\nNo viable matchups for queue were found"<<endl<<endl;
    }

    if (incstr=="go")
    {
    while(true)
    {
    bool shouldstop = false;
    if (queuechanged)
    {
    healerlistcheck(healerlist,ddlist);
    queuechanged = false;
    }
    else
    cout<<"\nQueue didn't change since last time"<<endl<<endl;
    if (!queuefound)
    shouldstop = true;
    if (queuefound)
    {
    popqueue(healerlist,ddlist);
    queuefound = false;
    }
    else
    cout<<"\nNo viable matchups for queue were found"<<endl<<endl;
    if (shouldstop)
    break;
    }
    }

    if (incstr=="req")
    {
    requeueerased(healerlist,ddlist);
    }

    if (incstr=="ddlist")
    {
    printlist(ddlist,'d');
    }

    if (incstr=="hlist")
    {
    printlist(healerlist,'h');
    }

    if (incstr=="elist")
    {
    printlist(erasedlist,'1');
    }

    if (incstr=="exit")
    break;
    }

    return 0;
    }


    It does cover:
    1) Personal rating range feature described at I
    2) Random matchup only when several matchups are possible as described at II
    3) Forbidden combs list feature, which is the most interesting and complicated part here.
    Spoiler: Show

    I wrote it while i was in the process of figuring out the good algorithm to effectively check the queue for possible matchups that do not belong to the forbiddenlist giving the priority to those players who queued fist.

    Most of the time (unless you have too many banned matchups) it takes fist 2 healers in queue that have the shared mmr range and the first 4 dd from the ddqueue and the same mmr range and chooses one of upt to 6 possible matchups.
    Sounds extremely easy, unless you get in a theoretical situation where you have forbidden 1.5 million (i'll get to where i got 1.5mil later) matchups out of 1.5 million and only left lest than 10 valid ones. In this case you have to check an anormous amount of possible matchups.
    The probablility to find a valid matchup witch each check in this situation (lets say you have 10 valid) is 10/1500000
    The probablility to find a valid matchup in n checks is 1-(1-10/1500000)^n
    Given that you have 25 dd specs, for every pair of healers there are (48*(48-1)/2)*((48-2)*(48-3)/2)=1167480 different possibilities to take 4 players out of ddqueue size of 48 (no point considering a queue longer that 48 because in a queue of 48 you have each spec 2 times and you cant take 2 players of same class in 1 team, 48=25*2=50-2healers) actually the exact numbers are less because of "no 2 players in same team" rule and are around 700000 (depends on what classes are the healers in a given pair) and you will see them in 1 of the videos.
    So resuming the question before the probablility to find a valid matchup in 700000 checks is 1-(1-10/1500000)^700000=0.99 - 99% to find a matchup for every pair of 2 healers. And on my computer it takes less than 100 miliseconds to check all 700000. And if if you only leave 1 possible matchup (for lolz) 1-(1-1/1500000)^700000=0.37
    Still 37% to find a match, even if you require to find 2 matches to be able to choose from randomly like i wanted, 0.37^2=0.14, still a valid chance to find que.
    Now i kind of forgot why i went into those calculations, whatever, what i mean in order for those huge calculations to start happening you need to forbind almost everything for example if you leave 100 possible matchups you will only need 70000 calculations per pair of healers to find 2 possible matches for every pair of healers with a 98% probability (1-(1-100/1500000)^70000)^2=0.98 (when you have 48 dd on this range 2 of every different spec). Thus its 5 milliseconds for every pair of healers.
    But if you only did forbade half of the matchups it's 10 checks per pair of healers with almost 100% chance to find 2 matches (1-(1-750000/1500000)^10)^2=0.998 and i highly doubt you will forbid half a million matchups.
    While the situation is theoretical it's required to be analyzed to know where the edge is, here's the video for situation where all 700000 are checked for every pair of healers.
    Spoiler: Show


    But you still need an algorithm how to manage all the those combinations. While they won't have computational difficulty (even if it did you could prevent it by simple maxcalculationsamount or something more smart) they still operate with hight numbers of those things.
    So now idk, gonna try to explain used algorithms for virtually possible readers (anybody reading?ok Russian guy lives in a hotel, all the staff
    is english speaking, one morning he wakes up and goes to the toilet, not to pee but another thig, tries to flush but the flush button doesnt work.
    He thinks what to do a few minutes, eventually comes out of his room and sees cleaning lady in the hallway, with few english words he knows he says: "excuse me, there! come!" she follows him, they enter the toilet room, the guy shows with his finger on the contents of the toilet, and says: "Look!" and presses the flush buttn. It works out.)

    I have no idea, how this server's soloq queue system works, but this is what i came up with given i needed to have features 1-3 implemented:
    We have list of queued healers and a list of queued dd, search starts from healer queue and tries to find 2 healers with shared mmr range, first in queue are first to look at.
    Spoiler: Show

    No healer with those requirements found means no queue pop is possible.
    Once 2 healers are found, we look through dd queue and choose those ddplayers who fit in in the given mmr range.
    Spoiler: Show

    Once we find at least 4 (max 48, explained in image above) dd that meet the requirements, lets say we found m ddplayers (m>=4; m<=48)
    we take first 4 plyrs out of m plyrs list and start checking possible combinations with these 4dd and 2 healers (up to 6 combinations).
    Id there aren't more than 2 unique matchups found within first 4 ddplyrs (e.g. 4 matchups but all unique)
    Spoiler: Show


    then we take 1 more ddplyr out of m and continue checking, this is done by a recursive function:
    it takes as an argument that list of up to 48 plyrs and checks all possible combinations for given 2 healers
    Here is an example for m=7
    Spoiler: Show

    The amount of combinations to get 4 different items from the list of m items equals m*(m-1)*(m-2)*(m-3)/(4!)={in case of m==7}=7*6*5*4/(1*2*3*4)=35 as you can see it's exactly what the program covered. Thus it covers all possible combinations of 4 players in the given list for every combination of 4 ddplayers and 2 healers you have 6 possibilities to get 3 players against 3 players (in 1 heal 2 dd combo):
    (d1d2h1-d3d4h2; d1d3h1-d2d4h2; d1d4h1-d2d3h2)
    (d1d2h2-d3d4h1; d1d3h2-d2d4h1; d1d4h2-d2d3h1)
    This is what function called matchup6analisys does - checks those 6 possibilities.
    Spoiler: Show

    Function called matchupcheck checks the 1 matchup itself: if there are 2 same classes in 1 team it's immediately isn't valid then it checks the matchup itself and if the mathchup belongs to forbidden list it's not valid as well. If matchup was valid, it puts it into the list of possible matchups to later choose 1 of the variants when popping queue.
    At this point if a pssible queue pop found you should pop the queue, if it wasn't it keeps seaching for new pairs of healers with their shared mmr ranges until
    2healers+4validdd are found.

    If there is a way to get a game going without going out of the players mmr ranges that they set for themselves - it will find it.
    Now about the possible amount of different matchups: we have 25 possible dps specs and 6 possible healer specs.
    Spoiler: Show

    If i assume that there are approximately 3 specs per class, the amount of possibilities to take 2 dd players of different class in 1 team is approximately 25*(25-3)/2
    same for the 2nd team, thus 25^2*22^2/4 possibilities to take 4 dds in different teams so each one will be different spec-wise.
    With 6 healers specs and 6*6/2= 18 possibilites to take 2 healers it's around 25^2*22^2/4*18=1361250 (that is approximate estimation) possible different spec-wise matchups. (actually more accurate formula for this will be 25*(6+(6*6-6)/2)+((25*(25-3)/2)^2-25)/2*6*6 = 1361325 but that makes almost no difference)
    So how do you compare all of those matchups, or hold information about them?
    Simple - a function that takes specids of all 6 players for the matchup and returns a unique identificator.
    Spoiler: Show

    Maximum identificator possible in this case is 14062499, what is approximately 10 times more than the amount of possible matchups, so 90% of numbers are not used, but its very simple.
    Everytime you are checking a matchup, you get the identificator for this matchup and compare it with the list of the forbidden matchups
    Sound like averegely m/2 comparisons for list size of m, but if you sort the list, you can do it with log2(m). with 1 million forbidden matchups out of 1.5 million it is log2(10^6)=20 comparisons only.
    Best way to explain the algorithm is this example: how many questions you need to find a number somebody secretly chose from 0 to 100? log2(100)=7 questions (up to 7 actually)
    Lets say somebody chose 34;
    is it more than 50 less than 50 or equial? -less
    is it more than 25 less than 25 or equial? -more
    is it more than 38 less than 38 or equial? -less
    is it more than 32 less than 32 or equial? -more
    is it more than 35 less than 35 or equial? -less
    answer is 34; 5 questions.



    V
    Now another very important question: how to gather the statistics?
    I know nothing about what you already gather, except that you have some database that is used for armory, and you actually have there valuable information on:
    0) You have list of all games played on server, with matchids, they are universal for all brackets but that shouldnt be a problem.
    1) What were the classes that fought in the matchup.
    2) All information on win-loss.
    3) You kind of disabled the display of mmr and rating, but is it just hidden, you you don't have it at all, idk.
    4) Time, damage,healing e.t.c. i dont see use for this here.
    My main concern here is it seems you don't have information on player's specs at the time of those games.
    Without spec info you can do the thing only based on classes, but it's gonna be such a crippled version of can be done.

    Ideally i would do something like this:
    I would create an array filled with all possible matchups identeficators and also containing count of games analyzed , count of wins, ratinginfo as 1 element. (max size is max possible matchup combinations, with different class specs it's around 1.5mil like explained above)
    Then sort it by identificator.
    Then go through a list of match id's of soloqgames writing statistics in the array (since the array is sorted it's easo to find the current matchup in the big array with log2(size) speed)

    Once done you go through the array now and if (averegerating(game)>2700 and (|rating(team1)-rating(team2)|<100) and totalgamescount>mingamesanalyzedamount and (winrate<(0.5-x) or winrate>(0.5+x))
    add the identificator to the new array of identificators.
    (i would suggest x=0.1 because 40:60 winrate is still viable and a lot of matchups should get into this category, and 67:33 is kind of too bad chances 2:1)
    Then sort the array of identificators and implement and use it in the algorithm i described above (Actually it's already gonna be sorted because the first array was sorted).
    Don't take lowrated games into the account.
    Although this leads to absence of any teams with rogues in the statistic, so you can do rating(player)>minratingrequired(playerclass) for every player
    instead of averegerating(game)>2700. and choose minratingrequired as the rating of top10 of each class in the ladder at the time of the procedure or something like that.

    Anyway, you can also manually add forbidden combs based on subjective opinion but i think that's a waste of potential.

    THE END.

    P.s. Now that i think of it forbidding matchups completely is not a very good option - additional rating change correction based on statistics is the way to go. The reason for this is as you forbid combs copletely, you can no longer keep statistics on them, and since armory most probably doesn't have any information on player specs, and with time people can invent new stratigies/improve that statistic can change and you have to constantly update it and thus forbidding matchups completely is bad here.
    Edited: February 24, 2017

  2. I can give you Solo Queue code if you want to take a look

  3. TLDR cba sorry and yes staff would ban and delete topic but fortunately u posted on blackrock forum so no1 will notice this ;)

    My version:

    1) SoloQ is the worst cancer ever invented, I tested it in every possible server and I can confirm 100% you loose only rating first of all, then patience, hope in humanity, braincells, and you can get several mental disorders and PTSD from playing too much that bracket.
    2) You are alone so you must cross your fingers and prey every divinity of every religion to find decent partners and most of all to NOT find counter-setups or mongoloid cleaves that have no clue about how to play but "dude rush that one with strangulate while i bladestoorm it should work lol, oh, our healer is afk... w/e it doesnt matter xddd".
    3) [skip this point if u play elemental/rsham or war or dk] You need to know when to stop. Every loss can potentially throw you in the 1350 pit and I swear God you will NEVER exit from there, until next season when mmr and team reset. Or if you DuoQ maybe you have a chance to escape, because the 1350 pit it's like a big cage full of brain damaged monkeys throwing **** each other all day long and laughing non stop for it. So it's better stay away, stay away from there. Its faster to delete the character and create another one from zero, trust me. This problem tho, affects only hard classes like Rogue (1st place obviously, tested multiple season), ferals, disci priests and more.
    4) SoloQ as already said is a cancer, this means its made by dangerous particles such as "DK", "WAR" and "Hpal". Keep in mind that the cancer keeps evolving, some particles mutated from "arms" to "protection", inceasing the amount of toxicity that you breath every single second.
    5) Keep also in mind that if you are a caster and you are against shaman+protection warrior sitting on you+random kicker you are allowed to leave arena istantly with no remorse, it's the best thing you can do and your brain will be thankful to you.
    6) It doesn't matter what class you play and if you have won or loss, what matters is you keep ALWAYS your status on <DND> when you SoloQ. If that isn't enough and you accuse some problems like headache, nervousism, anger, you can also tab to combat log and filter 100% the LFG and party channel. Again, your brain will be VERY thankful to you.

    In short: the soloq system is a total failure and a shame for the human intelligence, stay the hell away from it unless you:

    1) Have 2s and 3s partners offline and you're TOTALLY bored
    2) Want to troll people by entering naked in arena with 0 minutes of /played and 0 rating achieved in other brackets (because staff is very smart allowing this happening)
    3) Are a sick masochist with serious mental problems
    4) Play FOTM
    5) Play FOTM with scripts
    Edited: January 6, 2017

  4. Rip forum, dead AF
    or maybe it's my fault, lots of letters hurt your eyes. my apologies.

  5. waow, you must have been really ill. +1 that u survived.
    Rest is basically, more or less, rubbish. There's nothing wrong with SQ as it is. Rng can not be fully eliminated and their will always be comps that are better than others. Also, there's next to no TSG's around on decent ratings, because there are less than a handful good dk's playing in SQ every season.
    And not gonna bother explaining why, because i'm exhausted after reading 1/3 of your post.
    But it's just an opinion.

    THe major issue of SQ in my opinion, is dispels. Let's say you are a warlock or SP and you want to crowd control, which your class is extremely dependant on in order to win. WEll, good luck, when you're facing Hpala/Sp/ele. Or Hpala/lock/sp.
    It CAN be done, but usually not against decent players. That's just one example, there are plenty more ridiculous matchups.
    If i were to make one suggestion regarding SQ and balance, it would be: 1 team = max 1 magic dispel (and maybe also decurse)
    Edited: January 24, 2017

  6. come on, at least pay attention to this part
    First of all requeueing:
    Even before that mad turbommr change every 10 sec was made, it was quite bad, being forced to requeue every minute to not to get lower mmr, because i dont know how about most of the peasants here but i personnaly dont want to play with or against lower mmr. It is not only that i have to repeat this process every 20 seconds now, it's that you actually loose your higher position in queue when you do it. Thus comes the most simple change - create and option for people to choose a constant mmr range for them.

    So they can queue 1 time and wait until it pops while the queue system looks for enemies and partners in a given mmr range. Not completely given at players discretion but their soloqrating+100-soloq-100*n range where the player can only choose his personal n {ranges from 1 to whatever}.
    You can set it by default on 3 or 4 and add and option to change it ONLY ON THE QUEUEING NPC if you put it on the other npc nobody is gonna find it, half of the players will still not know about this feature half a year from now
    On the queueing npc it's almost impossible to miss additional option {first 2 options are 1) queue solo 2)queue as group or something}

  7. There are 2 issues (the first one is critical, the 2d is not that much): 1) the server is half-dead; 2) SQ is not MeleeCasterHealer. You can change mmr system, gear, bla bla - that's all isnt that much important as the previous 2 statements.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •