diff --git a/.factorypath b/.factorypath
new file mode 100644
index 0000000..41be359
--- /dev/null
+++ b/.factorypath
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..e9441bb
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs
new file mode 100644
index 0000000..dfa4f3a
--- /dev/null
+++ b/.settings/org.eclipse.jdt.apt.core.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.apt.aptEnabled=true
+org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
+org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..8f693c0
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=21
+org.eclipse.jdt.core.compiler.compliance=21
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.processAnnotations=enabled
+org.eclipse.jdt.core.compiler.release=enabled
+org.eclipse.jdt.core.compiler.source=21
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/src/main/java/com/epita/creeps/AsyncExec.java b/src/main/java/com/epita/creeps/AsyncExec.java
index 7a5034f..fd36f47 100644
--- a/src/main/java/com/epita/creeps/AsyncExec.java
+++ b/src/main/java/com/epita/creeps/AsyncExec.java
@@ -1,14 +1,12 @@
package com.epita.creeps;
-import com.epita.creeps.given.vo.report.Report;
-import com.epita.creeps.given.vo.response.CommandResponse;
-import lombok.AllArgsConstructor;
+
+import kong.unirest.core.HttpResponse;
+import kong.unirest.core.JsonNode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
-import java.net.http.HttpResponse;
-import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@@ -20,18 +18,23 @@ public class AsyncExec {
@Getter
@Setter
- private static long ticksPerSecond = 1;
- private CompletableFuture task;
+ private static float ticksPerSecond = 1;
+// private CompletableFuture task;
+ public static long ticksToTime(long ticks) {
+ return Math.ceilDiv(ticks, (long)Math.ceil(ticksPerSecond));
+ }
public static CompletableFuture asyncExec(Supplier supplier, long time) {
return CompletableFuture.supplyAsync(supplier).thenApplyAsync(x -> x,
- CompletableFuture.delayedExecutor(time/ticksPerSecond + 1, TimeUnit.SECONDS));
+ CompletableFuture.delayedExecutor(ticksToTime(time), TimeUnit.SECONDS));
}
public static CompletableFuture thenAsyncExec(CompletableFuture base, Function f, long time) {
- return base.thenApplyAsync(f, CompletableFuture.delayedExecutor(time/ticksPerSecond + 1, TimeUnit.SECONDS));
+ return base.thenApplyAsync(f, CompletableFuture.delayedExecutor(time, TimeUnit.SECONDS));
}
+
public static void justWait(long time) {
- CompletableFuture.supplyAsync(() -> 0, CompletableFuture.delayedExecutor(time/ticksPerSecond + 1, TimeUnit.SECONDS)).join();
+ CompletableFuture.supplyAsync(() -> 0, CompletableFuture.delayedExecutor(time, TimeUnit.SECONDS)).join();
}
+
}
diff --git a/src/main/java/com/epita/creeps/Program.java b/src/main/java/com/epita/creeps/Program.java
index 8fee7f0..02fb30c 100644
--- a/src/main/java/com/epita/creeps/Program.java
+++ b/src/main/java/com/epita/creeps/Program.java
@@ -37,10 +37,9 @@ public class Program {
// Classes
logger = LoggerFactory.getLogger(Program.class);
- Basics basics = new Basics(logger, srvUrl);
logger.info("Initializing");
+ Basics.setSrvUrl(srvUrl);
Citizen.srvUrl = srvUrl;
- Citizen.logger = logger;
logger.debug("Using server " + srvUrl + " with player " + login);
if (default_values)
@@ -58,19 +57,31 @@ public class Program {
// Create account and get init infos
logger.info("Creating account");
- InitResponse initResponse = basics.connectAccount(login);
+ InitResponse initResponse = Basics.connectAccount(login);
login = initResponse.login; // Just in case
AsyncExec.setTicksPerSecond((long)initResponse.setup.ticksPerSeconds);
Citizen citizen1 = new Citizen(login, initResponse.citizen1Id);
Citizen citizen2 = new Citizen(login, initResponse.citizen2Id);
- while (true) {
+ for(int i = 0; i < 3; i++) {
citizen1.move(Direction.RIGHT);
citizen2.move(Direction.UP);
- CommandResponse citizen1_resp = citizen1.waitFinished();
- CommandResponse citizen2_resp = citizen2.waitFinished();
+ citizen1.waitFinished();
+ citizen2.waitFinished();
+
+// logger.debug("Received actions responses");
+// logger.debug("citizen1.error: " + citizen1_resp.error);
+// logger.debug("citizen2.error: " + citizen2_resp.error);
+ }
+
+ for(int i = 0; i < 3; i++) {
+ citizen1.move(Direction.LEFT);
+ citizen2.move(Direction.DOWN);
+
+ citizen1.waitFinished();
+ citizen2.waitFinished();
// logger.debug("Received actions responses");
// logger.debug("citizen1.error: " + citizen1_resp.error);
diff --git a/src/main/java/com/epita/creeps/ServerReponseException.java b/src/main/java/com/epita/creeps/ServerReponseException.java
new file mode 100644
index 0000000..5757612
--- /dev/null
+++ b/src/main/java/com/epita/creeps/ServerReponseException.java
@@ -0,0 +1,7 @@
+package com.epita.creeps;
+
+public class ServerReponseException extends RuntimeException {
+ public ServerReponseException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/epita/creeps/commands/Basics.java b/src/main/java/com/epita/creeps/commands/Basics.java
index 740fd94..bae31e7 100644
--- a/src/main/java/com/epita/creeps/commands/Basics.java
+++ b/src/main/java/com/epita/creeps/commands/Basics.java
@@ -1,7 +1,9 @@
package com.epita.creeps.commands;
import com.epita.creeps.AsyncExec;
+import com.epita.creeps.given.exception.NoReportException;
import com.epita.creeps.given.json.Json;
+import com.epita.creeps.given.vo.report.Report;
import com.epita.creeps.given.vo.response.InitResponse;
import kong.unirest.core.HttpResponse;
import kong.unirest.core.JsonNode;
@@ -10,7 +12,9 @@ import kong.unirest.core.UnirestException;
import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.Setter;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
@@ -18,10 +22,11 @@ import java.util.concurrent.CompletableFuture;
@Getter
public class Basics {
- private Logger logger;
- private String srvUrl;
+ private static final Logger logger = LoggerFactory.getLogger(Basics.class);
+ @Getter @Setter
+ private static String srvUrl;
- public InitResponse connectAccount(String login) {
+ public static InitResponse connectAccount(String login) {
try {
CompletableFuture> resp = AsyncExec.asyncExec(() -> Unirest.post(srvUrl + "/init/" + login).asJson(), 0);
HttpResponse response = (HttpResponse) resp.join();
@@ -38,13 +43,19 @@ public class Basics {
}
}
- public void getReport (String reportId) {
+ // Asks the server for a certain report
+ public static Report getReport (String reportId) {
HttpResponse response;
try {
response = Unirest.get(srvUrl + "/report/" + reportId).asJson();
- logger.debug(response.getBody().toPrettyString());
+ logger.debug("Got report: " + response.getBody().toPrettyString());
+ return Json.parseReport(response.getBody().toString());
} catch (UnirestException e) {
logger.error("Could not retrieve report");
+ throw new RuntimeException(e);
+ } catch (NoReportException e) {
+ logger.error("Could not parse report: not a report");
+ throw new RuntimeException(e);
}
}
diff --git a/src/main/java/com/epita/creeps/units/Building.java b/src/main/java/com/epita/creeps/units/Building.java
new file mode 100644
index 0000000..2ceebd7
--- /dev/null
+++ b/src/main/java/com/epita/creeps/units/Building.java
@@ -0,0 +1,14 @@
+package com.epita.creeps.units;
+
+public enum Building {
+ TOWNHALL("town-hall"),
+ HOUSEHOLD("household"),
+ SAWMILL("sawmill"),
+ SMELTERY("smeltery"),
+ ROAD("road");
+
+ public final String name;
+ private Building(final String building) {
+ this.name = building;
+ }
+}
diff --git a/src/main/java/com/epita/creeps/units/Citizen.java b/src/main/java/com/epita/creeps/units/Citizen.java
index 9dbf319..67d62f8 100644
--- a/src/main/java/com/epita/creeps/units/Citizen.java
+++ b/src/main/java/com/epita/creeps/units/Citizen.java
@@ -1,13 +1,21 @@
package com.epita.creeps.units;
import com.epita.creeps.AsyncExec;
+import com.epita.creeps.ServerReponseException;
+import com.epita.creeps.commands.Basics;
+import com.epita.creeps.given.exception.NoReportException;
import com.epita.creeps.given.json.Json;
import com.epita.creeps.given.vo.geometry.Direction;
+import com.epita.creeps.given.vo.parameter.MessageParameter;
+import com.epita.creeps.given.vo.report.MoveReport;
+import com.epita.creeps.given.vo.report.Report;
import com.epita.creeps.given.vo.response.CommandResponse;
import kong.unirest.core.HttpResponse;
import kong.unirest.core.JsonNode;
import kong.unirest.core.Unirest;
+import java.util.concurrent.CompletableFuture;
+
public class Citizen extends Unit {
@@ -16,20 +24,36 @@ public class Citizen extends Unit {
}
public void move(Direction direction) {
- pendingAction = AsyncExec.asyncExec(() -> Unirest.post(command_uri + "move:"+direction.direction).asJson(), 2)
- .thenApplyAsync( x -> x );
+ sendAction("move:"+direction.direction, 2);
+ }
+ public void observe() {
+ sendAction("observe", 1);
+ }
+ public void gather() {
+ sendAction("gather", 4);
+ }
+ public void unload() {
+ sendAction("unload", 3);
+ }
+ public void farm() {
+ sendAction("farm", 10);
+ }
+ public void build(Building building) {
+ sendAction("build:" + building.name, 20);
+ }
+ public void spawn(String unit) {
+ sendAction("spawn:" + unit, 6);
+ }
+ public void refine(String resource) {
+ sendAction("refine:" + resource, 8);
+ }
+ public void sendMessage(String receiver, String message) {
+ MessageParameter mp = new MessageParameter(receiver, message);
+ sendActionWithBody("message:send", Json.serialize(mp), 1);
+ }
+ public void fetchMessages() {
+ sendAction("message:fetch", 1);
}
- public CommandResponse waitFinished() {
- if (pendingAction == null) {
- logger.warn("Tried to wait a citizen with no pending action");
- return null;
- }
- JsonNode response = ((HttpResponse) pendingAction.join()).getBody();
- return Json.parse(response.toString(), CommandResponse.class);
- }
- public void noop() {
-// AsyncExec.asyncExec()
- }
}
diff --git a/src/main/java/com/epita/creeps/units/Unit.java b/src/main/java/com/epita/creeps/units/Unit.java
index b163567..674f0e6 100644
--- a/src/main/java/com/epita/creeps/units/Unit.java
+++ b/src/main/java/com/epita/creeps/units/Unit.java
@@ -1,8 +1,16 @@
package com.epita.creeps.units;
+import com.epita.creeps.AsyncExec;
+import com.epita.creeps.ServerReponseException;
+import com.epita.creeps.commands.Basics;
+import com.epita.creeps.given.json.Json;
+import com.epita.creeps.given.vo.report.Report;
+import com.epita.creeps.given.vo.response.CommandResponse;
import kong.unirest.core.HttpResponse;
import kong.unirest.core.JsonNode;
+import kong.unirest.core.Unirest;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
@@ -10,14 +18,71 @@ public abstract class Unit {
protected final String id;
protected final String command_uri;
protected CompletableFuture> pendingAction;
+ protected CompletableFuture pendingReport;
public static String srvUrl;
- public static Logger logger;
+ public static final Logger logger = LoggerFactory.getLogger(Unit.class);
public Unit(String login, String id) {
- if (srvUrl == null || logger == null) {
+ if (srvUrl == null) {
throw new RuntimeException("Tried to create a citizen without properly initializing static fields");
}
this.id = id;
command_uri = srvUrl + "/command/" + login + "/" + id + "/";
}
+
+ // Sends a specific action to the server using it's HTTPS string representation
+ // Sets pending action accordingly and asks for a report after `delay` ticks
+ public void sendActionWithBody(String actionCode, String body, long delay) {
+ // Move
+ pendingAction = AsyncExec.asyncExec(() -> Unirest.post(command_uri + actionCode).asJson(), delay)
+ .thenApplyAsync( x -> x );
+ // Get report
+ pendingReport = getCommandReport();
+ }
+
+ // Just sends an action with an empty body
+ public void sendAction(String actionCode, long delay) {
+ sendActionWithBody(actionCode, "{}", delay);
+ }
+
+ public void upgrade() {
+ sendAction("upgrade", 1);
+ }
+ public void noop() {
+ sendAction("noop", 1);
+ }
+
+ /*
+ * @return true if action succeeded, false otherwise
+ */
+ public boolean waitFinished() {
+ if (pendingAction == null || pendingReport == null) {
+ logger.warn("Tried to wait a citizen with no pending action or report");
+ return false;
+ }
+ Report r = pendingReport.join();
+ if (r == null) {
+ logger.warn("Invalid report received: null value");
+ return false;
+ }
+ logger.debug("Got report: " + r);
+
+ return r.errorCode != null;
+ }
+
+
+ // Retrieves the report of the current pending action from the server
+ private CompletableFuture getCommandReport() {
+ if (pendingAction == null) {
+ logger.warn("Tried to retrieve report but there's no pending action");
+ return null;
+ }
+ return AsyncExec.thenAsyncExec(pendingAction, x -> {
+ CommandResponse cr = Json.parse(x.getBody().toString(), CommandResponse.class);
+ if (cr.error != null)
+ throw new ServerReponseException("Error retrieving the report id");
+ String reportId = cr.reportId;
+ return Basics.getReport(reportId);
+ }, 0);
+ }
}