--- /dev/null
+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));
+ }
+}
--- /dev/null
+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);
+ }
+ }
+}