PHP: сортировка командных турниров по нескольким атрибутам - PullRequest
1 голос
/ 29 апреля 2011

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

  • командных очка (3 * победа в матче + 1 * ничья)
  • конфронтационная команда (не уверен, что это правильное слово, но я имею в виду матчи между одинаковыми командами, т.е. если две команды имеют одинаковые очки, но одна была побеждена другой, победившая будет выше проигравшей)
  • разница мячей (забитый гол-забитый гол)
  • забитый гол
  • в алфавитном порядке

Данные для построения этой модели извлекаются с помощью различных запросов к базе данных, и структура, которую я сейчас использую для их сохранения, представляет собой массив таких объектов:

  • TeamID
  • сыгранных матчей
  • выигранных матчей
  • проигранных матчей
  • спички
  • точка
  • забитый гол
  • цель достигнута
  • разница мячей
  • команд, которые потерпели поражение в текущем = массив (teamId1, teamId2 ...)
  • команд, которые победили текущий = массив (teamId1, teamId2 ...)
  • команд, которые имели связь с текущим = массив (teamId1, teamId2 ...)

Для большинства атрибутов сортировки я могу использовать функцию php array_multisort и выполнить работу, но проблема заключается в конфронтации команды. В качестве примера, скажем, у меня есть такая ситуация:

  • Команда A - 3 очка - выиграл у D
  • Команда B - 3 очка - выиграл у D
  • Команда C - 3 очка - выиграл у A
  • Команда D - 0 очков - выиграл у D

В этом случае у меня есть команда C, которая должна остаться выше A, так как C победила A, а я должен проверить разницу мячей (следующий атрибут в заказе), чтобы определить позицию B по сравнению с B и C. Я пытаюсь разработать алгоритм, способный решить эту проблему с любой конфигурацией атрибутов, но пока не повезло. У кого-нибудь есть предложения? Большое спасибо и простите меня, если я не был ясен

Ответы [ 2 ]

1 голос
/ 02 мая 2011

то, что вы называете конфронтацией команд, фактически является новой таблицей, рассчитанной для команд, которые набирают одинаковые очки, используя только игры между ними. Эта проблема превращается в особенно неприятную ситуацию, когда у вас есть 3 или более команд, привязанных по точкам, и в этом случае вы не можете отсортировать таблицу позиций, используя сравнения один к одному (что и делают все алгоритмы сортировки), так как вам нужно знать другие команды привязан к созданию вашей подстолицы. Вам нужно будет создать функцию, которая дает список матчей и список команд, которые генерируют вашу таблицу позиций для этих команд, отсортированную с учетом только очков. Перед возвратом таблицы позиций проверьте, существуют ли группы с одинаковыми точками, и замените этот раздел таблицы результатом рекурсивного вызова со всеми совпадениями, но только с командами в связанных группах. Обязательно остановите рекурсию, когда вся таблица завязана, иначе вы получите бесконечный цикл, в этом случае примените глобальную разницу между целями, забитые и алфавитные цели.

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

0 голосов
/ 02 октября 2016

@ ilcavero совершенно верно.

Я реализовал нечто похожее на это. В моем коде предполагается, что разрешающие связи типа «конфронтация» не могут быть запущены, если (а) все игроки не сыграли друг с другом и (б) один игрок не выиграл все матчи или один игрок не проиграл все матчи между связанными командами.

Это утверждение if позволяет избежать таких проблем:

  • Алиса победила Боба
  • Боб бил Карла
  • Карл победил Алису

Алиса должна быть впереди Боба и позади Карла. Боб должен быть впереди Карла и позади Алисы, но Алиса должна быть позади Карла. Это ломает. Это также позволяет избежать наказания или вознаграждения кого-либо за матч, в котором он не играл.

Код разрешает связи, которые выглядят следующим образом:

  • Алиса победила Боба
  • Алиса победила Карла
  • Карл победил Боба

Сначала мы можем удалить Алису, которая победила других игроков, и расположить ее над связанными командами:

  1. Алиса
  2. Боб и Карл

Поскольку Боб проиграл Карлу, мы можем снять его с галстука и поместить его в позицию под галстуком (который в этот момент был бы просто Карлом). Разрешение на:

  1. Алиса
  2. Карл
  3. Bob

Я сохраняю ранжирование в такой структуре, как при сортировке ($ this-> sortedTeams):

[
  1 => [$id => $team, $id => $team, $id = $team], // 3 teams tied for first position.
  4 => [$id => $team], // One team in 4th position.
  5 => [$id => $team, $id => $team] // 2 teams tied in 5th position.
]

Вот код в моем классе TeamSorter, который имеет дело с личным сравнением:

  private function headToHead() {
    foreach ($this->findTies() as $position)
      $this->headToHeadThisPosition($position);
    ksort($this->sortedTeams);
  }

  private function headToHeadThisPosition($position) {

    // Teams that are tied.
    $teams = $this->sortedTeams[$position];

    // Every team must play every other team, or head to head doesn't work.
    if (!$this->tiedTeamsHaveAllPlayedEachother($teams)) return; 

    // If we have a winner, it assumes $position, and other(s) assume
    // $positon + 1, moving away from first place.
    if ($winner_nid = $this->tiedPositionHasWinner($teams))
      $position = $this->removeFromTie('winner', $winner_nid, $position);

    // If we have a loser, it assumes $position + 1 (moving away from first
    // place), other(s) stay at $position.
    if ($loser_nid = $this->tiedPositionHasLoser($teams))
      $this->removeFromTie('loser', $loser_nid, $position);

    // Recursively call this function if we might resolve a tie at $position
    // before going on to the next position.
    if ($this->recursionNeeded($position))
      $this->headToHeadThisPosition($position);
  }

  private function recursionNeeded($position) {
    $teams = $this->sortedTeams[$position];
    return
      count($this->sortedTeams[$position]) > 1
      &&
      $this->tiedTeamsHaveAllPlayedEachother($this->sortedTeams[$position])
      &&
      $this->tiedPositionHasWinner($this->sortedTeams[$position]);
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...