c - 从文本文件中随机配对团队两次

标签 c random readfile

我对C编程相当陌生,我正在尝试完成这个随机配对程序,但在启动它时遇到问题。基本上,该程序需要从文本文件中读取 3 个字母的团队名称,将它们放入一个数组中,然后随机将团队相互配对。比赛共两轮,第二轮不能重赛。此外,来自同一学校的球队不能互相比赛。来自同一学校的团队在文本文件中共享相同的第一个字符和行。谁能帮助我如何编写这个代码? :) 这是名为 Provisions.txt 的文本文件:

ABA ABC ABD ABG
BAA BAB BAC
CAB CBA
DAB DBC DBE DBA
EAB
FAB FAC FAA
GAB GAA
HAA HAB
IAB
JAA
KAA
LAL LAB
MAA MAB MBA MUM
NAN NAB

到目前为止我的代码是:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>

int main()
{
// Read characters from text file into array
FILE *file = fopen("provision.txt", "r");

char teamList[115];
char teams[32][4];  // Holds team names
int i;

for(i = 0; i < 32; i++){
    fscanf(file, "%s", teams[i]);
}

for(i = 0; i < 32; i++){
        printf("%s \n", teams[i]);  // Test to make sure teams are read in
}

// Clean up
fclose(file);

return 0;
}

如果可能,我想将两轮的输出存储在名为 round1_pairings.txt 和 round2_pairings.txt 的文本文件中。

最佳答案

该程序试图解决一些微妙的问题,例如随机选择偏差、退出死胡同尝试等。如果由于来自团队不足而导致给定回合无法配对,则不保证终止。其他学校,这种情况更有可能发生在轮数较多的情况下(不太可能只有两轮和许多学校)。

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define NAMELEN 3
#define ROUNDS 2
#define RETRIES 10 // max attempts before restarting matching                                                           

#define STR_HELPER(x) #x // http://stackoverflow.com/a/5459929/4323                                                     
#define STR(x) STR_HELPER(x)
#define NAMEPRINTF "%" STR(NAMELEN) "s"

typedef char team_t[NAMELEN + 1];

typedef struct
{
    team_t team;
    team_t opponents[ROUNDS];
} pairing_t;

// the first round is round=0                                                                                           
// when round>0, prior round matches will be prevented from recurring                                                   
void make_matches(pairing_t* pairings, size_t count, size_t round)
{
    // clip random() range to avoid bias toward first teams                                                             
    long randmax = LONG_MAX - LONG_MAX % count - 1;
  begin:
    for(size_t ii = 0; ii < count; ++ii) {
        if(pairings[ii].opponents[round][0]) continue; // already paired                                                
        //printf("matching: %s\n", pairings[ii].team);                                                                  
        unsigned retry = 0;
        while(retry < RETRIES) {
            long rand = random();
            if (rand > randmax) continue; // avoid bias                                                                 
            pairing_t *opp = &pairings[rand % count];
            if(opp->team[0] == pairings[ii].team[0]) { // same school                                                   
                ++retry;
                continue;
            }
            if(opp->opponents[round][0]) continue; // already paired                                                    
            size_t prior;
            for(prior = 0; prior < round; ++prior) {
                if(!memcmp(opp->team, pairings[ii].opponents[prior], sizeof(team_t))) {
                    break;
                }
            }
            if(prior != round) continue; // duplicate pairing                                                           
            //printf("match made: %s %s\n", opp->team, pairings[ii].team);                                              
            memcpy(pairings[ii].opponents[round], opp->team, sizeof(team_t));
            memcpy(opp->opponents[round], pairings[ii].team, sizeof(team_t));
            break;
        }
        if(retry == RETRIES) { // matching failed, start again                                                          
            for(size_t ii = 0; ii < count; ++ii) {
                memset(pairings[ii].opponents[round], 0, sizeof(team_t));
            }
            goto begin;
        }
    }
}

int main(void)
{
    srandom(time(NULL));

    FILE *file = fopen("provision.txt", "r");

    size_t capacity = 15; // arbitrary initial size                                                                     
    pairing_t *pairings = calloc(capacity, sizeof(pairing_t));
    if(!pairings) abort();

    size_t count = 0;
    while(fscanf(file, NAMEPRINTF, pairings[count].team) != EOF) {
        //printf("%s\n", pairings[count].team);                                                                         
        ++count;
        if(count >= capacity) { // expand array                                                                         
            capacity *= 2;
            pairings = realloc(pairings, capacity * sizeof(pairing_t));
            if(!pairings) abort();
            memset(&pairings[count], 0, (capacity - count) * sizeof(pairing_t));
        }
    }

    for(size_t round = 0; round < ROUNDS; ++round) {
        make_matches(pairings, count, round);
    }

    for(size_t ii = 0; ii < count; ++ii) {
        printf("%s %s %s\n", pairings[ii].team, pairings[ii].opponents[0], pairings[ii].opponents[1]);
    }

    free(pairings);
    fclose(file);
    return 0;
}

输出是一个简单的表格,包含三列:参加比赛的球队、他们的第一个对手和他们的第二个对手。我相信您可以弄清楚如何根据需要将它们写入单独的文件。

关于c - 从文本文件中随机配对团队两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37127745/

相关文章:

c - 如何在 C 中的 fork 进程中查找共享/复制的内存页

c - 如何从 malloc 区域执行一段代码

c++ - 创建一个函数以返回指定范围内的随机数

C 程序错误地读取文件

c - 解析由逗号分隔的表 txt 文件组成的数组

c - 结构没有命名的成员

mysql - 如何使用 group by 子句选择随机行?

javascript - jQuery Orbit - 如何制作随机幻灯片?

c - 从 ReadFile 中检测错误数据

windows - 当文件禁用读取共享时如何使用 ReadFile 读取数据