【问题标题】:How to dynamically generate possible encounters between teams?如何动态生成团队之间可能的遭遇?
【发布时间】:2020-11-23 05:16:43
【问题描述】:

感谢您在此练习中提前提供的帮助,其中的真相我还没有发现如何解决它

如何动态生成团队之间可能的遭遇?

具有以下输入字段

  • 开始日期
  • 团队
  • 字段
  • 玩几天

以以下数据为例

const startDate = "03-08-2020";
const teams = ["A", "B", "C", "D", "E", "F"];
const fields = ["Field1", "Field2"];
const daysToPlay = ["Monday", "Wednesday"];

现在,我需要根据这些数据动态生成比赛日及其比赛匹配,比赛场地必须像从日期到日期的日期一样互换。从 startDate 值开始

输出示例如下

const output = [
    {
        number: 1,
        date: "03-08-2020", // Monday
        field: "Field1",
        matches: [
            ["A", "B"],
            ["C", "D"],
            ["E", "F"],
        ],
    },
    {
        number: 2,
        date: "05-08-2020", // Wednesday
        field: "Field2",
        matches: [
            ["A", "C"],
            ["B", "E"],
            ["C", "F"],
        ],
    },
];

以这种方式,根据团队之间唯一可能遇到的次数。

更新 0

  • 所有球队必须在每个日期参加比赛
  • 团队数量总是偶数
  • 比赛在每支球队都与其他球队交手后结束,

更新 1

我遵循 Oliver 的建议,但在最后一组比赛中我得到了一场比赛,这里我期待两场比赛像以前的比赛一样

const teams = ["A", "B", "C", "D"];

const getCombinations = (data) => {
  let output = [];

  for (let i = 0; i < teams.length - 1; i++) {
    for (let j = i + 1; j < teams.length; j++) {
      output = [...output, [data[i], data[j]]];
    }
  }

  return output;
};

const getMatches = (data) => {
  let matches = [];
  let i = 0;

  while (data.length) {
    for (const [index, entry] of data.entries()) {
      if (index === 0) {
        matches.push([entry]);

        data.splice(index, 1);

        continue;
      }

      const [team1, team2] = entry;
      const idx = matches[i].findIndex(
        (value) => value.includes(team1) || value.includes(team2)
      );

      if (idx !== -1) {
        continue;
      }

      matches[i].push(entry);
      data.splice(index, 1);
    }

    i++;
  }

  return matches;
};

const combinations = getCombinations(teams);
const matches = getMatches(combinations);

console.log(matches);

更新 2

修复之前的更新

const teams = ["A", "B", "C", "D"];

const getCombinations = (data) => {
  let output = [];

  for (let i = 0; i < teams.length - 1; i++) {
    for (let j = i + 1; j < teams.length; j++) {
      output = [...output, [data[i], data[j]]];
    }
  }

  return output;
};

const getMatches = (data) => {
  let matches = [];
  let i = 0;

  while (data.length) {
    for (const [index, entry] of data.entries()) {
      if (data.length === 1) {
        matches[i - 1].push(entry);
        data.splice(index, 1);
        break;
      }

      if (index === 0) {
        matches.push([entry]);

        data.splice(index, 1);
        continue;
      }

      const [team1, team2] = entry;
      const idx = matches[i].findIndex(
        (value) => value.includes(team1) || value.includes(team2)
      );

      if (idx !== -1) {
        continue;
      }

      matches[i].push(entry);
      data.splice(index, 1);
    }

    i++;
  }

  return matches;
};

const combinations = getCombinations(teams);

console.log(combinations);

const matches = getMatches(combinations);

console.log(matches);

更新 3

我快到了

我在执行与日期相关的任务时遇到问题,如何获得正确的日期。为了使解决方案更容易,我设法通过一周中的天数而不是日期的名称来更改游戏日的输入,这样

Sunday 0
...
Saturday 6

在示例中,日期对应于Monday (1) 和星期三(3)

感谢您的评论

const startDate = "2020-08-03";
const matchDays = [1, 3];
const fields = ["Field 1", "Field 2"];
const teams = ["A", "B", "C", "D"];

const getCombinations = (data) => {
  let output = [];

  for (let i = 0; i < teams.length - 1; i++) {
    for (let j = i + 1; j < teams.length; j++) {
      output = [...output, [data[i], data[j]]];
    }
  }

  return output;
};

const getMatches = (data) => {
  let matches = [];
  let i = 0;

  while (data.length) {
    for (const [index, entry] of data.entries()) {
      if (data.length === 1) {
        matches[i - 1].push(entry);
        data.splice(index, 1);
        break;
      }

      if (index === 0) {
        matches.push([entry]);

        data.splice(index, 1);
        continue;
      }

      const [team1, team2] = entry;
      const idx = matches[i].findIndex(
        (value) => value.includes(team1) || value.includes(team2)
      );

      if (idx !== -1) {
        continue;
      }

      matches[i].push(entry);
      data.splice(index, 1);
    }

    i++;
  }

  return matches;
};

const getGameDays = (data) => {
  const options = {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  };

  return data.map((entry, index) => {
    return {
      number: index + 1,
      date:
        index === 0
          ? new Date(startDate).toLocaleDateString("es-ES", options)
          : new Date(startDate).toLocaleDateString("es-ES", options), // Here I need to move on every target day of week in matchDays
      field:
        fields.length === 1
          ? fields[0]
          : index === 0
          ? fields[0]
          : index % 2 === 0
          ? fields[0]
          : fields[1],
      matches: [...entry],
    };
  });
};

const combinations = getCombinations(teams);

console.log(combinations);

const matches = getMatches(combinations);

console.log(matches);

const gameDays = getGameDays(matches);

console.dir(gameDays, { depth: null, color: true });

此时设置每天的开始日期

谢谢

【问题讨论】:

  • 请发布您迄今为止为实现这一目标所做的尝试。
  • 在这个特殊的任务中,我不知道如何开始。我想如果我知道团队可能组合的数量,我就可以知道每天的日期。但我不知道如何获取这些信息
  • 要从您需要数组中的项目组合的地方开始,请关注:stackoverflow.com/questions/43241174/…
  • 这里有几项任务要完成,感觉缺少很多约束。我想到的一些问题是:“一个场地每天可以打多少场比赛?”,“比赛将如何安排(锦标赛,循环赛,复赛)?”,“多少场比赛?单支球队可以玩一天吗?”。所以对我来说,为这个问题提供一个真正的答案似乎很不完整。我认为你只会得到一些关于组合学的知识,就是这样。
  • 你说得对,我会更新问题

标签: javascript


【解决方案1】:

似乎是https://github.com/dankogai/js-combinatorics 的工作。

在这里,您必须创建大小为 2 (new Combination(teams, 2);) 的所有组合。现在你得到了所有的组合(如果你有重新匹配,你可以用new Combination(teams.reverse(), 2);创建它们。

现在持有一个teamsPlayedToday 的(空)数组,从组合中选择第一个条目,将其添加到当日比赛中,将球队添加到上述数组中并将其从组合列表中删除。

在下一步中,从组合中选择下一个条目,检查 teamsPlayedToday 列表中是否提到了任何团队,如果是,则跳到下一个组合,直到找到一个在今天列表中没有团队的组合。

当您到达终点时,您就有了第 1 天的计划。每天重复上述步骤,直到您的组合列表为空。

从给定的开始日期,输入new Date()和方法getDay()你应该能够找出startDate的值。

如果此草图中的任何内容不起作用,请使用您的具体代码以及您期望什么以及您得到什么提出一个新问题。

获取有效日期的更新

要从给定的开始日期和允许的工作日获取可以玩的天数列表,您可以使用以下内容:

// Taken from https://stackoverflow.com/a/19691491/1838048
function addDays(date, days) {
  var result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

// Proof-of-concept without argument checks (could lead to endless loops!)
function getMatchingDays(startDate, allowedDays, maxCount) {
  const matchingDays = [];
  let current = startDate;

  while (matchingDays.length < maxCount) {
    if(allowedDays.find(day => day === current.getUTCDay())){
      matchingDays.push(current);
    }

    current = addDays(current, 1);
  }

  return matchingDays;
}

// Given start values
const startDate = "2020-08-03";
const daysToPlay = [1, 3];
// Could come from your matches.length array
const numberOfMatches = 13;

const result = getMatchingDays(new Date(startDate), daysToPlay, numberOfMatches);
console.log(result);

【讨论】:

  • 感谢您回答 Oliver,我正在尝试实现您共享的逻辑,直到相关日期,您能否查看我正在共享的更新。我在最后一组比赛中遇到了意外的行为
  • 再次感谢奥利弗。我一直在测试并且逻辑运行良好,只是在我的时区而不是从 8 月 3 日开始计算,示例从同月 04 日开始计算。任何想法我该如何处理?谢谢
  • 它现在可以工作了,我在本地将 current.getDay() 更改为 current.getUTCDay() @按预期返回1。我会用最终结果更新答案。
  • 很高兴看到我的草图可以提供帮助。使用 UTC 确实可以更好地避免时区变化(特别是如果时间是午夜并导致白班)。还要注意缺少对传入参数的检查。如果allowedDays 是一个空数组或只包含不是从零到六的数字的东西,它将无限运行。
【解决方案2】:

const startDate = "03-08-2020";
const teams = ["A", "B", "C", "D", "E", "F"];
const fields = ["Field1", "Field2"];
const daysToPlay = ["03-08-2020", "05-08-2020"]; // use raw value, and format when displaying
let output = []


function matchmaking() {
  
  const games = []
  // 15 games in total, (n^2 + n) / 2
  for (let i = 0; i < teams.length - 1; i++) {
    for (let k = 0; k < teams.length - i - 1; k++) {
      const left = teams[k]
      const right = teams[k + i + 1]
      games.push([left, right])
    }
  }
  
  const availableFields = fields.length
  const fieldGames = Math.floor(games.length / availableFields)
  
  // 15 / 2 !== 7
  const leftOvers = games.length % availableFields

  for (let i = 0; i < availableFields; i++) {
    output.push({
      number: i + 1,
      date: daysToPlay[i],
      field: fields[i],
      matches: games.slice(i * fieldGames, (i + 1) * fieldGames),
    })
  }
  // add leftOvers to latest date, or earliest
  const leftOverGames = games.slice(availableFields * fieldGames, availableFields * fieldGames + leftOvers)
  output[output.length - 1].matches = output[output.length - 1].matches.concat(leftOverGames)
  
  console.log(output)
  return output
}

matchmaking()

考虑未来的数据结构:fields和daysToPlay可以组合成一个实体——fieldSlot,它可以包含时隙和field id。例如daysToPlay 对上述演示代码没有数据结构影响。

【讨论】:

    猜你喜欢
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 2012-02-19
    • 2021-01-31
    相关资源
    最近更新 更多