package org.pixelgaffer.turnierserver.gamelogic;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.pixelgaffer.turnierserver.Logger;
import org.pixelgaffer.turnierserver.gamelogic.interfaces.Ai;
import org.pixelgaffer.turnierserver.gamelogic.interfaces.BuilderSolverAiObject;
import org.pixelgaffer.turnierserver.gamelogic.interfaces.BuilderSolverGameState;
import org.pixelgaffer.turnierserver.gamelogic.interfaces.BuilderSolverGameState.Response;
import org.pixelgaffer.turnierserver.gamelogic.interfaces.Game;
import org.pixelgaffer.turnierserver.gamelogic.messages.BuilderSolverChange;
import org.pixelgaffer.turnierserver.gamelogic.messages.BuilderSolverResponse;
/**
* @param <E>
* Das AiObject
* @param <G>
* Der GameState
* @param <B>
* Die BuilderResponse
* @param <S>
* Die SolverResponse
*/
public abstract class BuilderSolverLogic<E extends BuilderSolverAiObject<G>, G extends BuilderSolverGameState<?, B, S>, B, S> extends GameLogic<E, BuilderSolverResponse<B, S>> {
public static Logger logger = new Logger();
/**
* True wenn building, sonst solving
*/
private boolean building;
/**
* Die Liste mit den Ais, die ihre momentane Aufgabe schon erfüllt haben
*/
private List<Ai> finished = new ArrayList<>();
/**
* Gibt eine Liste mit allen Ais zurück, die Builden sollen
*
* @return Die Liste mit allen Ais, die Builden sollen
*/
public abstract List<Ai> getBuilder();
/**
* Gibt eine Liste mit allen Ais zurück, die Solven sollen
*
* @return Die Liste mit allen Ais, die Solven sollen
*/
public abstract List<Ai> getSolver();
/**
* Erstellt einen neuen GameState, damit die ai diesen aufbauen kann
*
* @param ai Die Ai, die diesen aufbauen wird
* @return Den neuen GameState
*/
public abstract G createGameState(Ai ai);
/**
* Wird aufgerufen, wenn eine Ai beim ausführen ihrer Aufgabe gescheitert ist
*
* @param building True wenn die Aufgabe Builden war, False wenn die Aufgabe Solven war.
* @param ai Die Ai, welche gescheitert ist
*/
public abstract void failed(boolean building, Ai ai);
/**
* Wird aufgerufen, wenn eine Ai beim ausführen ihrer Aufgabe erfoglreich war
*
* @param building True wenn die Aufgabe Builden war, Fale wenn die Aufgabe Solven war.
* @param ai Die Ai, welche erflogreich war
*/
public abstract void succeeded(boolean building, Ai ai);
/**
* Gibt die Ai zurück, welche das Spielefeld für die gegebene Ai gebuildet hat
*
* @param ai Die Ai, für welche der Builder bestimmt werden soll
* @return Die Ai, welche das Spielfeld gebuildet hat
*/
public abstract Ai getBuilder(Ai ai);
@Override
public void startGame(Game game) {
super.startGame(game);
System.out.println("Das Spiel fängt an");
started = true;
startBuilding();
}
/**
* super.lost(Ai ai) MUSS AUFGERUFEN WERDEN!!
*/
@Override
public void lost(Ai ai) {
logger.info("Ai hat verloren: " + ai.getIndex());
List<Ai> list = building ? getBuilder() : getSolver();
if (list.contains(ai)) {
if (!finished.contains(ai)) {
finished.add(ai);
failed(building, ai);
check();
}
}
}
@Override
protected void receive(BuilderSolverResponse<B, S> response, Ai ai, int passedMikros) {
if (finished.contains(ai)) {
getUserObject(ai).loose("Die KI ist für diese Runde schon fertig und hat trotzdem noch einmal etwas gesendet");
return;
}
if(getUserObject(ai).subtractMikros(passedMikros)) {
return;
}
Response<?> result = null;
if (building) {
if (response.build == null) {
getUserObject(ai).loose("Die KI hat kein Builder Objekt gesendet");
return;
}
result = getUserObject(ai).building.build(response.build);
logger.info("Wurde das Feld erfolgreich gebaut?: " + result.valid);
} else {
if (response.solve == null) {
getUserObject(ai).loose("Die KI hat kein Solver Objekt gesendet");
return;
}
result = getUserObject(ai).solving.solve(response.solve);
}
logger.info("Antwort, die gesendet wird: " + result);
if (result.renderData != null) {
sendRenderData(result.renderData);
}
if (result.changes != null) {
try {
BuilderSolverChange<Object> change = new BuilderSolverChange<>();
change.change = result.changes;
change.building = building;
sendToAi(change, ai);
} catch (IOException e) {
getUserObject(ai).loose("Es gab ein Problem mit der Kommunikation mit der KI");
}
}
if (result.finished) {
logger.info("Die Aufgabe wurde beendet!");
finished.add(ai);
if (!result.valid) {
logger.info("Die Aufgabe wurde nicht erfolgreich beendet!");
failed(building, ai);
} else {
logger.info("Die Aufgabe wurde erfolgreich beendet!");
succeeded(building, ai);
getUserObject(ai).succesful = true;
}
check();
}
return;
}
private void check() {
if (finished.size() != (building ? getBuilder() : getSolver()).size()) {
return;
}
finished.clear();
if (building) {
logger.info("Die Ais fangen nun an zu solven");
startSolving();
} else {
round();
if (allRoundsPlayed()) {
endGame("Die maximale Anzahl an Runden (" + maxTurns + ") wurde gespielt");
logger.info("Das Spiel wurde erfolgreich beendet");
return;
}
logger.info("Die Ais fangen nun an zu builden");
startBuilding();
}
}
private void startSolving() {
building = false;
BuilderSolverChange<Object> change = new BuilderSolverChange<>();
change.building = false;
for (Ai ai : getSolver()) {
if (getUserObject(ai).lost) {
finished.add(ai);
return;
}
Ai builder = getBuilder(ai);
if (!getUserObject(builder).succesful || getUserObject(ai).lost) {
succeeded(false, ai);
finished.add(ai);
return;
}
getUserObject(ai).solving = getUserObject(builder).building;
getUserObject(ai).solving.setAi(ai);
change.change = getUserObject(builder).building.getState();
getUserObject(ai).succesful = false;
try {
sendToAi(change, ai);
} catch (IOException e) {
getUserObject(ai).loose("Es gab ein Problem mit der Kommunikation mit der KI");
}
}
}
private void startBuilding() {
building = true;
BuilderSolverChange<Object> change = new BuilderSolverChange<>();
change.building = true;
for (Ai ai : getBuilder()) {
if (getUserObject(ai).lost) {
finished.add(ai);
continue;
}
getUserObject(ai).building = createGameState(ai);
getUserObject(ai).succesful = false;
try {
sendToAi(change, ai);
} catch (IOException e) {
getUserObject(ai).loose("Es gab ein Problem mit der Kommunikation mit der KI");
}
}
}
}