Как динамически генерировать возможные встречи между командами? - PullRequest
2 голосов
/ 03 августа 2020

Заранее благодарен за вашу помощь в этом упражнении, правда, я не обнаружил, как его решить

Как динамически генерировать возможные столкновения между командами?

Имея следующие поля ввода

  • дата начала
  • команды
  • поля
  • дни для игры

Например, со следующими данными

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

Я следую предложению Оливера, но в последнем наборе совпадений я получаю одно совпадение, здесь я ожидаю два совпадает как и предыдущие

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 });

В это время установите дату начала для каждого дня

Спасибо

Ответы [ 2 ]

2 голосов
/ 03 августа 2020

Кажется, это работа для https://github.com/dankogai/js-combinatorics.

Здесь вам нужно создать все комбинации с размером 2 (new Combination(teams, 2);). Теперь у вас есть все комбинации (если у вас есть повторные матчи, вы можете создать их с помощью new Combination(teams.reverse(), 2);.

Теперь удерживайте (пустой) массив teamsPlayedToday, выберите первую запись из комбинаций, добавьте ее в день совпадения, команды в вышеупомянутый массив и удалите его из списка комбинаций.

На следующем шаге выберите следующую запись из комбинаций, проверьте, указана ли какая-либо команда в списке teamsPlayedToday и если да, переходите к следующей комбинации, пока не найдете ту, в которой нет ни одной команды в сегодняшнем списке.

Когда вы дойдете до конца, у вас будет план на день 1. Повторяйте шаги, указанные выше, для каждого дня, пока не начнете. список комбинаций пуст.

С указанной даты начала введите new Date() и метод getDay() вы сможете узнать значение для startDate.

Если что-то из этого скетча не работает, задайте новый вопрос с вашим конкретным кодом, с тем, что вы ожидаете и что у вас есть.

Обновление для получения действительных дат

Чтобы ge t от заданной даты начала и разрешенных дней недели список дней для игры, вы можете использовать что-то вроде этого:

// 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);
1 голос
/ 03 августа 2020

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()

Учитывайте структуру данных на будущее: поля и daysToPlay можно объединить в одну сущность - fieldSlot, которая может содержать временные интервалы и идентификаторы полей. Для примера, daysToPlay не влияет на структуру данных в приведенном выше демонстрационном коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...