Алгоритм планирования футбольного матча - PullRequest
0 голосов
/ 04 ноября 2019

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

  1. Четное количество команд
  2. Один сезон состоит из 2 туров
  3. В один игровой денькаждая команда играет ровно в одном матче
  4. Домашние команды в предыдущем игровом дне должны быть командой на выезде в следующем игровом дне (если это возможно - я посмотрел на матчи серии А, и есть исключение из этого правила - каждая команда играет 2 разаподряд (дома / гости - первый раунд / раунд мести) за один сезон
  5. Есть 2 раунда, и правило таково: первый матч в первом раунде (день 1) команда A играет с командой B(A: B), так что матч мести B: A должен состояться в - игровой день allMatchDays/2 + i, где i = 1

Текущий подход:


  private static Map<Integer, List<Match>> createSchedule(/*Set<Team> allTeams*/) {

    Set <Team> allTeams = Set.of(

            Team.builder().name("A").build(),
            Team.builder().name("B").build(),
            Team.builder().name("C").build(),
            Team.builder().name("D").build(),
            Team.builder().name("E").build(),
            Team.builder().name("F").build(),
            Team.builder().name("G").build(),
            Team.builder().name("H").build(),
            Team.builder().name("I").build(),
            Team.builder().name("J").build()

    );

    int teamsNumber = allTeams.size();
    int matchDays = (teamsNumber - 1) * 2;
    int gamesNumberPerMatchDay = teamsNumber / 2;

    List<Match> allMatches = allTeams.stream()
            .map(team ->
                    allTeams.stream().filter(otherTeam -> !otherTeam.equals(team))
                            .map(otherTeam -> Match.builder().homeTeam(team)
                                    .awayTeam(otherTeam).build()).collect(Collectors.toList())
            )
            .flatMap(Collection::stream)
            .collect(Collectors.toList());

    Map<Integer, List<Match>> schedule = IntStream.rangeClosed(1, matchDays)
            .boxed()
            .collect(Collectors.toMap(
                    matchDay -> (Integer) matchDay,
                    matchDay -> new ArrayList<>()));

    Set<Team> homeTeamsInCurrentMatchDay = new HashSet<>();
    List<Team> teamsScheduledForCurrentMatchDay = new ArrayList<>();

    /*matchDay*/
    for (int i = 1; i <= matchDays / 2; i++) {

        List<Team> homeTeamsInPreviousMatchDay = new ArrayList<>(homeTeamsInCurrentMatchDay);
        homeTeamsInCurrentMatchDay.clear();

        /*match number in current Matchday*/
        for (int j = 1; j <= gamesNumberPerMatchDay; j++) {

            /*first match*/

            Match match = drawMatch(allMatches, teamsScheduledForCurrentMatchDay, homeTeamsInPreviousMatchDay);

            allMatches.remove(match);

            schedule.get(i).add(match);

            homeTeamsInCurrentMatchDay.add(match.getHomeTeam());

            teamsScheduledForCurrentMatchDay.add(match.getHomeTeam());
            teamsScheduledForCurrentMatchDay.add(match.getAwayTeam());

            /*revenge match*/

            Match revengeMatch = Match.builder().homeTeam(match.getAwayTeam()).awayTeam(match.getHomeTeam()).build();

            schedule.get((matchDays / 2) + i).add(revengeMatch);

            allMatches.remove(revengeMatch);

        }
        teamsScheduledForCurrentMatchDay.clear();
    }

    return schedule;
}

private static Match drawMatch(List<Match> matches, List<Team> alreadyScheduledTeamsInCurrentMatchDay, List<Team> homeTeamsInPreviousMatchDay) {


    List<Match> possibleMatches = matches.stream()
            .filter(match -> !alreadyScheduledTeamsInCurrentMatchDay.contains(match.getHomeTeam()) && !alreadyScheduledTeamsInCurrentMatchDay.contains(match.getAwayTeam()))
            .collect(Collectors.toList());

    List<Match> possibleMatchesWithExclusionOfHomeTeams = new ArrayList<>(possibleMatches);

    possibleMatchesWithExclusionOfHomeTeams.removeIf(match -> homeTeamsInPreviousMatchDay.contains(match.getHomeTeam()));

    if (possibleMatchesWithExclusionOfHomeTeams.size() != 0) {
        possibleMatches = new ArrayList<>(possibleMatchesWithExclusionOfHomeTeams);
    }

    int randomNumber = new Random().nextInt(possibleMatches.size());
    return possibleMatches.get(randomNumber);
}

Чертежи команды и матча:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
class Team {
    String name;
}


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class Match {

    private Team homeTeam;
    private Team awayTeam;
}

Алгоритм не работает.

Исключение в потоке "main" java.lang.IllegalArgumentException: привязка должна бытьположительный

выбрасывается - это означает, что для некоторыхВ туре для какой-то команды есть 0 возможных матчей, которые соответствуют правилам, перечисленным в начале. Я не уверен, что мне здесь не хватает и как должен выглядеть алгоритм расписания, чтобы отразить настоящий алгоритм. Другими словами, почему possibleMatches.size() когда-либо оказывается 0 и какие исправления должны быть сделаны для правильной работы этого алгоритма?

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