Leaguify cheating
authorJBM <jbm@codingame.com>
Thu, 11 Jun 2020 14:38:43 +0000 (16:38 +0200)
committerJBM <jbm@codingame.com>
Thu, 11 Jun 2020 14:38:43 +0000 (16:38 +0200)
PLAN.org
src/main/java/com/codingame/game/LeagueManager.java
src/main/java/com/codingame/game/Model.java
src/main/java/com/codingame/game/Referee.java
src/test/java/TrollTest.java

index e31b52c..25d67cd 100644 (file)
--- a/PLAN.org
+++ b/PLAN.org
 ** TODO Leagues (need multiround)
 ** TODO Multiround (need early termination)
 ** TODO Leaguification
+- [X] Cheating
+- [ ] Maps
+- [ ] Trolls
+- [ ] 
 ** DONE Early termination (need time rationalization)
 ** DONE Time rationalization (need code reorg)
 ** TODO Code cleanup
 
 That one's probably never going to be DONE ^^'
 
+- [ ] split GameManager
+
 *** organize routines by functional area
 
 *** split out what can be
index ed7d455..94a7f5f 100644 (file)
@@ -18,6 +18,9 @@ class LeagueManager {
     @Inject
     LeagueManager(MultiplayerGameManager<AbstractMultiplayerPlayer> gameManager)
     {
-        cheatLevel = CheatLevel.FORBIDDEN;
+        int level = gameManager.getLeagueLevel();
+        cheatLevel = level <= 1 ? CheatLevel.ALLOWED
+                   : level <= 2 ? CheatLevel.TOLERATED
+                   : CheatLevel.FORBIDDEN;
     }    
 }
index 108b5a6..217388a 100644 (file)
@@ -26,6 +26,11 @@ class Model {
             hit = false;
         }
 
+        void loseRound() {
+            hit = true;
+            winner = 1 - index;
+        }
+
         private int castlePosition;
         public int getCastlePosition() { return castlePosition; }
         public void setCastlePosition(int pos) { castlePosition = pos; }
index 19ef894..fb99ef9 100644 (file)
@@ -105,6 +105,7 @@ public class Referee extends AbstractReferee {
             }
             player.view.displayMessage(player.messageString);
         }
+        if (disqual) return;
 
         /* Update game model and view, stones' part.
          *
@@ -123,9 +124,19 @@ public class Referee extends AbstractReferee {
             delta += player.model.getMultiplier() * player.stoneThrow;
 
             if (player.stoneThrow < 0) {
-                disqualify(player, "CHEAT", "cheated.  Banning account.");
-                player.view.markCheat();
-                disqual = true;
+                switch(league.cheatLevel) {
+                case ALLOWED:
+                    break;
+                case TOLERATED:
+                    player.view.markCheat();
+                    if (model.random.nextInt(2) == 0) player.model.loseRound();
+                    break;
+                case FORBIDDEN:
+                    disqualify(player, "CHEAT", "cheated.  Banning account.");
+                    player.view.markCheat();
+                    disqual = true;
+                    break;
+                }
             }
             if (player.stoneThrow != 0) {
                 player.view.animateStones(player.stoneThrow);
index e8dff3f..7b998b9 100644 (file)
@@ -11,15 +11,24 @@ import org.junit.Test;
 import com.codingame.gameengine.runner.MultiplayerGameRunner;
 import com.codingame.gameengine.runner.dto.*;
 
-public class TrollTest {
-    static GameResult runGame(String left, String right) {
+public class TrollTest implements Cloneable {
+    Integer leagueLevel;
+    Long seed;
+    TrollTest branch() {
+        try { return (TrollTest) clone(); }
+        catch (CloneNotSupportedException e) { throw new InternalError(e); }
+    }
+    TrollTest setLeague(int league) { leagueLevel = league; return this; }
+    TrollTest setSeed(long seed) { this.seed = seed; return this; }
+
+    GameResult runGame(String left, String right) {
         MultiplayerGameRunner gameRunner = new MultiplayerGameRunner();
         Properties gameParameters = new Properties();
         gameParameters.setProperty("roadLength", "6");
         gameParameters.setProperty("initialStones", "15");
         gameRunner.setGameParameters(gameParameters);
-        gameRunner.setSeed(0l);
-        gameRunner.setLeagueLevel(1);
+        if (seed != null) gameRunner.setSeed(seed); else gameRunner.setSeed(0l);
+        if (leagueLevel != null) gameRunner.setLeagueLevel(leagueLevel);
 
         gameRunner.addAgent(left);
         gameRunner.addAgent(right);
@@ -48,8 +57,17 @@ public class TrollTest {
 
         // win despite fastforward after winner exhaustion
         // (harder to construct :-D )
-        assertWinLose(agent(1,2,2,2,8),
-                      agent(3,1,1,1,8));
+        assertWinLose(agent(1,2,2,2,8), agent(3,1,1,1,8));
+    }
+
+    @Test
+    public void cheatingGames() {
+        // win by cheating (works in league 1, which is the default)
+        assertWinLose(agentCheat, agentTwo);
+
+        // league 2 randomizes: we should be able to get a win and a loss
+        branch().setLeague(2).setSeed(0).assertWinLose(agentCheat, agentTwo);
+        branch().setLeague(2).setSeed(1).assertWinLose(agentTwo, agentCheat);
     }
 
     // great thanks to @dbdr for the intense moral support leading to
@@ -58,6 +76,7 @@ public class TrollTest {
     static String agentTwo = "yes 2";
     static String agentCrash = "false";
     static String agentGarbage = "yes this_is_assuredly_not_an_int";
+    static String agentCheat = agent(-100,25,25,25,25);
 
     static String agent(int... tosses) {
         String cmd = "echo -e ";
@@ -113,25 +132,33 @@ public class TrollTest {
         p.println("[agent] " + agent.agentId + ": " + agent.avatar + " " + agent.index + " " + agent.name);
     }
 
-    static void assertWinLose(String winner, String loser) {
+    void assertWinLose(String winner, String loser) {
         assertLeftWin(runGame(winner, loser));
         assertRightWin(runGame(loser, winner));
     }
 
     static void assertLeftWin(GameResult gameResult) {
+        assertLeftWin(gameResult, false);
+    }
+    static void assertLeftWin(GameResult gameResult, boolean strict) {
         int[] scores = assertTwoScores(gameResult);
         if (scores == null) return;
 
         int s1 = scores[0], s2 = scores[1];
         assertTrue("Left player has higher score than right player", s1 > s2);
+        if (strict) assertTrue("Right player isn't disqualified", s2 >= 0);
     }
 
     static void assertRightWin(GameResult gameResult) {
+        assertRightWin(gameResult, false);
+    }
+    static void assertRightWin(GameResult gameResult, boolean strict) {
         int[] scores = assertTwoScores(gameResult);
         if (scores == null) return;
 
         int s1 = scores[0], s2 = scores[1];
         assertTrue("Right player has higher score than right player", s2 > s1);
+        if (strict) assertTrue("Left player isn't disqualified", s1 >= 0);
     }
 
     static void assertIsDraw(GameResult gameResult) {