package net.olemartin.engine; import com.google.common.collect.Lists; import net.olemartin.domain.*; import java.util.*; import java.util.stream.Collectors; import static java.util.stream.Collectors.joining; import static net.olemartin.domain.Color.BLACK; import static net.olemartin.domain.Color.WHITE; public class MonradEngine implements TournamentEngine { private final List<Player> players; private Set<String> triedCombinations = new HashSet<>(); public MonradEngine(Iterable<Player> players) { this.players = Lists.newArrayList(players); } @Override public List<Player> getPlayers() { return players; } @Override public List<Match> round(int round) { Collections.sort(players); LinkedList<Match> matches = new LinkedList<>(); if (round == 1) { for (int i = 0; i < players.size() - 1; i += 2) { matches.add(new Match(players.get(i + 1), players.get(i))); } if (players.size() % 2 == 1) { Match walkoverMatch = new Match(players.get(players.size() - 1)); walkoverMatch.reportResult(Result.WALKOVER); matches.add(walkoverMatch); } } else { System.out.println("Current round: " + round + "\n\n"); otherRounds(matches); } return matches; } private void otherRounds(LinkedList<Match> matches) { LinkedList<Player> pickedPlayers = new LinkedList<>(); if (players.size() % 2 == 1) { Player walkoverPlayer = findLowestRankedPlayerWithoutWalkover(players); pickedPlayers.add(walkoverPlayer); Match walkoverMatch = new Match(walkoverPlayer); walkoverMatch.reportResult(Result.WALKOVER); matches.add(walkoverMatch); } try { triedCombinations = new HashSet<>(); while (pickedPlayers.size() != players.size()) { Player player = players.stream().filter(p -> !pickedPlayers.contains(p)).findFirst().get(); System.out.println("Trying player " + player.getName()); pickPlayer(matches, pickedPlayers, player, false); } } catch (NotPossibleException e) { triedCombinations = new HashSet<>(); while (pickedPlayers.size() != players.size()) { Player player = players.stream().filter(p -> !pickedPlayers.contains(p)).findFirst().get(); System.out.println("Trying player " + player.getName()); pickPlayer(matches, pickedPlayers, player, true); } } } private Player findLowestRankedPlayerWithoutWalkover(List<Player> players) { for (int i = players.size() - 1; i >= 0; i--) { Player player = players.get(i); if (!player.hasWalkover() && player.mustHaveColor() != Color.BLACK) { return player; } } throw new IllegalStateException("All players has had walkover"); } private void pickPlayer(LinkedList<Match> matches, LinkedList<Player> pickedPlayers, Player player1, boolean overrideThreeRule) { Color color1 = player1.nextOptimalColor(); List<Player> opponents = players.stream() .filter(p -> p != player1) .filter(p -> !pickedPlayers.contains(p)) .filter(p -> !p.hasMet(player1)) .filter(p -> matchColor(overrideThreeRule, player1.mustHaveColor(), p)) .filter(p -> !triedCombination(pickedPlayers, player1, p)) .collect(Collectors.toList()); Player player2; if (opponents.isEmpty()) { rollback(matches, pickedPlayers, player1, overrideThreeRule); return; } else { player2 = opponents.get(0); } Color color2 = player2.nextOptimalColor(); if (player1.mustHaveColor() == WHITE || player2.mustHaveColor() == BLACK) { matches.add(new Match(player1, player2)); } else if (player1.mustHaveColor() == BLACK || player2.mustHaveColor() == WHITE) { matches.add(new Match(player2, player1)); } else if (color1 == color2) { matches.add(new Match(player2, player1)); } else { if (color1 == WHITE) { matches.add(new Match(player1, player2)); } else { matches.add(new Match(player2, player1)); } } pickedPlayers.addAll(Arrays.asList(player1, player2)); updateTriedCombination(pickedPlayers); } private boolean matchColor(boolean overrideThreeRule, Color mustHave, Player p) { return overrideThreeRule || mustHave == null || p.mustHaveColor() == null || mustHave != p.mustHaveColor(); } private void updateTriedCombination(LinkedList<Player> pickedPlayers) { String collect = pickedPlayers.stream().map(Player::getName).collect(joining(", ")); triedCombinations.add(collect); System.out.println("Storing " + collect); Player p1 = pickedPlayers.removeLast(); Player p2 = pickedPlayers.removeLast(); pickedPlayers.add(p1); pickedPlayers.add(p2); triedCombinations.add(pickedPlayers.stream().map(Player::getName).collect(joining(", "))); } private boolean triedCombination(LinkedList<Player> pickedPlayers, Player player1, Player player2) { List<Player> tempPlayers = (List<Player>) pickedPlayers.clone(); tempPlayers.add(player1); tempPlayers.add(player2); String combination = tempPlayers.stream().map(Player::getName).collect(joining(", ")); return triedCombinations.contains(combination); } private void rollback(LinkedList<Match> matches, LinkedList<Player> pickedPlayers, Player player, boolean override) { System.out.println("Rolling back because of player " + player.getName()); if (pickedPlayers.size() == 0 || (matches.size() == 0 || (matches.size() == 1 && matches.get(0).isWalkover()))) { System.out.println("Tried combinations: " + triedCombinations.size()); System.out.println("\n\n\n\n FAILED \n\n\n\n"); throw new NotPossibleException(); } else { pickedPlayers.removeLast(); pickedPlayers.removeLast(); matches.getLast().getBlack().removeLastOpponent(); matches.getLast().getWhite().removeLastOpponent(); matches.removeLast(); pickPlayer(matches, pickedPlayers, player, override); } } }