Initial commit
authorJBM <jbm@codingame.com>
Wed, 20 May 2020 13:21:22 +0000 (15:21 +0200)
committerJBM <jbm@codingame.com>
Wed, 20 May 2020 13:21:22 +0000 (15:21 +0200)
20 files changed:
.gitignore [new file with mode: 0644]
config/Boss.java [new file with mode: 0644]
config/Boss.sh [new file with mode: 0644]
config/config.ini [new file with mode: 0644]
config/statement_en.html [new file with mode: 0644]
config/stub.txt [new file with mode: 0644]
pom.xml [new file with mode: 0644]
src/main/java/com/codingame/game/InvalidAction.java [new file with mode: 0644]
src/main/java/com/codingame/game/Player.java [new file with mode: 0644]
src/main/java/com/codingame/game/Referee.java [new file with mode: 0644]
src/main/resources/view/assets/background.png [new file with mode: 0644]
src/main/resources/view/assets/castle.png [new file with mode: 0644]
src/main/resources/view/assets/game.xcf [new file with mode: 0644]
src/main/resources/view/assets/troll.png [new file with mode: 0644]
src/main/resources/view/config.js [new file with mode: 0644]
src/main/resources/view/demo.js [new file with mode: 0644]
src/test/java/Main.java [new file with mode: 0644]
src/test/java/Player1.java [new file with mode: 0644]
src/test/java/Player2.java [new file with mode: 0644]
src/test/resources/log4j2.properties [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..54e1393
--- /dev/null
@@ -0,0 +1,7 @@
+.idea/
+target/
+.settings
+.classpath
+.project
+.vscode
+bin
\ No newline at end of file
diff --git a/config/Boss.java b/config/Boss.java
new file mode 100644 (file)
index 0000000..d3c297d
--- /dev/null
@@ -0,0 +1,20 @@
+import java.util.Random;
+import java.util.Scanner;
+
+public class Player2 {
+    public static void main(String[] args) {
+        Scanner in = new Scanner(System.in);
+        Random random = new Random(0);
+
+        int roadLength = in.nextInt();
+        int initialStones = in.nextInt();
+
+        while (true) {
+            int trollDistance = in.nextInt();
+            int stones = in.nextInt();
+            int opponentStones = in.nextInt();
+           
+            System.out.println(random.nextInt(stones+1));
+        }
+    }
+}
diff --git a/config/Boss.sh b/config/Boss.sh
new file mode 100644 (file)
index 0000000..0b3832f
--- /dev/null
@@ -0,0 +1 @@
+exec yes 1
diff --git a/config/config.ini b/config/config.ini
new file mode 100644 (file)
index 0000000..2002eb1
--- /dev/null
@@ -0,0 +1,4 @@
+title=Castle Troll
+min_players=2
+max_players=2
+type=multi
\ No newline at end of file
diff --git a/config/statement_en.html b/config/statement_en.html
new file mode 100644 (file)
index 0000000..83c0e4e
--- /dev/null
@@ -0,0 +1,22 @@
+<div class="statement-body"> 
+   <!-- GOAL --> 
+   <div class="statement-section statement-goal"> 
+     <h2> 
+       <span class="icon icon-goal">&nbsp;</span> 
+       <span>The Goal</span> 
+     </h2> 
+     <div class="statement-goal-content"> 
+       Don't get destroyed by the troll.
+     </div>
+   </div> 
+   <!-- RULES --> 
+   <div class="statement-section statement-rules"> 
+     <h2> 
+       <span class="icon icon-rules">&nbsp;</span> 
+       <span>Rules</span> 
+     </h2> 
+     <div class="statement-rules-content">
+       In the classic version, you <em>have</em> to shoot at least one stone per turn.  This isn't enforced yet.
+     </div> 
+   </div>
+</div>
diff --git a/config/stub.txt b/config/stub.txt
new file mode 100644 (file)
index 0000000..88c3d38
--- /dev/null
@@ -0,0 +1,17 @@
+read roadLength:int initialStones:int
+gameloop
+read trollDistance:int stones:int opponentStones:int
+write 1
+
+STATEMENT
+Keep the troll out of your castle!
+
+INPUT
+roadLength: the length of the road between both castles. The troll starts in the middle.
+initialStones: the number of stones each castle starts with
+trollDistance: distance between the troll and your castle. Keep it above zero!
+stones: number of stones left
+opponentStones: number of stones left to your opponent
+
+OUTPUT
+number of stones to shoot at the troll
diff --git a/pom.xml b/pom.xml
new file mode 100644 (file)
index 0000000..8c64961
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,35 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+
+       <groupId>com.codingame.game</groupId>
+       <artifactId>castle-troll</artifactId>
+       <version>0.5-git</version>
+
+       <properties>
+               <gamengine.version>3.13.1</gamengine.version>
+               <maven.compiler.source>1.8</maven.compiler.source>
+               <maven.compiler.target>1.8</maven.compiler.target>
+       </properties>
+
+       <dependencies>
+               <dependency>
+                       <groupId>com.codingame.gameengine</groupId>
+                       <artifactId>core</artifactId>
+                       <version>${gamengine.version}</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>com.codingame.gameengine</groupId>
+                       <artifactId>module-entities</artifactId>
+                       <version>${gamengine.version}</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>com.codingame.gameengine</groupId>
+                       <artifactId>runner</artifactId>
+                       <version>${gamengine.version}</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/src/main/java/com/codingame/game/InvalidAction.java b/src/main/java/com/codingame/game/InvalidAction.java
new file mode 100644 (file)
index 0000000..5681dd9
--- /dev/null
@@ -0,0 +1,10 @@
+package com.codingame.game;
+
+public class InvalidAction extends Exception {
+    private static final long serialVersionUID = -8185589153224401564L;
+
+    public InvalidAction(String message) {
+        super(message);
+    }
+
+}
diff --git a/src/main/java/com/codingame/game/Player.java b/src/main/java/com/codingame/game/Player.java
new file mode 100644 (file)
index 0000000..2716b17
--- /dev/null
@@ -0,0 +1,70 @@
+package com.codingame.game;
+
+import com.codingame.gameengine.core.AbstractMultiplayerPlayer;
+import com.codingame.gameengine.module.entities.Group;
+import com.codingame.gameengine.module.entities.Text;
+import com.codingame.gameengine.module.entities.Sprite;
+
+public class Player extends AbstractMultiplayerPlayer {
+    Group hud;
+    Text stoneCounter;
+
+    Sprite castle;
+    Text stone;
+    
+
+    private int castlePosition;
+    public int getCastlePosition() {
+        return castlePosition;
+    }
+    public void setCastlePosition(int pos) {
+        castlePosition = pos;
+    }
+
+    private int stones;
+    public int getStones()
+    {
+        return stones;
+    }
+    public void consumeStones(int n) throws InvalidAction {
+        if (n > stones) {
+            throw new InvalidAction("attempted to throw more stones than they had.");
+        }
+        setStones(stones - n);
+    }
+    public void setStones(int n) {
+        stones = n;
+        if (stones <= 0) {
+            stoneCounter.setText("No stones!");
+            stoneCounter.setFillColor(0xff7777);
+        }
+        else if (stones == 1) {
+            stoneCounter.setText("1 stone");
+            stoneCounter.setFillColor(0xffbb77);
+        }
+        else {
+            stoneCounter.setText(stones + " stones");
+        }
+    }
+
+    private int multiplier;
+    public int getMultiplier() {
+        return multiplier;
+    }
+    public void setMultiplier(int m){
+        multiplier = m;
+    }
+
+    public void adjustScore(int trollPosition) {
+        setScore(Math.abs(castlePosition - trollPosition));
+    }
+
+    @Override
+    public int getExpectedOutputLines() {
+        return 1;
+    }
+
+    public int getAction() throws TimeoutException, NumberFormatException {
+        return Integer.parseInt(getOutputs().get(0));
+    }
+}
diff --git a/src/main/java/com/codingame/game/Referee.java b/src/main/java/com/codingame/game/Referee.java
new file mode 100644 (file)
index 0000000..4b1315b
--- /dev/null
@@ -0,0 +1,291 @@
+package com.codingame.game;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+
+import com.codingame.gameengine.core.AbstractPlayer.TimeoutException;
+import com.codingame.gameengine.core.AbstractReferee;
+import com.codingame.gameengine.core.GameManager;
+import com.codingame.gameengine.core.MultiplayerGameManager;
+import com.codingame.gameengine.module.entities.GraphicEntityModule;
+import com.codingame.gameengine.module.entities.Rectangle;
+import com.codingame.gameengine.module.entities.Sprite;
+import com.codingame.gameengine.module.entities.Text;
+import com.codingame.gameengine.module.entities.Curve;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+public class Referee extends AbstractReferee {
+    @Inject private MultiplayerGameManager<Player> gameManager;
+    @Inject private GraphicEntityModule graphicEntityModule;
+
+    int roadLength;
+    int initialStones;
+    int trollPosition;
+    Player p0, p1;
+    Sprite troll;
+    Text trollPositionGauge;
+    
+    @Override
+    public void init() {
+        switch (new Random(gameManager.getSeed()).nextInt(4)) {
+        case 0:
+            roadLength = 7;
+            initialStones = 15;
+            break;
+        case 1:
+            roadLength = 7;
+            initialStones = 30;
+            break;
+        case 2:
+            roadLength = 15;
+            initialStones = 30;
+            break;
+        case 3:
+            roadLength = 15;
+            initialStones = 50;
+            break;
+        }
+
+        trollPosition = (roadLength - 1) / 2;
+
+        p0 = gameManager.getPlayer(0);
+        p0.setCastlePosition(0);
+        p0.setMultiplier(1);
+        p0.adjustScore(trollPosition);
+        p0.sendInputLine(String.format("%d %d", roadLength - 1, initialStones));
+
+        p1 = gameManager.getPlayer(1);
+        p1.setCastlePosition(roadLength-1);
+        p1.setMultiplier(-1);
+        p1.adjustScore(trollPosition);
+        p1.sendInputLine(String.format("%d %d", roadLength - 1, initialStones));
+
+        drawBackground();
+        drawPlayer();
+        drawTroll();
+
+        // result in text display, so do last:
+        p0.setStones(initialStones);
+        p1.setStones(initialStones);
+
+        gameManager.setFrameDuration(2000);
+    }
+
+    private void drawBackground() {
+        graphicEntityModule.createSprite()
+                .setImage("background.png")
+                .setAnchor(0);
+    }
+
+    private void drawPlayer() {
+        for (Player player : gameManager.getPlayers()) {
+            boolean p0 = player.getIndex() == 0;
+            int x = p0 ? 280 : 1920 - 280;
+            int y = 220;
+
+            Rectangle border1 = graphicEntityModule
+                    .createRectangle()
+                    .setWidth(140)
+                    .setHeight(140)
+                    .setX(x - 70)
+                    .setY(y - 70)
+                    .setLineWidth(0)
+                    .setFillColor(player.getColorToken());
+
+            Rectangle border2 = graphicEntityModule
+                    .createRectangle()
+                    .setWidth(120)
+                    .setHeight(120)
+                    .setX(x - 60)
+                    .setY(y - 60)
+                    .setLineWidth(0)
+                    .setFillColor(0xffffff);
+
+            Text text = graphicEntityModule.createText(player.getNicknameToken())
+                    .setX(x)
+                    .setY(y + 120)
+                    .setZIndex(20)
+                    .setFontSize(40)
+                    .setFillColor(0x7f3f00)
+                    .setAnchor(0.5);
+
+            Sprite avatar = graphicEntityModule.createSprite()
+                    .setX(x)
+                    .setY(y)
+                    .setZIndex(20)
+                    .setImage(player.getAvatarToken())
+                    .setAnchor(0.5)
+                    .setBaseHeight(116)
+                    .setBaseWidth(116);
+
+            Text stoneCounter = graphicEntityModule.createText("S")
+                .setX(x)
+                .setY(y+200)
+                .setZIndex(20)
+                .setFontSize(40)
+                .setFillColor(0x7f3f00)
+                .setAnchor(0.5);
+
+            player.castle = graphicEntityModule.createSprite()
+                .setImage("castle.png")
+                .setX(p0 ? 160 : 1920-160)
+                .setY(p0 ? 890 : 880)
+                .setZIndex(1)
+                .setAnchorX(0.5)
+                .setAnchorY(1);
+
+            player.stone = graphicEntityModule.createText()
+                .setZIndex(3)
+                .setFontSize(150)
+                .setFillColor(0x12322a)
+                .setAnchor(0.5)
+                .setAlpha(0);
+
+            player.hud = graphicEntityModule.createGroup(border1, border2, text, avatar, stoneCounter, player.castle);
+            player.stoneCounter = stoneCounter;
+        }
+    }
+
+    private void drawTroll() {
+        troll = graphicEntityModule.createSprite()
+            .setImage("troll.png")
+            .setAnchorX(0.5)
+            .setAnchorY(1)
+            .setX(1920/2)
+            .setY(880)
+            .setZIndex(2);
+        trollPositionGauge = graphicEntityModule.createText()
+            .setZIndex(2)
+            .setAnchor(0.5)
+            .setFontSize(40)
+            .setX(1980/2)
+            .setY(980)
+            .setFillColor(0xffffff);
+    }
+
+    private void moveTroll() {
+        graphicEntityModule.commitEntityState(0.5, troll, trollPositionGauge);
+        int x0 = p0.castle.getX(), x1 = p1.castle.getX();
+        int y0 = p0.castle.getY(), y1 = p1.castle.getY();
+        troll.setX(x0 + trollPosition * (x1-x0) / (roadLength - 1),
+                   Curve.ELASTIC);
+        troll.setY(y0 + trollPosition * (y1-y0) / (roadLength - 1),
+                   Curve.ELASTIC);
+
+        trollPositionGauge.setX((trollPositionGauge.getX() + troll.getX()) / 2);
+        int delta = trollPosition - (roadLength - 1) / 2;
+        if (delta < 0) {
+            trollPositionGauge.setText("← " + Math.abs(delta));
+        }
+        else if (delta > 0) {
+            trollPositionGauge.setText(Math.abs(delta) + " →");
+        }
+        else {
+            trollPositionGauge.setText("↔");
+        }
+        graphicEntityModule.commitEntityState(0.75, trollPositionGauge);
+        trollPositionGauge.setX(troll.getX());
+    }
+
+    @Override
+    public void gameTurn(int turn) {
+
+        p0.sendInputLine(String.format("%d %d %d", p0.getScore(), p0.getStones(), p1.getStones()));
+        p1.sendInputLine(String.format("%d %d %d", p1.getScore(), p1.getStones(), p0.getStones()));
+
+        for (Player player : gameManager.getActivePlayers()) {
+            player.execute();
+        }
+
+        int delta = 0;
+        for (Player player : gameManager.getActivePlayers()) {
+            try {
+                final int stones = player.getAction();
+                player.consumeStones(stones);
+                gameManager.addToGameSummary(String.format("%s throws %d stone%s at the troll.", player.getNicknameToken(), stones, stones == 1 ? "" : "s"));
+                delta += player.getMultiplier() * stones;
+
+                if (stones > 0) {
+                    player.stone.setX(player.castle.getX());
+                    player.stone.setY(player.castle.getY() - 100);
+                    player.stone.setText(new Integer(stones).toString());
+                    player.stone.setAlpha(1);
+                    graphicEntityModule.commitEntityState(0, player.stone);
+    
+                    int peakX = (player.castle.getX() + troll.getX()) / 2;
+                    int peakY = 540;
+                    player.stone.setX(peakX);
+                    player.stone.setY(peakY, Curve.EASE_OUT);
+                    graphicEntityModule.commitEntityState(0.25, player.stone,
+                                                          player.stoneCounter);
+    
+                    player.stone.setX(troll.getX());
+                    player.stone.setY(troll.getY() - 50, Curve.EASE_IN);
+                    player.stone.setAlpha(0, Curve.EASE_IN);
+                    graphicEntityModule.commitEntityState(0.5, player.stone);
+                }
+            }
+            catch (InvalidAction e) {
+                player.deactivate(player.getNicknameToken() + " INVALID");
+                gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " " + e.getMessage()));
+                player.setScore(-1);
+                endGame();
+            }
+            catch (NumberFormatException e) {
+                player.deactivate(player.getNicknameToken() + " ERROR");
+                gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " provided malformed input!"));
+                player.setScore(-1);
+                endGame();
+            }
+            catch (TimeoutException e) {
+                gameManager.addToGameSummary(player.getNicknameToken() + " timed out!");
+                player.deactivate(player.getNicknameToken() + " T/O");
+                player.setScore(-1);
+                endGame();
+            }
+        }
+
+        if (delta > 0) {
+            gameManager.addToGameSummary("Troll walks right.");
+            trollPosition++;
+            moveTroll();
+        }
+        else if (delta < 0) {
+            gameManager.addToGameSummary("Troll walks left.");
+            trollPosition--;
+            moveTroll();
+        }
+        else {
+            gameManager.addToGameSummary("Troll stands still.");
+        }
+
+        for (Player player : gameManager.getActivePlayers()) {
+            player.adjustScore(trollPosition);
+            if (trollPosition == player.getCastlePosition()) {
+                gameManager.addToGameSummary(GameManager.formatErrorMessage("Troll destroys " + player.getNicknameToken()));
+                endGame();
+            }
+        }
+    }
+
+    private void endGame() {
+        gameManager.endGame();
+
+        if (p0.getScore() > p1.getScore()) {
+            gameManager.addToGameSummary(GameManager.formatSuccessMessage(p0.getNicknameToken() + " wins"));
+            p1.hud.setAlpha(0.3);
+        }
+        else if (p0.getScore() < p1.getScore()) {
+            gameManager.addToGameSummary(GameManager.formatSuccessMessage(p1.getNicknameToken() + " wins"));
+            p0.hud.setAlpha(0.3);
+        }
+        else {
+            gameManager.addToGameSummary(GameManager.formatErrorMessage("Everybody loses!"));
+            p0.hud.setAlpha(0.3);
+            p1.hud.setAlpha(0.3);
+        }
+    }
+}
diff --git a/src/main/resources/view/assets/background.png b/src/main/resources/view/assets/background.png
new file mode 100644 (file)
index 0000000..4b31ba2
Binary files /dev/null and b/src/main/resources/view/assets/background.png differ
diff --git a/src/main/resources/view/assets/castle.png b/src/main/resources/view/assets/castle.png
new file mode 100644 (file)
index 0000000..22d4c08
Binary files /dev/null and b/src/main/resources/view/assets/castle.png differ
diff --git a/src/main/resources/view/assets/game.xcf b/src/main/resources/view/assets/game.xcf
new file mode 100644 (file)
index 0000000..8384687
Binary files /dev/null and b/src/main/resources/view/assets/game.xcf differ
diff --git a/src/main/resources/view/assets/troll.png b/src/main/resources/view/assets/troll.png
new file mode 100644 (file)
index 0000000..be7d5d5
Binary files /dev/null and b/src/main/resources/view/assets/troll.png differ
diff --git a/src/main/resources/view/config.js b/src/main/resources/view/config.js
new file mode 100644 (file)
index 0000000..50b1654
--- /dev/null
@@ -0,0 +1,12 @@
+import { GraphicEntityModule } from './entity-module/GraphicEntityModule.js';
+
+export const gameName = 'Castle-Troll';
+
+export const playerColors = [
+  '#f2b213', // yellow
+  '#22a1e4' // curious blue
+];
+
+export const modules = [
+       GraphicEntityModule
+];
diff --git a/src/main/resources/view/demo.js b/src/main/resources/view/demo.js
new file mode 100644 (file)
index 0000000..7c3c397
--- /dev/null
@@ -0,0 +1,2 @@
+export const demo = 
+{"views":["KEY_FRAME 0\n{\"global\":{\"entitymodule\":{\"width\":1920,\"height\":1080}},\"frame\":{\"duration\":2000,\"entitymodule\":\"CS;R;R;T;S;T;S;T;G;R;R;T;S;T;S;T;G;S\\nU15 1 i castle.png ay 1 v 1 ax 0.5 x 1640 y 880 z 1;2 1 f -1 v 1 w 140 x 210 y 150 W 0 h 140;16 1 f 1192490 ay 0.5 v 1 ax 0.5 a 0 s 150 z 3;1 1 i background.png ay 0 v 1 ax 0;7 1 i castle.png ay 1 v 1 ax 0.5 x 280 y 887 z 1;6 1 f 16777215 ay 0.5 v 1 ax 0.5 x 280 y 420 s 40 T '15 stones' z 20;14 1 f 16777215 ay 0.5 v 1 ax 0.5 x 1640 y 420 s 40 T '15 stones' z 20;3 1 f 16777215 v 1 w 120 x 220 y 160 W 0 h 120;17 1 ch 15,13,12,10,14,11 v 1;13 1 bw 116 i $1 ay 0.5 v 1 ax 0.5 x 1640 y 220 bh 116 z 20;8 1 f 1192490 ay 0.5 v 1 ax 0.5 a 0 s 150 z 3;12 1 f 16777215 ay 0.5 v 1 ax 0.5 x 1640 y 340 s 40 T $1 z 20;18 1 i troll.png ay 1 v 1 ax 0.5 x 960 y 880 z 2;5 1 bw 116 i $0 ay 0.5 v 1 ax 0.5 x 280 y 220 bh 116 z 20;9 1 ch 3,2,7,5,6,4 v 1;10 1 f -2 v 1 w 140 x 1570 y 150 W 0 h 140;4 1 f 16777215 ay 0.5 v 1 ax 0.5 x 280 y 340 s 40 T $0 z 20;11 1 f 16777215 v 1 w 120 x 1580 y 160 W 0 h 120\"}}\n","INTERMEDIATE_FRAME 1\n","KEY_FRAME 2\n{\"entitymodule\":\"U16 0 a 1 x 1640 y 780 T 11;8 0 a 1 x 280 y 787 T 1;16 0.25 x 1300 y 540 🙒;8 0.25 x 620 y 540 🙒;16 0.5 a 0 🙖 x 960 y 830 🙖;8 0.5 a 0 🙖 x 960 y 830 🙖;18 0.5;18 1 x 713 ~;6 1 T '14 stones';14 1 T '4 stones'\"}\n","INTERMEDIATE_FRAME 3\n","KEY_FRAME 4\n{\"entitymodule\":\"U16 0 a 1 x 1640 y 780 T 3;8 0 a 1 x 280 y 787;16 0.25 x 1176 y 540 🙒;8 0.25 x 496 y 540 🙒;16 0.5 a 0 🙖 x 713 y 830 🙖;8 0.5 a 0 🙖 x 713 y 830 🙖;18 0.5;18 1 x 466 ~;6 1 T '13 stones';14 1 f 16759671 T '1 stone'\"}\n","INTERMEDIATE_FRAME 5\n","KEY_FRAME 6\n{\"entitymodule\":\"U8 0 a 1 x 280 y 787;8 0.25 x 373 y 540 🙒;8 0.5 a 0 🙖 x 466 y 830 🙖;18 0.5;18 1 x 713 ~;6 1 T '12 stones'\"}\n","INTERMEDIATE_FRAME 7\n","KEY_FRAME 8\n{\"entitymodule\":\"U16 0 a 1 x 1640 y 780 T 1;8 0 a 1 x 280 y 787;16 0.25 x 1176 y 540 🙒;8 0.25 x 496 y 540 🙒;16 0.5 a 0 🙖 x 713 y 830 🙖;8 0.5 a 0 🙖 x 713 y 830 🙖;6 1 T '11 stones';14 1 f 16742263 T 'No stones!'\"}\n","INTERMEDIATE_FRAME 9\n","KEY_FRAME 10\n{\"entitymodule\":\"U8 0 a 1 x 280 y 787;8 0.25 x 496 y 540 🙒;8 0.5 a 0 🙖 x 713 y 830 🙖;18 0.5;18 1 x 960 ~;6 1 T '10 stones'\"}\n","INTERMEDIATE_FRAME 11\n","KEY_FRAME 12\n{\"entitymodule\":\"U8 0 a 1 x 280 y 787;8 0.25 x 620 y 540 🙒;8 0.5 a 0 🙖 x 960 y 830 🙖;18 0.5;18 1 x 1206 ~;6 1 T '9 stones'\"}\n","INTERMEDIATE_FRAME 13\n","KEY_FRAME 14\n{\"entitymodule\":\"U8 0 a 1 x 280 y 787;8 0.25 x 743 y 540 🙒;8 0.5 a 0 🙖 x 1206 y 830 🙖;18 0.5;18 1 x 1453 ~;6 1 T '8 stones'\"}\n","INTERMEDIATE_FRAME 15\n","KEY_FRAME 16\n{\"entitymodule\":\"U8 0 a 1 x 280 y 787;8 0.25 x 866 y 540 🙒;8 0.5 a 0 🙖 x 1453 y 830 🙖;18 0.5;17 1 a 0.3;18 1 x 1700 ~;6 1 T '7 stones'\"}\n"],"agents":[{"index":0,"name":"Player 0","avatar":"https://static.codingame.com/servlet/fileservlet?id=16085713250612&format=viewer_avatar","agentId":0},{"index":1,"name":"Player 1","avatar":"https://static.codingame.com/servlet/fileservlet?id=16085756802960&format=viewer_avatar","agentId":1}]};
diff --git a/src/test/java/Main.java b/src/test/java/Main.java
new file mode 100644 (file)
index 0000000..956794c
--- /dev/null
@@ -0,0 +1,19 @@
+import com.codingame.gameengine.runner.MultiplayerGameRunner;
+
+public class Main {
+    public static void main(String[] args) {
+        
+        MultiplayerGameRunner gameRunner = new MultiplayerGameRunner();
+        gameRunner.addAgent(Player1.class);
+        gameRunner.addAgent(Player2.class);
+        
+        // gameRunner.addAgent("python3 /home/user/player.py");
+        
+        // The first league is classic tic-tac-toe
+        gameRunner.setLeagueLevel(1);
+        // The second league is ultimate tic-tac-toe
+        // gameRunner.setLeagueLevel(2);
+        
+        gameRunner.start();
+    }
+}
diff --git a/src/test/java/Player1.java b/src/test/java/Player1.java
new file mode 100644 (file)
index 0000000..bc78cb2
--- /dev/null
@@ -0,0 +1,21 @@
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.Scanner;
+
+public class Player1 {
+    public static void main(String[] args) {
+        Scanner in = new Scanner(System.in);
+
+        int roadLength = in.nextInt();
+        int initialStones = in.nextInt();
+
+        while (true) {
+            int trollDistance = in.nextInt();
+            int stones = in.nextInt();
+            int opponentStones = in.nextInt();
+           
+            System.out.println(1);
+        }
+    }
+}
diff --git a/src/test/java/Player2.java b/src/test/java/Player2.java
new file mode 100644 (file)
index 0000000..d3c297d
--- /dev/null
@@ -0,0 +1,20 @@
+import java.util.Random;
+import java.util.Scanner;
+
+public class Player2 {
+    public static void main(String[] args) {
+        Scanner in = new Scanner(System.in);
+        Random random = new Random(0);
+
+        int roadLength = in.nextInt();
+        int initialStones = in.nextInt();
+
+        while (true) {
+            int trollDistance = in.nextInt();
+            int stones = in.nextInt();
+            int opponentStones = in.nextInt();
+           
+            System.out.println(random.nextInt(stones+1));
+        }
+    }
+}
diff --git a/src/test/resources/log4j2.properties b/src/test/resources/log4j2.properties
new file mode 100644 (file)
index 0000000..4ca7574
--- /dev/null
@@ -0,0 +1,11 @@
+# Configuration
+name = PropertiesConfig
+status = WARN
+
+appender.console.type = Console
+appender.console.name = CONSOLE
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = [%d{yyyy/MM/dd HH:mm:ss}][GF] %-5p : %c{1} - %m%n
+
+rootLogger.level = warn
+rootLogger.appenderRef.console.ref = CONSOLE