package me.stieglmaier.sphereMiners.model.rules;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import me.stieglmaier.sphereMiners.main.Constants;
import me.stieglmaier.sphereMiners.model.ai.Player;
import me.stieglmaier.sphereMiners.model.util.GameSimulation;
import me.stieglmaier.sphereMiners.model.util.Sphere;
public enum WinningConditions {
/**
* The game will not end, even if only one AI is left.
*/
OPEN_END {
/**
* {@inheritDoc}
*/
@Override
public boolean hasGameEnded(GameSimulation simulation, Constants constants) {
return false;
}
},
/**
* The game will end if only one AI is left.
*/
ONE_LEFT {
/**
* {@inheritDoc}
*/
@Override
public boolean hasGameEnded(GameSimulation simulation, Constants constants) {
Player firstpPlayer = null;
for (Sphere s : simulation.getTick(simulation.getSize() - 1).getSpheres()) {
if (firstpPlayer == null) {
firstpPlayer = s.getOwner();
} else if (firstpPlayer != s.getOwner()) {
return false;
}
}
winner = Collections.singletonList(firstpPlayer);
return true;
}
},
/**
* The game will end when any AI reaches a certain size. This AI will then
* also be the winner.
*/
SIZE_REACHED {
/**
* {@inheritDoc}
*/
@Override
public boolean hasGameEnded(GameSimulation simulation, Constants constants) {
Map<Player, Integer> sizes = computePlayerSizes(simulation);
List<Player> winners = new ArrayList<>();
for (Entry<Player, Integer> e : sizes.entrySet()) {
if (e.getValue() > constants.getTotalSizeToReach()) {
winners.add(e.getKey());
}
}
winner = winners;
return !winners.isEmpty();
}
},
/**
* The game will end after a certain timespan, the winner is
* the AI with the largest accumulated size of spheres.
*/
BIGGEST_AFTER_TIME {
/**
* {@inheritDoc}
*/
@Override
public boolean hasGameEnded(GameSimulation simulation, Constants constants) {
if (constants.getTotalGameTime() <= simulation.getSize() / constants.getFramesPerSecond()) {
Map<Player, Integer> sizes = computePlayerSizes(simulation);
int maxValue = 0;
for (Entry<Player, Integer> e : sizes.entrySet()) {
if (e.getValue() > maxValue) {
maxValue = e.getValue();
}
}
List<Player> winners = new ArrayList<>();
for (Entry<Player, Integer> e : sizes.entrySet()) {
if (e.getValue() == maxValue) {
winners.add(e.getKey());
}
}
winner = winners;
return true;
}
return false;
}
};
private static List<Player> winner = new ArrayList<>();
/**
* Checks if the game has ended regarding the chosen winning rule.
* @param simulation the simulation that should be checked if it has ended
* @param constants the constants that should be used for computing the result
*
* @return indicates whether the game has ended or not
*/
public abstract boolean hasGameEnded(GameSimulation simulation, Constants constants);
/**
* Returns the winner if the game has ended, or an empty list. This method
* has only correct results if before hasGameEnded was called. Additionally
* this method can only be called once, before hasGameEnded needs to be
* called again.
*
* @return the list of players who fulfill the given rule
*/
public List<Player> getWinner() {
List<Player> tmp = winner;
winner = Collections.emptyList();
return tmp;
}
private static Map<Player, Integer> computePlayerSizes(GameSimulation simulation) {
Map<Player, Integer> sizes = new HashMap<>();
for (Sphere s : simulation.getTick(simulation.getSize() - 1).getSpheres()) {
Player currentPlayer = s.getOwner();
if (sizes.containsKey(currentPlayer)) {
sizes.replace(currentPlayer, sizes.get(currentPlayer) + s.getSize());
} else {
sizes.put(currentPlayer, 0);
}
}
return sizes;
}
}