改进配对玩家的算法 - 重复代码太多
Improving alghoritm to pair players - too much duplication code
我有球员。玩家获得优先位置。我们有 3 个位置——防守者、攻击者、两者(在两个位置上都擅长的球员)。
我需要创建两个团队。配对玩家应该是这样的:
“一个攻击手可以搭配一个后卫,或者两个位置都可以打的人。当然,两个位置都很舒服的人可以组队。两个防守者或两个攻击者比其他组合弱,所以应该仅在没有其他选择时才以这种方式配对。"
我写过这样的东西。我知道这是天真的实现,但找不到更好的方法。
首先,我按位置对球员进行排序,因此我有 3 个列表。然后,使用 while 循环我首先处理攻击者,然后是防御者,然后是 attackers/defenders.
有什么办法可以改善吗?如果没有,我想知道如何将重复的代码提取到方法中。
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);
}
}
}
您可以将三个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 语句将防守者置于第二位置,或者将防守者置于第二位置。只有在攻击者或防守者明显多于对方的情况下,才会将两名防守者或两名攻击者放在同一个团队中。
另一种简化方法是使用辅助方法。
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;
}
我使用的算法是将攻击者与防御者配对,然后将剩余的 attackers/defenders 分配给可以同时做这两种事情的玩家,然后可以互相做这两种事情的玩家,然后将剩余的玩家配对。
我有球员。玩家获得优先位置。我们有 3 个位置——防守者、攻击者、两者(在两个位置上都擅长的球员)。 我需要创建两个团队。配对玩家应该是这样的: “一个攻击手可以搭配一个后卫,或者两个位置都可以打的人。当然,两个位置都很舒服的人可以组队。两个防守者或两个攻击者比其他组合弱,所以应该仅在没有其他选择时才以这种方式配对。"
我写过这样的东西。我知道这是天真的实现,但找不到更好的方法。
首先,我按位置对球员进行排序,因此我有 3 个列表。然后,使用 while 循环我首先处理攻击者,然后是防御者,然后是 attackers/defenders.
有什么办法可以改善吗?如果没有,我想知道如何将重复的代码提取到方法中。
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);
}
}
}
您可以将三个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 语句将防守者置于第二位置,或者将防守者置于第二位置。只有在攻击者或防守者明显多于对方的情况下,才会将两名防守者或两名攻击者放在同一个团队中。
另一种简化方法是使用辅助方法。
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;
}
我使用的算法是将攻击者与防御者配对,然后将剩余的 attackers/defenders 分配给可以同时做这两种事情的玩家,然后可以互相做这两种事情的玩家,然后将剩余的玩家配对。