2008年9月14日日曜日

リーグ戦スケジューラー

個人的に参加している某ゲームの対戦会用に、リーグ戦のスケジューラーを作りました。
メッセとかに貼り付けれるように、リーグ表とか順位表とかも表示するようにしています。
以下がそのイメージ












巷では.Netがはやってそうですが、知らないのでMFCを使用。


デバッグは5~12人まで目視で行いました。
それ以上、以下はしていないのでミスがあるかも。

アルゴリズムとしては
-------------------------------------------------------------
1:まず奇数人数の場合、1人ダミーの人を入れて偶数人数化します。(後でダミーと当った対戦は除外)
2:A vs B で左の人をホスト、右の人をクライアントと呼ぶ
3:各回戦ごとにホスト基準で対戦相手を検索開始する。
4:検索順は A~F の6人の場合 A>B>C>F>E>D となる、 注意するのは(人数/2)を超えた場合最後の人から戻ってくるような検索の仕方に変わること。
5:基準のホストが決まったら次に対戦相手のクライアントを探して行く。
6:この時 クライアント候補は F>E>D>C>B>A>F>E... と 1回戦内でループしていき、対戦相手が決まったら、次に相手を決定するホストは直前のホストの相手-1の位置にいる相手から検索を始める。
7:例えば、最初の試合が A vs Fになった場合、 次にホストとなったBはEから検索を始める。
8:対戦相手が決まらなかった場合、クライアント検索開始位置は変わらず、4に戻る


プログラムソース的には 以下を回戦数分繰り返す。というか試合数が最大になる回戦まで繰り返す
int mMemberNum = x; // グループ人数
int client = mMemberNum- 1; // クライアント候補の人のID
bool roundCache[mMemberNum]; // 各ラウンドごとに対戦相手が決定したかどうかを表すフラグ
int league[mMemberNum * mMemberNum] // 各対戦情報を管理する配列
int roundCount; // N回戦をあらわす
for( int hostCount = 0; hostCount < (mMemberNum); hostCount++ )
{
     int host = hostCount;
    // ホスト位置が半分を超えたら、最後の人から逆方向にホスト位置をずらしはじめる
     if( host >= (mMemberNum)/2 ) host = (mMemberNum-1) - (host-mMemberNum/2);
    // ホスト候補の人が既に対戦が決定している
    if( roundCache[host] ) continue;

    for( int count = 0; count < (mMemberNum); client = (client - 1 + mMemberNum) % mMemberNum, count++ )
    {
        // クライアント候補が自分なら飛ばす
        if( host == client ) continue;
        // その人が対戦相手決定済みなら飛ばす
        if( roundCache[client] ) continue;
        // すでにクライアント候補の人とは対戦している場合は飛ばす
        if( league[(host *mMemberNum) + client] != -1 ) continue;
        // 対戦情報を設定
        league[(host *(mMemberNum+gisou)) + client] = roundCount;
        league[(client *(mMemberNum+gisou)) + host] = roundCount;
        roundCache[host] = true;
        roundCache[client] = true;

        break;
    }
}


--------------------------------------------------------------

無理やりな思いつきのアルゴリズムだからかなり穴があるかもしれない。