Улучшение алгоритма для пары игроков - слишком много дублирующего кода - PullRequest
0 голосов
/ 20 октября 2019

У меня есть игроки. Игроки получили предпочтительную позицию. У нас есть 3 позиции - DEFENDERS, ATTACKERS, BOTH (игроки, которые хороши на обеих позициях). Мне нужно создать команды из двух человек. Сопряжение игроков должно быть таким: «Атакующий должен быть в паре с защитником или теми, кто может играть на обеих позициях. Конечно, те, кто чувствует себя комфортно на обеих позициях, могут играть друг с другом в команде. Два защитника или два атакующихболее слабые, чем другие комбинации, поэтому должны быть согласованы таким образом, только когда нет других вариантов. "

Я написал что-то подобное. Я знаю, что это наивная реализация, но не смог найти лучшего способа сделать это.

Сначала я сортирую игроков по их позициям, поэтому у меня есть 3 списка. Затем, используя цикл while, я имею дело с сначала атакующими, затем защитниками, затем атакующими / защитниками. Есть ли способ улучшить это? Если нет, я хотел бы знать, как я могу извлечь дублированный код в метод.

package foostour.app;

import foostour.app.model.Player;
import foostour.app.model.Team;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

class TeamScheduler {

    private List<Team> teams = new ArrayList<>();

    private List<Player> defenders = new ArrayList<>();
    private List<Player> attackers = new ArrayList<>();
    private List<Player> attackersAndDefenders = new ArrayList<>();
    private int teamNumber = 0;

    List<Team> createTeams(List<Player> shuffledPlayers) {

        sortPlayersByPosition(shuffledPlayers);

        while (!attackers.isEmpty()) {
            Team team = new Team("Team " + (teamNumber + 1));
            team.setFirstPlayer(attackers.remove(new Random().nextInt(attackers.size())));
            if (!defenders.isEmpty()) {
                team.setSecondPlayer(defenders.remove(new Random().nextInt(defenders.size())));
            } else if (!attackersAndDefenders.isEmpty()) {
                team.setSecondPlayer(attackersAndDefenders.remove(new Random().nextInt(attackersAndDefenders.size())));
            } else if (!attackers.isEmpty())
                team.setSecondPlayer(attackers.remove(new Random().nextInt(attackers.size())));
            teams.add(team);
            teamNumber++;
        }


        while (!defenders.isEmpty()) {
            Team team = new Team("Team " + (teamNumber + 1));
            team.setFirstPlayer(defenders.remove(new Random().nextInt(defenders.size())));
            if (!attackers.isEmpty()) {
                team.setSecondPlayer(attackers.remove(new Random().nextInt(attackers.size())));
            } else if (!attackersAndDefenders.isEmpty()) {
                team.setSecondPlayer(attackersAndDefenders.remove(new Random().nextInt(attackersAndDefenders.size())));
            } else if (!defenders.isEmpty())
                team.setSecondPlayer(defenders.remove(new Random().nextInt(defenders.size())));
            teams.add(team);
            teamNumber++;
        }


        while (!attackersAndDefenders.isEmpty()) {
            Team team = new Team("Team " + (teamNumber + 1));
            team.setFirstPlayer(attackersAndDefenders.remove(new Random().nextInt(attackersAndDefenders.size())));
            if (!attackers.isEmpty()) {
                team.setSecondPlayer(attackers.remove(new Random().nextInt(attackers.size())));
            } else if (!defenders.isEmpty()) {
                team.setSecondPlayer(defenders.remove(new Random().nextInt(defenders.size())));
            } else if (!attackersAndDefenders.isEmpty()) {
                team.setSecondPlayer(attackersAndDefenders.remove(new Random().nextInt(attackersAndDefenders.size())));
            }
            teams.add(team);
            teamNumber++;
        }

        return teams;
    }

    private void sortPlayersByPosition(List<Player> players) {
        for (Player player : players) {
            if (player.getPreferredPosition() == PositionType.BOTH)
                attackersAndDefenders.add(player);
            else if (player.getPreferredPosition() == PositionType.ATTACK)
                attackers.add(player);
            else if (player.getPreferredPosition() == PositionType.DEFENSE)
                defenders.add(player);
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 20 октября 2019

Другой способ упростить это использование вспомогательного метода.

private Team pickTwo(int n, List<Player> list1, List<Player> list2) {
    Team team = new Team("Team " + n);
    team.setFirstPlayer(list1.remove(list1.size() - 1));
    team.setFirstPlayer(list2.remove(list2.size() - 1));
    return team;
}

List<Team> createTeams(List<Player> players) {
    List<Player> attackers = new ArrayList<>();
    List<Player> defenders = new ArrayList<>();
    List<Player> bothTypes = new ArrayList<>();

    for (Player p : players) {
        switch(p.getPreferredPosition()) {
            case ATTACK: { attackers.add(p); break; }
            case DEFENSE: { defenders.add(p); break; }
            case BOTH: { bothTypes.add(p); break; }
        }
    }

    int n = 1;
    List<Team> teams = new ArrayList<>(players.size() / 2);

    while (!attackers.isEmpty() && !defenders.isEmpty()) {
        teams.add(pickTwo(n++, attackers, defenders));
    }
    while (!attackers.isEmpty() && !bothTypes.isEmpty()) {
        teams.add(pickTwo(n++, attackers, bothTypes));
    }
    while (!defenders.isEmpty() && !bothTypes.isEmpty()) {
        teams.add(pickTwo(n++, defenders, bothTypes));
    }
    while (bothTypes.size() > 1) {
        teams.add(pickTwo(n++, bothTypes, bothTypes));
    }
    while (attackers.size() > 1) {
        teams.add(pickTwo(n++, attackers, attackers));
    }
    while (defenders.size() > 1) {
        teams.add(pickTwo(n++, defenders, defenders));
    }

    return teams;
}

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

0 голосов
/ 20 октября 2019

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

while (!both.isEmpty() || !attackers.isEmpty() || !defenders.isEmpty()) {
    if (!attackers.isEmpty()) {
        team.setFirstPlayer(attackers.remove(new Random().nextInt(attackers.size())));
    } else if (!both.isEmpty()) {
        team.setFirstPlayer(both.remove(new Random().nextInt(attackers.size())));
    } else if (!defenders.isEmpty()) {
        team.setFirstPlayer(defenders.remove(new Random().nextInt(attackers.size())));
    }

    if (!defenders.isEmpty()) {
        team.setFirstPlayer(defenders.remove(new Random().nextInt(attackers.size())));
    } else if (!both.isEmpty()) {
        team.setFirstPlayer(both.remove(new Random().nextInt(attackers.size())));
    } else if (!attackers.isEmpty()) {
        team.setFirstPlayer(attackers.remove(new Random().nextInt(attackers.size())));
    }
}

Сначала это проверит атакующих и поместит их в команду. Если нет нападающих, это поставит кого-то, кто может сделать оба. Второй набор утверждений if ставит защитника на вторую позицию или кого-то, кто может выполнять обе функции в этой позиции. Только в случае, когда атакующих или защитников значительно больше, чем другого, он назначит двух защитников или двух атакующих в одну команду.

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