Php 如何从8名玩家中创建7轮的独特玩家组合

Php 如何从8名玩家中创建7轮的独特玩家组合,php,c++,c,algorithm,Php,C++,C,Algorithm,我有一个问题,并试图开发或使用一个算法来解决这个问题 我有8名球员,每个球员可以和其他球员组成7支独特的球队。一个队由两名队员组成 举个例子,, 假设所有玩家的名字都是 [A,B,C,D,E,F,G,H] 现在,从这8名球员中,我可以创建总共28个独特的团队组合 现在我想打7轮,每一轮他们都必须和一支独特的球队比赛 我尝试了循环算法,但它可以运行4轮。无法创建7轮 A B C D E F G H ROUND 1: AE, BF, CG, DH E A B C F G H D ROUN

我有一个问题,并试图开发或使用一个算法来解决这个问题

我有8名球员,每个球员可以和其他球员组成7支独特的球队。一个队由两名队员组成

举个例子,, 假设所有玩家的名字都是

[A,B,C,D,E,F,G,H]
现在,从这8名球员中,我可以创建总共28个独特的团队组合

现在我想打7轮,每一轮他们都必须和一支独特的球队比赛

我尝试了
循环算法
,但它可以运行4轮。无法创建7轮

A B C D
E F G H 

ROUND 1: AE, BF, CG, DH 

E A B C
F G H D

ROUND 2: EF, AG, BH, CD 

F E A B 
G H D C 

ROUND 3: FG, EH, AD, BC, 

G F E A 
H D C B

ROUND 4: GH, FD, EC, AB
我还需要用独特的球员组合再创造3轮


任何帮助都将不胜感激。谢谢。

为了保持最大的多样性,每个玩家都不应该与之前配对过的玩家配对。由于有8名球员和7轮,这意味着每个球员需要与其他球员进行一次精确的比赛。每轮4对

由于有8个玩家,我们可以将每个玩家表示为字节中的一位

Enum PlayerId : Byte {
    PLAYER_A = 1,
    PLAYER_B = 2,
    PLAYER_C = 4,
    PLAYER_D = 8,
    PLAYER_E = 16,
    PLAYER_F = 32,
    PLAYER_G = 64,
    PLAYER_H = 128
}

// player index to player id lookup
PlayerId _playerIds[] = { PLAYER_A, PLAYER_B, PLAYER_C, ... }
每个玩家有7对独特的配对,所有这些都将在游戏中看到。对于每一轮,我们需要4个这样的配对,没有冲突:即,所有玩家必须在所有这样的配对中只进行一次

我们将用图表来表示所有的可能性。我们将为每个可能的配对创建一个节点,并在节点之间创建彼此兼容的边(即,在玩家选择中没有冲突)

公共类配对图{
映射节点=新映射();
贴图边=新贴图();
PairingNode*AddPairing(播放器p1、播放器p2){
配对节点n(这个,p1,p2);
if(nodes.ContainsKey(n->id)){
抛出新异常(“重复玩家配对”);
节点[n->id]=n;
对于其他:节点{
如果(n->id&other->id)继续;
边->添加(新的PairingEdge(此、n、其他));
}
返回n;
}
布尔RemoveNode(字节id){
如果(!nodes.ContainsKey(id))返回false;
自动n=节点[id];
//首先删除此节点所属的所有边。
对于e:n->边{
如果(e->p1!=n){
e->p1->边缘。移除(e);
}否则{
e->p2->边缘。移除(e);
}
删除e;
}
节点。移除(n);
删除n;
返回true;
}
配对图(){
//使用所有播放器组合初始化图形
对于(int i=0;i<8;i++){
对于(int j=i+1;j<8;j++){
AddPairing(_playerIds[i],_playerIds[j]);
}
}            
}
}
公共类配对节点{
配对图*图;
列出边缘;
playeridp1;
playeridp2;
字节id;
PairingNode(PairingGraph*g,PlayerId p1,PlayerId p2){
如果(p1==p2)抛出新异常(“创建PairingNode需要两个不同的参与者”);
图=g;
这是1.p1=p1;
这是p2=p2;
this.id=p1 | p2;
}
}
公共类PairingEdge{
配对图*g;
配对节点*p1;
配对节点*p2;
字节id;
配对边(配对图*g,配对节点*p1,配对节点*p2){
如果(p1->id&p2->id)抛出新异常(“无法在共享玩家的PairingNode之间创建边”);
图=g;
这是1.p1=p1;
这是p2=p2;
this.id=p1->id | p2->id;
this.p1.edges.Add(this);
this.p2.edges.Add(this);
}
}
现在,我们可以用所有可能的组合构造一个配对图,我们创建配对的算法很简单:从图中随机选择并移除节点,附加的约束是移除的节点不会与先前为该轮选择的任何节点冲突

List<Tuple<PlayerId, PlayerId>>* SelectPlayersForRound(PairingGraph* g) {

    List<Tuple<PlayerId, PlayerId>> results = new List<Tuple<PlayerId, PlayerId>>;
    Byte restrictions = 0;

    // start by randomly selecting an intial node.
    int selection = rand(0, g->nodes->count -1);
    auto last_node = g->nodes[g->nodes->keys(selection)];
    restrictions |= n->id;
    selectedNodes.Add(n);

    // select the three other player pairs, informed from previous selections.
    for(int i = 1; i < 4; i++)
    {            
        // start by randomly selecting an edge from the last node
        // it necessarily won't conflict with the last_node, but may
        // not meet all restriction criteria
        int selection = rand(0, last_node->edges->count -1);

        // Grab the node on the opposite end of the selected edge
        auto e = last_node->edges[selection];
        auto next_node = (e->p1 == last_node)? e->p2 : e->p1;

        // If the node doesn't meet our current restrictions, try again.
        while(next_node->id & restrictions) {
            selection++;
            if(selection == last_node->edges->count) selection++;
            e = last_node->edges[selection];
            next_node = (e->p1 == last_node)? e->p2 : e->p1;
        }

        // Remove the last_node from the Graph
        g->RemoveNode(last_node->id);

        // update for next iteration
        last_node = curr_node;
        restrictions |= last_node->id;
    }

    // Remove the last_node from the Graph
    g->RemoveNode(last_node->id);

    return results;
}
List*selectsplayersforround(PairingGraph*g){
列表结果=新列表;
字节限制=0;
//从随机选择初始节点开始。
int selection=rand(0,g->nodes->count-1);
自动最后一个节点=g->nodes[g->nodes->keys(选择)];
限制|=n->id;
选择的节点。添加(n);
//根据之前的选择,选择其他三对玩家。
对于(int i=1;i<4;i++)
{            
//从最后一个节点随机选择一条边开始
//它必然不会与最后一个_节点冲突,但可能会发生冲突
//不符合所有限制条件
int selection=rand(0,最后一个节点->边->计数-1);
//抓住选定边另一端的节点
自动e=最后一个节点->边[选择];
自动下一个节点=(e->p1==最后一个节点)?e->p2:e->p1;
//如果节点不符合我们当前的限制,请重试。
while(下一个节点->id和限制){
选择++;
如果(选择==最后一个节点->边->计数)选择++;
e=最后一个节点->边[选择];
下一个节点=(e->p1==最后一个节点)?e->p2:e->p1;
}
//从图形中删除最后一个_节点
g->RemoveNode(最后一个节点->id);
//为下一次迭代更新
最后一个节点=当前节点;
限制|=最后一个节点->id;
}
//从图形中删除最后一个_节点
g->RemoveNode(最后一个节点->id);
返回结果;
}
只需为每一场游戏创建一个新的配对图,并为每一轮调用SelectPlayers,您就完成了

请注意,这只是一些psuedo代码(因为您没有指定语言),并且还没有经过测试。希望对您有所帮助:)

编辑:您已经在帖子中添加了一些语言。我的PSUEDO代码或多或少是C++的,因此您应该能够轻松地为您的目的复制修改。 EDIT2:改进了选择例程,以利用最后一个节点的兼容边列表(减少潜在冲突)

EDIT3:修复了一些条件逻辑
List<Tuple<PlayerId, PlayerId>>* SelectPlayersForRound(PairingGraph* g) {

    List<Tuple<PlayerId, PlayerId>> results = new List<Tuple<PlayerId, PlayerId>>;
    Byte restrictions = 0;

    // start by randomly selecting an intial node.
    int selection = rand(0, g->nodes->count -1);
    auto last_node = g->nodes[g->nodes->keys(selection)];
    restrictions |= n->id;
    selectedNodes.Add(n);

    // select the three other player pairs, informed from previous selections.
    for(int i = 1; i < 4; i++)
    {            
        // start by randomly selecting an edge from the last node
        // it necessarily won't conflict with the last_node, but may
        // not meet all restriction criteria
        int selection = rand(0, last_node->edges->count -1);

        // Grab the node on the opposite end of the selected edge
        auto e = last_node->edges[selection];
        auto next_node = (e->p1 == last_node)? e->p2 : e->p1;

        // If the node doesn't meet our current restrictions, try again.
        while(next_node->id & restrictions) {
            selection++;
            if(selection == last_node->edges->count) selection++;
            e = last_node->edges[selection];
            next_node = (e->p1 == last_node)? e->p2 : e->p1;
        }

        // Remove the last_node from the Graph
        g->RemoveNode(last_node->id);

        // update for next iteration
        last_node = curr_node;
        restrictions |= last_node->id;
    }

    // Remove the last_node from the Graph
    g->RemoveNode(last_node->id);

    return results;
}