Enforce 1-stone rule. Animate defeats a bit more.
authorJBM <jbm@codingame.com>
Wed, 20 May 2020 22:40:36 +0000 (00:40 +0200)
committerJBM <jbm@codingame.com>
Wed, 20 May 2020 22:40:36 +0000 (00:40 +0200)
.gitignore
config/statement_en.html
src/main/java/com/codingame/game/Player.java
src/main/java/com/codingame/game/Referee.java
src/main/resources/view/demo.js

index 98be836..a786704 100644 (file)
@@ -4,5 +4,5 @@ target/
 .classpath
 .project
 .vscode
-.factorypath/
+.factorypath
 bin
index 88c6b65..4784b15 100644 (file)
        opinions (leave a comment on the draft submission page!)
        <ul>
          <li>
-           is it even worth publishing? can the problem be totally solved?
+           Is it even worth publishing? can the problem be totally solved?
          </li>
          <li>
-           More maps? (a map is a road length / initial stones pair)
+           More maps? (a map is a {road length} × {initial stone count} pair)
          </li>
          <li>
-           leagues? I could conceive the referee being permissive (allow 0 stones thrown) in the first one, and then strict.
+           Leagues? I could conceive the referee being permissive
+           (allow 0 stones thrown) in the first one, and then strict.
          </li>
          <li>
-           fog of war? (see only troll position, not enemy throw/stones left)<br>
-           <string>variable</string> for of war? (seeing enemy stones
-           is a boolean decided randomly as part of the map?) (or
-           seeing enemy stones only when troll is close to us?)
+           Fog of war? (see only troll position, not enemy throw/stones left)
+         </li>
+         <li>
+           <strong>variable</strong> for of war? (seeing enemy stones
+           is a boolean decided randomly as part of the map?
+         </li>
+         <li>
+           alternative fog of war? (seeing enemy stones only when
+           troll is close to us?)
          </li>
          <li>
            Praise for my artistic skillz
@@ -73,7 +79,7 @@
    <div class="statement-section statement-protocol">
      <h2>
        <span class="icon icon-protocol">&nbsp;</span>
-       <spam>I/O Protocol</spam>
+       <span>I/O Protocol</span>
      </h2>
      <div class="statement-protocol-content">
        Just read the sample code.  You can figure this out.
    <div class="statement-section statement-changelog">
      <h2>Change Log</h2>
      <ul>
+       <li>
+         Enforce the one-stone rule.  (that also fixed the legacy
+         buh&mdash;sorry people!  I put an easter egg in exchange)
+       </li>
+       <li>
+         Cutesy defeat animations.
+       </li>
+       <li>
+         Distinct castle sprites!
+       </li>
        <li>
          Terminate game when there are no more stones in sight.
        </li>
          More pretty. (SRLSLY)
        </li>
        <li>
-         No more void maps. (root cause: java <const>%</const> on a
+         No more void maps. (root cause: Java <const>%</const> on a
          negative seed)
        </li>
      </ul>
    </div>
+   <div class="statement-story-background">
+     <div class="statement-story"
+          style="position: relative; min-height: min-content">
+       <div class="story-text">
+         Based on an involuntary suggestion by
+         <span class="card" cg-codingamer-card-popup=""
+               userid="user.codingamer.userId">
+           <a class="pseudo"
+              href="/profile/dbfa96e0ac9b77a3db679628f27224ae8509333"
+              title="Zaap38">Zaap38</a>
+         </span>
+         on the #Fr channel.  The original appears to be by
+         <a href="http://andre.lovichi.free.fr/teaching/ea/2015-2016/cours/troll/Trolls_et_chateaux.pdf">
+           Romain Andr&eacute;-Lovichi
+         </a>.
+       </div>
+     </div>
+   </div>
 </div>
index 2716b17..bf40000 100644 (file)
@@ -6,9 +6,8 @@ import com.codingame.gameengine.module.entities.Text;
 import com.codingame.gameengine.module.entities.Sprite;
 
 public class Player extends AbstractMultiplayerPlayer {
-    Group hud;
+    Group avatar;
     Text stoneCounter;
-
     Sprite castle;
     Text stone;
     
index 6866b9b..5b6ec3a 100644 (file)
@@ -21,6 +21,8 @@ public class Referee extends AbstractReferee {
     @Inject private MultiplayerGameManager<Player> gameManager;
     @Inject private GraphicEntityModule graphicEntityModule;
 
+    Random random;
+
     int roadLength;
     int initialStones;
     int trollPosition;
@@ -30,7 +32,8 @@ public class Referee extends AbstractReferee {
     
     @Override
     public void init() {
-        switch (new Random(gameManager.getSeed()).nextInt(4)) {
+        random = new Random(gameManager.getSeed());
+        switch (random.nextInt(4)) {
         case 0:
             roadLength = 7;
             initialStones = 15;
@@ -104,15 +107,7 @@ public class Referee extends AbstractReferee {
                     .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()
+            Sprite avatarSprite = graphicEntityModule.createSprite()
                     .setX(x)
                     .setY(y)
                     .setZIndex(20)
@@ -121,7 +116,17 @@ public class Referee extends AbstractReferee {
                     .setBaseHeight(116)
                     .setBaseWidth(116);
 
-            Text stoneCounter = graphicEntityModule.createText("S")
+            player.avatar = graphicEntityModule.createGroup(border1, border2, avatarSprite);
+
+            Text text = graphicEntityModule.createText(player.getNicknameToken())
+                    .setX(x)
+                    .setY(y + 120)
+                    .setZIndex(20)
+                    .setFontSize(40)
+                    .setFillColor(0x7f3f00)
+                    .setAnchor(0.5);
+
+            player.stoneCounter = graphicEntityModule.createText("S")
                 .setX(x)
                 .setY(y+200)
                 .setZIndex(20)
@@ -131,11 +136,13 @@ public class Referee extends AbstractReferee {
 
             player.castle = graphicEntityModule.createSprite()
                 .setImage("castle.png")
+                .setTint(player.getColorToken())
                 .setX(p0 ? 160 : 1920-160)
                 .setY(p0 ? 890 : 880)
                 .setZIndex(1)
                 .setAnchorX(0.5)
-                .setAnchorY(1);
+                .setAnchorY(1)
+                .setScaleX(p0 ? 1 : -1);
 
             player.stone = graphicEntityModule.createText()
                 .setZIndex(3)
@@ -144,8 +151,6 @@ public class Referee extends AbstractReferee {
                 .setAnchor(0.5)
                 .setAlpha(0);
 
-            player.hud = graphicEntityModule.createGroup(border1, border2, text, avatar, stoneCounter, player.castle);
-            player.stoneCounter = stoneCounter;
         }
     }
 
@@ -203,12 +208,27 @@ public class Referee extends AbstractReferee {
         int delta = 0;
         for (Player player : gameManager.getActivePlayers()) {
             try {
-                final int stones = player.getAction();
+                int stones = player.getAction();
+                if (stones == 0 && player.getStones() > 0) {
+                    if (random.nextInt(10) > 0) {
+                        gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " tried not throwing stones.  Fixing that for them because I'm in a good mood today."));
+                        stones = 1;
+                    }
+                    else {
+                        throw new InvalidAction("tried not throwing any stone.  They were then eaten by a grue.");
+                    }
+                }
                 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) {
+                if (stones < 0) {
+                    player.deactivate(player.getNicknameToken() + " CHEAT");
+                    gameManager.addToGameSummary(GameManager.formatErrorMessage(player.getNicknameToken() + " cheated.  Banning account."));
+                    player.setScore(-1);
+                    endGame();
+                }
+                else if (stones > 0) {
                     player.stone.setX(player.castle.getX());
                     player.stone.setY(player.castle.getY() - 100);
                     player.stone.setText(new Integer(stones).toString());
@@ -275,21 +295,32 @@ public class Referee extends AbstractReferee {
         }
     }
 
+    private void destroyPlayer(Player player) {
+        player.avatar.setRotation(170*Math.PI/180, Curve.ELASTIC);
+
+        graphicEntityModule.commitEntityState(0.5, player.castle);
+        player.castle.setX(player.castle.getX(), Curve.ELASTIC);
+        player.castle.setScaleY(-0.2, Curve.EASE_IN);
+    }
+
     private void endGame() {
         gameManager.endGame();
 
         if (p0.getScore() > p1.getScore()) {
             gameManager.addToGameSummary(GameManager.formatSuccessMessage(p0.getNicknameToken() + " wins"));
-            p1.hud.setAlpha(0.3);
+            destroyPlayer(p1);
         }
         else if (p0.getScore() < p1.getScore()) {
             gameManager.addToGameSummary(GameManager.formatSuccessMessage(p1.getNicknameToken() + " wins"));
-            p0.hud.setAlpha(0.3);
+            destroyPlayer(p0);
         }
-        else {
+        else if (p0.getScore() < 0) {
             gameManager.addToGameSummary(GameManager.formatErrorMessage("Everybody loses!"));
-            p0.hud.setAlpha(0.3);
-            p1.hud.setAlpha(0.3);
+            destroyPlayer(p0);
+            destroyPlayer(p1);
+        }
+        else {
+            gameManager.addToGameSummary("Draw.");
         }
     }
 }
index 7c3c397..767fa2a 100644 (file)
@@ -1,2 +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}]};
+{"views":["KEY_FRAME 0\n{\"global\":{\"entitymodule\":{\"width\":1920,\"height\":1080}},\"frame\":{\"duration\":2000,\"entitymodule\":\"CS;R;R;S;G;T;T;S;T;R;R;S;G;T;T;S;T;S;T\\nU12 1 bw 116 i $1 ay 0.5 v 1 ax 0.5 x 1640 y 220 bh 116 z 20;4 1 bw 116 i $0 ay 0.5 v 1 ax 0.5 x 280 y 220 bh 116 z 20;11 1 f 16777215 v 1 w 120 x 1580 y 160 W 0 h 120;16 1 sx -1 i castle.png ay 1 v 1 ax 0.5 x 1760 y 880 t -2 z 1;10 1 f -2 v 1 w 140 x 1570 y 150 W 0 h 140;13 1 ch 12,11,10 v 1;5 1 ch 3,4,2 v 1;6 1 f 8339200 ay 0.5 v 1 ax 0.5 x 280 y 340 s 40 T $0 z 20;3 1 f 16777215 v 1 w 120 x 220 y 160 W 0 h 120;1 1 i background.png ay 0 v 1 ax 0;17 1 f 1192490 ay 0.5 v 1 ax 0.5 a 0 s 150 z 3;7 1 f 8339200 ay 0.5 v 1 ax 0.5 x 280 y 420 s 40 T '30 stones' z 20;14 1 f 8339200 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;2 1 f -1 v 1 w 140 x 210 y 150 W 0 h 140;8 1 sx 1 i castle.png ay 1 v 1 ax 0.5 x 160 y 890 t -1 z 1;15 1 f 8339200 ay 0.5 v 1 ax 0.5 x 1640 y 420 s 40 T '30 stones' z 20;19 1 f 16777215 ay 0.5 v 1 ax 0.5 x 990 y 980 s 40 z 2;9 1 f 1192490 ay 0.5 v 1 ax 0.5 a 0 s 150 z 3\"}}\n","INTERMEDIATE_FRAME 1\n","KEY_FRAME 2\n{\"entitymodule\":\"U17 0 a 1 x 1760 y 780 T 2;9 0 a 1 x 160 y 790 T 1;17 0.25 x 1360 y 540 🙒;7 0.25 T '29 stones';15 0.25 T '28 stones';9 0.25 x 560 y 540 🙒;17 0.5 a 0 🙖 x 960 y 830 🙖;18 0.5;19 0.5;9 0.5 a 0 🙖 x 960 y 830 🙖;19 0.75 x 841 T '← 1';18 1 x 693 ~ y 887 ~;19 1 x 693\"}\n","INTERMEDIATE_FRAME 3\n","KEY_FRAME 4\n{\"entitymodule\":\"U17 0 a 1 x 1760 y 780 T 18;9 0 a 1 x 160 y 790;17 0.25 x 1226 y 540 🙒;7 0.25 T '28 stones';15 0.25 T '10 stones';9 0.25 x 426 y 540 🙒;17 0.5 a 0 🙖 x 693 y 837 🙖;18 0.5;19 0.5;9 0.5 a 0 🙖 x 693 y 837 🙖;19 0.75 x 559 T '← 2';18 1 x 426 ~ y 889 ~;19 1 x 426\"}\n","INTERMEDIATE_FRAME 5\n","KEY_FRAME 6\n{\"entitymodule\":\"U17 0 a 1 x 1760 y 780 T 8;9 0 a 1 x 160 y 790;17 0.25 x 1093 y 540 🙒;7 0.25 T '27 stones';15 0.25 T '2 stones';9 0.25 x 293 y 540 🙒;17 0.5 a 0 🙖 x 426 y 839 🙖;18 0.5;19 0.5;8 0.5;9 0.5 a 0 🙖 x 426 y 839 🙖;19 0.75 x 293 T '← 3';18 1 x 160 ~ y 890 ~;8 1 sy -0.2 🙖;19 1 x 160;5 1 r 170 ~\"}\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}]};