planetwars.dev/examples/java/planetwars/PlanetWars.java
2023-11-20 16:34:47 +01:00

305 lines
9.9 KiB
Java

package planetwars;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
/**********************************************
* ______ _ _______ _____
* |___ / | | | | ___ \_ _|
* / / ___ _ _ ___ | | | | |_/ / | |
* / / / _ \ | | / __| | |/\| | __/ | |
* ./ /__| __/ |_| \__ \ \ /\ / | _| |_
* \_____/\___|\__,_|___/ \/ \/\_| \___/
*
*********************************************/
/**
* Klasse die het staat van het spel bijhoudt.
*
* Je doet dit door een instance aan te maken en bij elke keer als je input
* krijgt van het spel dit door te geven aan de klasse met de functie update().
*
* Deze functie zal de input verwerken zodat je alle data in variabelen hebt namelijk
* - myPlanets
* - neutralPlanets
* - ...
* - enemyExpeditions
*
* De data wordt opgeslagen als een bepaalde klasse.
* Deze zijn allemaal record klassen wat wilt zeggen dat ze alleen maar dienen om
* data in op te slaan.
* Je kan de data ervan niet bewerken.
* Meer informatie over hoe elke klasse zijn data bijhoudt kan je zien in
* de file van die klasse.
*
* Je kan dan door middel van de functie addMove() zetten toevoegen.
* Wanneer je al je zetten hebt toegevoegd en je ze effectief wilt spelen
* kan je de functie Move() oproepen.
* Daarna kan je geen extra moves meer spelen tot de volgende beurt waarbij je
* de functie update() oproept.
*
* Tenslotte heb je nog de variabele currentTurn.
* Die wordt momenteel voor niets gebruikt maar houd bij aan welke turn we zitten.
*
*
* je kan in de file Example.java een voorbeeld implementatie vinden.
*/
public class PlanetWars {
public List<Planet> myPlanets;
public List<Planet> neutralPlanets;
public List<Planet> enemyPlanets;
public List<Expedition> myExpeditions;
public List<Expedition> enemyExpeditions;
public int currentTurn;
private List<Move> queuedMoves;
private boolean moved;
private DateTimeFormatter dateFormatter;
public PlanetWars() {
this.myPlanets = new ArrayList<>();
this.neutralPlanets = new ArrayList<>();
this.enemyPlanets = new ArrayList<>();
this.myExpeditions = new ArrayList<>();
this.enemyExpeditions = new ArrayList<>();
this.currentTurn = 0;
this.queuedMoves = new ArrayList<>();
this.dateFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
}
/**
* Roep dit iedere beurt op met de input die je krijgt van het spel.
* Gaat over de data en maakt er de juiste objecten van.
*
* @param input | De data die je krijgt van het spel. Zie Main.java hoe je dit het best krijgt
*
* @return | Geeft aan of opgegeven data klopt en of je iets kan doen.
*/
public boolean update(String input) {
// Maak alle lijsten leeg.
this.nextTurn();
// Vorm de input om tot een JsonObject.
JsonObject state;
try {
state = new Gson().fromJson(input, JsonObject.class);
} catch (JsonSyntaxException e) {
this.log("Error: Converting input to json");
this.log(input);
return false;
}
// Krijg een lijst van alle planeten.
List<Planet> planets = new ArrayList<>();
try {
JsonArray planetsJson = state.getAsJsonArray("planets");
for (int i = 0; i < planetsJson.size(); i++) {
planets.add(new Planet(planetsJson.get(i).getAsJsonObject()));
}
} catch (Exception e) {
this.log("Error: Parsing planet input");
this.log(input);
return false;
}
if (planets.isEmpty()) {
this.log("Error: No planets");
this.log(input);
return false;
}
// Voeg de planeten toe tot de juiste lijst.
for (Planet planet : planets) {
if (planet.owner() == null) {
neutralPlanets.add(planet);
} else if (planet.owner() == 1) {
myPlanets.add(planet);
} else {
enemyPlanets.add(planet);
}
}
// Doe hetzelfde met de expedities.
try {
JsonArray expeditionsJson = state.getAsJsonArray("expeditions");
for (int i = 0; i < expeditionsJson.size(); i++) {
JsonObject expedition = expeditionsJson.get(i).getAsJsonObject();
// Zoek naar de planeet object vanwaar ze komen en naar toe gaan.
String originString = expedition.get("origin").getAsString();
String destinationString = expedition.get("destination").getAsString();
Planet originPlanet = null;
Planet destinationPlanet = null;
for (Planet planet: planets) {
if (planet.name().equals(originString)) {
// Planeet van waar ze komen is gevonden
originPlanet = planet;
}
if (planet.name().equals(destinationString)) {
// Planeet waar ze naar toe gaan is ook gevonden
destinationPlanet = planet;
}
}
// Maak nieuwe expeditie aan en voeg het toe bij de juiste lijst
Expedition exp = new Expedition(expedition, originPlanet, destinationPlanet);
if (exp.owner() == 1) {
myExpeditions.add(exp);
} else {
enemyExpeditions.add(exp);
}
}
} catch (Exception e) {
this.log("Error: Parsing expedition input");
this.log(input);
return false;
}
this.moved = false;
return true;
}
/**
* Voeg een zet toe.
* Je kan zoveel zetten toevoegen als je wilt en ze worden pas doorgegeven wanneer je move() aanroept.
*
* @param origin | De planeet van waar de schepen moeten komen.
* @param destination | De planeet waar de schepen moeten toekomen.
* @param ships | De hoeveelheid schepen die je wilt versturen
*
* @return | Geeft weer indien het een geldige zet is. Let op er worden maar een paar basis checks gedaan hiervoor
*/
public boolean addMove(Planet origin, Planet destination, int ships) {
// Je kan maar 1 keer al je moves versturen per buurt.
// Je kan daarin wel meerdere moves zetten.
// Je kan dit doen door meerdere keren add_move op te roepen voor je move() oproept.
if (this.moved) {
return false;
}
// Je kan alleen schepen sturen die komen van je eigen planeet.
if (origin.owner() != 1) {
return false;
}
// Je kan geen schepen sturen naar dezelfde planeet als van waar ze komen.
if (origin.equals(destination)) {
return false;
}
// Je kan niet meer schepen versturen dan er zijn op de oorsprong planeet.
int totalShips = ships;
for (Move move: this.queuedMoves) {
if (move.origin().equals(origin)) {
totalShips += move.shipCount();
}
}
if (totalShips > origin.shipCount()) {
return false;
}
this.queuedMoves.add(new Move(origin, destination, ships));
return true;
}
/**
* Verwijder de moves die je al had toegevoegd.
*/
public void clearMoves() {
this.queuedMoves.clear();
}
/**
* Voer alle zetten uit en ga naar de volgende beurt.
*/
public void move() {
// Je kan maar 1 keer al je moves versturen per beurt.
// Je kan daarin wel meerdere moves zetten.
// Je kan dit doen door meerdere keren add_move op te roepen voor je move() oproept.
if (this.moved) {
return;
}
List<JsonObject> movesJson = new ArrayList<>();
for (Move move : queuedMoves) {
movesJson.add(move.toJson());
}
JsonObject movesObj = new JsonObject();
movesObj.add("moves", new Gson().toJsonTree(movesJson));
this.moved = true;
System.out.println(movesObj);
}
/**
* Print een bericht met een tijdstip ervoor.
*
* @param message | Het bericht dat je wilt printen.
*/
public void log(String message) {
LocalDateTime timestamp = LocalDateTime.now();
String formattedTimestamp = timestamp.format(this.dateFormatter);
System.err.println("[" + formattedTimestamp + "] " + message);
}
/**
* Maakt variabelen klaar voor de volgende beurt.
*/
private void nextTurn() {
this.myPlanets.clear();
this.neutralPlanets.clear();
this.enemyPlanets.clear();
this.myExpeditions.clear();
this.enemyExpeditions.clear();
this.currentTurn += 1;
this.queuedMoves.clear();
}
}
/**
* Weet je niet hoe je nu verder moet?
*
* Kijk naar example.py hoe de klasse te implementeren.
*
* Nog enkele tips hoe je je bot beter kan maken:
*
* - Maak een nieuwe functie aan in de klasse PlanetWars `predict`.
* Deze probeert te voorspellen hoeveel schepen van je tegenstander er op een bepaalde
* planeet toekomen na x aantal beurten.
*
* - Maak een onderscheid tussen de gevallen waarbij jouw tegenstander geen extra schepen meer
* verstuurd naar een bepaalde planeet en al zijn schepen ernaar heeft verstuurd.
* Welke planeten kan je met de minste effort makkelijk pakken?
*
* - Indien je al meerdere planeten hebt probeer schepen van de achterliggende planeten naar
* de frontline te sturen.
*
* - ...
*
* Wees creatief, de mogelijkheden zijn eindeloos :D
*/