diff --git a/out/production/sp21-cs242-assignment1/RuleController.class b/out/production/sp21-cs242-assignment1/RuleController.class index 3cbec0e8bc6d73ca34e345d23260d98e2851eae0..4cd51c49ff5cbf5b60e2373a96937b5d4bb4fb78 100644 Binary files a/out/production/sp21-cs242-assignment1/RuleController.class and b/out/production/sp21-cs242-assignment1/RuleController.class differ diff --git a/out/test/sp21-cs242-assignment1/CardParserTest.class b/out/test/sp21-cs242-assignment1/CardParserTest.class deleted file mode 100644 index 794bde9fda9c4cea84edd5984070d1824519a500..0000000000000000000000000000000000000000 Binary files a/out/test/sp21-cs242-assignment1/CardParserTest.class and /dev/null differ diff --git a/out/test/sp21-cs242-assignment1/RuleControllerTest.class b/out/test/sp21-cs242-assignment1/RuleControllerTest.class index 193d470dab21a84f25e59a09e3affae987875f93..d81b897b07ecfc6a709c8c887add8725d235eada 100644 Binary files a/out/test/sp21-cs242-assignment1/RuleControllerTest.class and b/out/test/sp21-cs242-assignment1/RuleControllerTest.class differ diff --git a/src/Test/CardParserTest.java b/src/Test/CardParserTest.java deleted file mode 100644 index 9c4a698c7e06566222d006246150aec3cc378757..0000000000000000000000000000000000000000 --- a/src/Test/CardParserTest.java +++ /dev/null @@ -1,18 +0,0 @@ -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class CardParserTest { - - @Test - void parseCardID() { - } - - @Test - void parseCardDescription() { - } - - @Test - void isWildCard() { - } -} \ No newline at end of file diff --git a/src/Test/RuleControllerTest.java b/src/Test/RuleControllerTest.java index dfc804013e5cb5c6228ad2df61b2276b02c2b167..be37cfc13a5fc658cceef6fc09c63f7c37b45414 100644 --- a/src/Test/RuleControllerTest.java +++ b/src/Test/RuleControllerTest.java @@ -23,61 +23,19 @@ class RuleControllerTest { System.out.println(player.getCards()); RuleController ruler = new RuleController(); - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); + setCurrentState(ruler, "red", "none", "6", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); + setCurrentState(ruler, "yellow", "reverse", "none", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "blue", "draw2", "none", 1); // previous blue draw2 assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); + setCurrentState(ruler, "yellow", "none", "none", 2); // previous wildDraw4, declared yellow assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("none"); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("none"); - assert(!ruler.isValidPlay(player, 105, false)); - - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "red", "skip", "none", 3); assert(!ruler.isValidPlay(player, 105, false)); } @@ -90,63 +48,30 @@ class RuleControllerTest { Player player = player_Red_N_WildDraw4_Y(); RuleController ruler = new RuleController(); - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(ruler.isValidPlay(player, 105, false)); // playable! - - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("none"); - assert(ruler.isValidPlay(player, 105, false)); // playable! - - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); + setCurrentState(ruler, "red", "none", "6", 0); + assert(ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("none"); - assert(!ruler.isValidPlay(player, 105, false)); + setCurrentState(ruler, "red", "reverse", "none", 0); + assert(ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); + setCurrentState(ruler, "red", "draw2", "none", 1); // previous red draw2 + assert(ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); + setCurrentState(ruler, "red", "none", "none", 2); // previous wildDraw4 + assert(ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "red", "skip", "none", 3); assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); + setCurrentState(ruler, "blue", "reverse", "none", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); + setCurrentState(ruler, "green", "draw2", "none", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "yellow", "skip", "none", 3); assert(!ruler.isValidPlay(player, 105, false)); - } + } @Test /** @@ -157,61 +82,19 @@ class RuleControllerTest { Player player = player_AllColor_Y_WildDraw4_Y(); RuleController ruler = new RuleController(); - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("none"); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); + setCurrentState(ruler, "red", "none", "6", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); + setCurrentState(ruler, "yellow", "reverse", "none", 0); assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "blue", "draw2", "none", 1); // previous blue draw2 assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); + setCurrentState(ruler, "yellow", "none", "none", 2); // previous wildDraw4, declared yellow assert(!ruler.isValidPlay(player, 105, false)); - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("none"); - assert(!ruler.isValidPlay(player, 105, false)); - - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("skip"); - ruler.setNextPlayerSkiplevel(3); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("reverse"); - ruler.setNextPlayerSkiplevel(0); - assert(!ruler.isValidPlay(player, 105, false)); - - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("none"); + setCurrentState(ruler, "red", "skip", "none", 3); assert(!ruler.isValidPlay(player, 105, false)); } @@ -222,12 +105,11 @@ class RuleControllerTest { * 3. test previous card: red 8 */ void testSituation_Red8() throws Exception { + RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("none"); - ruler.setMatchableNumber("8"); + setCurrentState(ruler,"red", "none", "8", 0); ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, @@ -236,6 +118,7 @@ class RuleControllerTest { System.out.println(validByRuler); System.out.println(groundTruth); assert(validByRuler.equals(groundTruth)); + } @@ -246,9 +129,9 @@ class RuleControllerTest { void testSituation_Yellow0() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("yellow"); - ruler.setMatchableSymbol("none"); - ruler.setMatchableNumber("0"); + + setCurrentState(ruler, "yellow", "none", "0", 0); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -265,10 +148,9 @@ class RuleControllerTest { void testSituation_blueSkip() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("blue"); - ruler.setMatchableSymbol("skip"); - ruler.setMatchableNumber("none"); - ruler.setNextPlayerSkiplevel(3); + + setCurrentState(ruler, "blue", "skip", "none", 3); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -285,10 +167,9 @@ class RuleControllerTest { void testSituation_greenReverse() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("green"); - ruler.setMatchableSymbol("reverse"); - ruler.setMatchableNumber("none"); - ruler.setNextPlayerSkiplevel(0); + + setCurrentState(ruler, "green", "reverse", "none", 0); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -305,10 +186,9 @@ class RuleControllerTest { void testSituation_RedDraw2() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("red"); - ruler.setMatchableSymbol("draw2"); - ruler.setMatchableNumber("none"); - ruler.setNextPlayerSkiplevel(1); + + setCurrentState(ruler, "red", "draw2", "none", 1); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -319,8 +199,6 @@ class RuleControllerTest { } - - @Test /** * 8. test previous card: wild with red as declared color @@ -328,10 +206,9 @@ class RuleControllerTest { void testSituation_wildDeclaredRed() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("red"); // only color should be matchable in this case - ruler.setMatchableSymbol("none"); - ruler.setMatchableNumber("none"); - ruler.setNextPlayerSkiplevel(0); + + setCurrentState(ruler, "red", "none", "none", 0); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -349,10 +226,9 @@ class RuleControllerTest { void testSituation_wildDraw4DeclaredRed() throws Exception { RuleController ruler = new RuleController(); Player player = playerAllCards(); // a player who owns all cards - ruler.setMatchableColor("red"); // only color should be matchable in this case - ruler.setMatchableSymbol("none"); - ruler.setMatchableNumber("none"); - ruler.setNextPlayerSkiplevel(2); + + setCurrentState(ruler, "red", "none", "none", 2); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); @@ -363,12 +239,84 @@ class RuleControllerTest { } + @Test + /** + * 10. Test if ruler is updated correctly if last round was red 8 + * suppose the user cannot play wildDraw4 + * All possible plays are tested - no need to do more other than wildDraw4 + */ + void testUpdate_Red8() { + RuleController ruler = new RuleController(); + Player player = playerAllCards(); // a player who owns all cards + setCurrentState(ruler, "red", "none", "8", 0); + ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player); + ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player, + ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol()); + ruler.isValidPlay(player, 25, true); // check behavior of red 0 + assert(checkStateUpdatedCorrectly(ruler, "red", "none", "0", 0)); + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 20,true); // red skip card + assert(checkStateUpdatedCorrectly(ruler, "red", "skip", "none", 3)); + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 22,true); // red reverse card + assert(checkStateUpdatedCorrectly(ruler, "red", "reverse", "none", 0)); + assert(!ruler.getIsClockwise()); + + ruler.changeGameOrder(); + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 24,true); // red draw2 card + assert(checkStateUpdatedCorrectly(ruler, "red", "draw2", "none", 1)); + assert(ruler.getPenaltyDraw() == 2); // next player should draw 2 + + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 58, true); // blue 8 + assert(checkStateUpdatedCorrectly(ruler, "blue", "none", "8", 0)); + + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 102, true); // wild card, color should be NA, a special state + assert(checkStateUpdatedCorrectly(ruler, "NA", "none", "none", 0)); + } + + /** + * 11. test behavior of wildDraw4 + * given player has no red card, but has a wildDraw4 card + */ + @Test + void testUpdate_WildDraw4() { + RuleController ruler = new RuleController(); + Player player = player_Red_N_WildDraw4_Y(); + + // previous play red 8 + ruler.resetPenaltyDraw(); + setCurrentState(ruler, "red", "none", "8", 0); + ruler.isValidPlay(player, 108, true); + assert(checkStateUpdatedCorrectly(ruler, "NA", "none", "none", 2)); + assert(ruler.getPenaltyDraw() == 4); + + // previous play red draw 2 -- penalty draw should be 6 after wildDraw4 played + ruler.resetPenaltyDraw(); + setCurrentState(ruler, "red", "draw2", "none", 1); + ruler.increasePenaltyDraw(2); + ruler.isValidPlay(player, 108, true); + assert(checkStateUpdatedCorrectly(ruler, "NA", "none", "none", 2)); + assert(ruler.getPenaltyDraw() == 6); + + + // previous play wildDraw 4, and declared red as matchable color + ruler.resetPenaltyDraw(); + setCurrentState(ruler, "red", "none", "none", 2); + ruler.increasePenaltyDraw(4); + System.out.println(ruler.isValidPlay(player, 108, true)); + assert(checkStateUpdatedCorrectly(ruler, "NA", "none", "none", 2)); + assert(ruler.getPenaltyDraw() == 8); + + } @@ -481,4 +429,31 @@ class RuleControllerTest { } return player; } + + + /** + * helper function to set current game state based on previous player's move + */ + private void setCurrentState(RuleController ruler, + String matchableColor, + String machableSymbol, + String matchabeNumber, + int level) { + ruler.setMatchableColor(matchableColor); + ruler.setMatchableSymbol(machableSymbol); + ruler.setMatchableNumber(matchabeNumber); + ruler.setNextPlayerSkiplevel(level); + } + + private boolean checkStateUpdatedCorrectly(RuleController ruler, + String truthColor, + String truthSymbol, + String truthNumber, + int truthLevel) { + return truthColor.equals(ruler.getMatchableColor()) && + truthSymbol.equals(ruler.getMatchableSymbol()) && + truthNumber.equals(ruler.getMatchableNumber()) && + truthLevel == ruler.getNextPlayerSkiplevel(); + } + } \ No newline at end of file diff --git a/src/UNO/RuleController.java b/src/UNO/RuleController.java index 67639ad3f7e78b0f0bd9857cd25e93f29faf5670..c84d31004da333242e078a7e09b4684617de1241 100644 --- a/src/UNO/RuleController.java +++ b/src/UNO/RuleController.java @@ -9,7 +9,7 @@ public class RuleController { */ private String currentMatchableColor; private String currentMatchableNumber; - private String currentMatchableSymbol = "all"; // all symbols can be played in the first round + private String currentMatchableSymbol = "none"; // Card played in the first round can only match by either color or number private int nextPlayerSkipLevel = 0; private int cumulativePenaltyDraw = 0; private boolean isClockWise = true; // if clockwise, next player will be the element in player list @@ -76,38 +76,43 @@ public class RuleController { String type = result[1]; String content = result[2]; - // pending skip + boolean valid = false; + if (nextPlayerSkipLevel == 3) { - return false; + valid = false; + } else if (nextPlayerSkipLevel == 2) { if (content.equals("wildDraw4")) { - return checkDraw4IsLegal(player); + valid = checkDraw4IsLegal(player); + } else { + valid = false; } - return false; // any cards other than wildDraw4 are not playable + } else if (nextPlayerSkipLevel == 1) { if (content.equals("wildDraw4")) { - return checkDraw4IsLegal(player); + valid = checkDraw4IsLegal(player); + } else { + return content.equals("draw2"); // draw 2 is always allowed in this case } - return content.equals("draw2"); // draw 2 is always allowed in this case - } - boolean valid = false; - // if not skipped, first consider wild card - if (content.equals("wild")) { - valid = true; // can be used unconditionally - } - // then other colored cards - if (checkAttrMatch(currentMatchableColor, color)) - valid = true; - if (checkAttrMatch(currentMatchableNumber, content) || checkAttrMatch(currentMatchableSymbol, content)) - valid = true; + } else { + // if not skipped, first consider wild card + if (content.equals("wild")) { + valid = true; // can be used unconditionally + } - // check wildDraw4 at last - if (content.equals("wildDraw4")) { - valid = checkDraw4IsLegal(player); - } + // then other colored cards + if (checkAttrMatch(currentMatchableColor, color)) + valid = true; + if (checkAttrMatch(currentMatchableNumber, content) || checkAttrMatch(currentMatchableSymbol, content)) + valid = true; + // check wildDraw4 at last + if (content.equals("wildDraw4")) { + valid = checkDraw4IsLegal(player); + } + } if (valid && updateIfValid) { updateRule(color, type, content); @@ -118,13 +123,12 @@ public class RuleController { private void updateRule(String color, String type, String content) { setMatchableColor(color); // wildcard "NA" - this will be updated later by player declaring the color - if (type.equals("sym")) { if (content.equals("skip")) { setNextPlayerSkiplevel(3); // the states after the skip.. (supposed skipping is done) currentMatchableSymbol = content; //?? - currentMatchableNumber = "all"; //?? + currentMatchableNumber = "none"; //?? } else if (content.equals("draw2")) { // next round match by either COL or SYM @@ -138,7 +142,7 @@ public class RuleController { setNextPlayerSkiplevel(2); increasePenaltyDraw(4); currentMatchableSymbol = "none"; - currentMatchableNumber = "none"; // color will be declared by player later + currentMatchableNumber = "none"; } else if (content.equals("reverse")) { // next round match by either COL or SYM