diff --git a/out/production/sp21-cs242-assignment1/CmdUI.class b/out/production/sp21-cs242-assignment1/CmdUI.class
index ed707a5d848bfe36341a91d099a66097d3c0b42e..9e4a053d8df256d5f7e95477d0e4e5fc5397a49c 100644
Binary files a/out/production/sp21-cs242-assignment1/CmdUI.class and b/out/production/sp21-cs242-assignment1/CmdUI.class differ
diff --git a/out/production/sp21-cs242-assignment1/RuleController.class b/out/production/sp21-cs242-assignment1/RuleController.class
index cfcfdeff757385315eabfaa03c3974a8e2ef7467..3cbec0e8bc6d73ca34e345d23260d98e2851eae0 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/RuleControllerTest.class b/out/test/sp21-cs242-assignment1/RuleControllerTest.class
index da9badcd08ce0b4609ba10d8fa911d6f7329d88c..193d470dab21a84f25e59a09e3affae987875f93 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/RuleControllerTest.java b/src/Test/RuleControllerTest.java
index 9c2820484a4f1ac4a184011f438db40821811f5e..dfc804013e5cb5c6228ad2df61b2276b02c2b167 100644
--- a/src/Test/RuleControllerTest.java
+++ b/src/Test/RuleControllerTest.java
@@ -13,102 +13,372 @@ import java.util.Random;
 class RuleControllerTest {
     private static CardParser parser = new CardParser();
 
-    @Test  // if current allowed color is red, player with no red cards can use wild Draw 4
+    @Test
+    /**
+     * 0. A magic player owning all cards cannot play wildDraw4 anyway
+     * Test lots of combinations of color (r,g,b,y) & symbol (skip, reverse)
+     */
+    void test_Player_AllCards_CannotWildDraw4() throws Exception {
+        Player player = playerAllCards();
+        System.out.println(player.getCards());
+        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);
+        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");
+        assert(!ruler.isValidPlay(player, 105, false));
+    }
+
+
+    @Test
+    /**
+     * 1. if current allowed color is red, player with no red cards can use wild Draw 4
+     */
     void test_Player_Red_N_WildDraw4_Y_UseWildDraw4() throws Exception {
         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);
-        ruler.setAllowedColor("red");
-        ruler.setAllowedSymbol("skip");
-        assert(ruler.isValidPlay(player, 105, false));
+        assert(ruler.isValidPlay(player, 105, false));  // playable!
 
-        ruler.setAllowedColor("red");
-        ruler.setAllowedSymbol("reverse");
-        assert(ruler.isValidPlay(player, 105, false));
+        ruler.setMatchableColor("red");
+        ruler.setMatchableSymbol("none");
+        assert(ruler.isValidPlay(player, 105, false)); // playable!
 
-        ruler.setAllowedColor("blue");
-        ruler.setAllowedSymbol("skip");
+        ruler.setMatchableColor("blue");
+        ruler.setMatchableSymbol("skip");
+        ruler.setNextPlayerSkiplevel(3);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("blue");
-        ruler.setAllowedSymbol("reverse");
+        ruler.setMatchableColor("blue");
+        ruler.setMatchableSymbol("reverse");
+        ruler.setNextPlayerSkiplevel(0);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("green");
-        ruler.setAllowedSymbol("skip");
+        ruler.setMatchableColor("blue");
+        ruler.setMatchableSymbol("none");
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("green");
-        ruler.setAllowedSymbol("reverse");
+        ruler.setMatchableColor("green");
+        ruler.setMatchableSymbol("skip");
+        ruler.setNextPlayerSkiplevel(3);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("yellow");
+        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");
+        assert(!ruler.isValidPlay(player, 105, false));
     }
 
-    @Test // test player with all colors cannot use wildDraw4 anyway
+    @Test
+    /**
+     * 2. test player with all colors cannot use wildDraw4 anyway
+     */
+
     void test_Player_AllColors_CannotUseWildDraw4() throws Exception {
         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);
-        ruler.setAllowedColor("red");
-        ruler.setAllowedSymbol("skip");
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("red");
-        ruler.setAllowedSymbol("reverse");
+        ruler.setMatchableColor("red");
+        ruler.setMatchableSymbol("none");
+        assert(!ruler.isValidPlay(player, 105, false));
+
+        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));
+
+        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.setAllowedColor("blue");
-        ruler.setAllowedSymbol("skip");
+        ruler.setMatchableColor("green");
+        ruler.setMatchableSymbol("reverse");
+        ruler.setNextPlayerSkiplevel(0);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("blue");
-        ruler.setAllowedSymbol("reverse");
+        ruler.setMatchableColor("green");
+        ruler.setMatchableSymbol("none");
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("green");
-        ruler.setAllowedSymbol("skip");
+
+        ruler.setMatchableColor("yellow");
+        ruler.setMatchableSymbol("skip");
+        ruler.setNextPlayerSkiplevel(3);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("green");
-        ruler.setAllowedSymbol("reverse");
+        ruler.setMatchableColor("yellow");
+        ruler.setMatchableSymbol("reverse");
+        ruler.setNextPlayerSkiplevel(0);
         assert(!ruler.isValidPlay(player, 105, false));
 
-        ruler.setAllowedColor("yellow");
+        ruler.setMatchableColor("yellow");
+        ruler.setMatchableSymbol("none");
         assert(!ruler.isValidPlay(player, 105, false));
+    }
+
+
+
+    @Test
+    /**
+     * 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");
+
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
+
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
+
+
+    @Test
+    /**
+     * 4. test previous card: yellow 0
+     */
+    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");
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
+
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
+
+    @Test
+    /**
+     * 5. test previous card: blue skip
+     */
+    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);
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
+
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
+
+    @Test
+    /**
+     * 6. test previous card: green reverse
+     */
+    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);
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
 
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
 
+    @Test
+    /**
+     * 7. test previous card: red draw2
+     */
+    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);
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
+
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
     }
 
 
 
-//    @Test // Last round a red 8 played
-//    void testRed8() throws Exception {
-//        RuleController ruler = new RuleController();
-//
-//    }
 
+    @Test
+    /**
+     * 8. test previous card: wild with red as declared color
+     */
+    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);
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
 
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
+
+
+    @Test
     /**
-     *
+     * 9. test previous card: wildDraw4 with red as declared color
      */
-    void testInitializer() {}
+    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);
+        ArrayList<Integer> validByRuler = getAllLegalCardsByRuler(ruler, player);
+        ArrayList<Integer> groundTruth = groundTruthGenerator(ruler, player,
+                ruler.getMatchableColor(), ruler.getMatchableNumber(), ruler.getMatchableSymbol());
+
+        System.out.println(validByRuler);
+        System.out.println(groundTruth);
+        assert(validByRuler.equals(groundTruth));
+    }
+
+
+
+
+
+
+
+
+
+
 
     /**
      *  extract all the cards that the ruler think as legal
      */
-    private ArrayList<Integer> getAllLegalCardsByRuler(RuleController ruler, ArrayList<Integer> cards) {
+    private ArrayList<Integer> getAllLegalCardsByRuler(RuleController ruler, Player player) {
         ArrayList<Integer> validList = new ArrayList<>();
-        for (int cardID : cards) {
-            if (ruler.isValidPlay(null, cardID, false)) {
+        for (int cardID : player.getCards()) {
+            if (ruler.isValidPlay(player, cardID, false)) {
                 validList.add(cardID);
             }
         }
@@ -119,30 +389,54 @@ class RuleControllerTest {
      * extract all the cards that are indeed legal (ground true generator)
      */
     private ArrayList<Integer> groundTruthGenerator(RuleController ruler,
-                                                    ArrayList<Integer> cards,
-                                                    String color, String number,
-                                                    String symbol) {
-        for (int cardID : cards) {
+                                                    Player player,
+                                                    String colorTruth,
+                                                    String numberTruth,
+                                                    String symbolTruth) {
+        ArrayList<Integer> validList = new ArrayList<>();
+        for (int cardID : player.getCards()) {
             String cardDescription = parser.parseCardID(cardID);
             String[] result = parser.parseCardDescription(cardDescription);
             String cardCol = result[0];
-            String cardType = result[1];
             String cardContent = result[2];
 
             if (ruler.getNextPlayerSkiplevel() == 3) {
                 continue; // skip card played. any card will be illegal
+
             } else if (ruler.getNextPlayerSkiplevel() == 2) {
-                // only wildDraw4 if allowed
-                if (cardContent.equals("wildDraw4") || cardContent.equals("wildDraw2"));
+                // only wildDraw4 is allowed
+                if (cardContent.equals("wildDraw4") && ruler.isValidPlay(player, cardID, false)) {
+                     // this call is valid because wildDraw4 behavior has passed the test.
+                    validList.add(cardID);
+                }
+
             } else if (ruler.getNextPlayerSkiplevel() == 1) {
-                                        // both draw 2 and wild draw 4 are allowed
+                // both draw 2 and wild draw 4 are allowed
+                if (cardContent.equals("wildDraw4") && ruler.isValidPlay(player, cardID, false)) {
+                    validList.add(cardID);
+                } else if (cardContent.equals("draw2")) {
+                    validList.add(cardID);
+                }
+
             } else {
                 // cards with any one of color, number or symbol matched are playable
-
+                if (cardContent.equals("wild")) {
+                    validList.add(cardID);
+                } else if (cardContent.equals("wildDraw4") && ruler.isValidPlay(player, cardID, false)) {
+                    validList.add(cardID);
+                } else {
+                    if (cardCol.equals(colorTruth)) {
+                        validList.add(cardID);
+                    } else if (cardContent.equals(numberTruth)) {
+                        validList.add(cardID);
+                    } else if (cardContent.equals(symbolTruth)) {
+                        validList.add(cardID);
+                    }
+                }
             }
         }
-//        if (ruler.getSkip)
-        return null;
+
+        return validList;
     }
 
     /**
diff --git a/src/UNO/CmdUI.java b/src/UNO/CmdUI.java
index 75d95c81f7a1498cf9dad8ce565c7fddfb66bade..9da970239c7a9feddedc7a73aca19dbfc3815629 100644
--- a/src/UNO/CmdUI.java
+++ b/src/UNO/CmdUI.java
@@ -77,7 +77,7 @@ public class CmdUI {
                 promptChooseColor();
                 colorChosen = getInputColor();
             }
-            ruler.setAllowedColor(parser.colorDict.get(colorChosen));
+            ruler.setMatchableColor(parser.colorDict.get(colorChosen));
         }
         return cardID;
     }
@@ -97,7 +97,7 @@ public class CmdUI {
                     promptChooseColor();
                     colorChosen = getInputColor();
                 }
-                gameController.ruler.setAllowedColor(parser.colorDict.get(colorChosen));
+                gameController.ruler.setMatchableColor(parser.colorDict.get(colorChosen));
             }
 
             return cardID;
diff --git a/src/UNO/RuleController.java b/src/UNO/RuleController.java
index 2c2a08e1b2ff61a101949a48cafbf9ae02bb274b..67639ad3f7e78b0f0bd9857cd25e93f29faf5670 100644
--- a/src/UNO/RuleController.java
+++ b/src/UNO/RuleController.java
@@ -83,6 +83,7 @@ public class RuleController {
             if (content.equals("wildDraw4")) {
                 return checkDraw4IsLegal(player);
             }
+            return false; // any cards other than wildDraw4 are not playable
         } else if (nextPlayerSkipLevel == 1) {
             if (content.equals("wildDraw4")) {
                 return checkDraw4IsLegal(player);
@@ -116,7 +117,7 @@ public class RuleController {
     }
 
     private void updateRule(String color, String type, String content) {
-        setAllowedColor(color); // wildcard "NA" - this will be updated later by player declaring the color
+        setMatchableColor(color); // wildcard "NA" - this will be updated later by player declaring the color
 
         if (type.equals("sym")) {
             if (content.equals("skip")) {
@@ -175,8 +176,6 @@ public class RuleController {
             int cardID = cards.get(i);
             String cardDescription = parser.parseCardID(cardID);
             String color = parser.parseCardDescription(cardDescription)[0]; // color of wild cards are NA
-            System.out.println(color);
-
             if (color.equals(currentMatchableColor)) {
                 return false;
             }
@@ -192,19 +191,19 @@ public class RuleController {
         return currentMatchableNumber;
     }
 
-    public void getAllowedNumber(String number) {
-        currentMatchableColor = number;
+    public void setMatchableNumber(String number) {
+        currentMatchableNumber = number;
     }
 
     /**
      *  Getter and Setter for Allowed Symbol
      */
 
-    public String getCurrentMatchableSymbol() {
+    public String getMatchableSymbol() {
         return currentMatchableSymbol;
     }
 
-    public void setAllowedSymbol(String symbol) {
+    public void setMatchableSymbol(String symbol) {
         currentMatchableSymbol = symbol;
     }
 
@@ -217,7 +216,7 @@ public class RuleController {
         return currentMatchableColor;
     }
 
-    public void setAllowedColor(String color) {
+    public void setMatchableColor(String color) {
         currentMatchableColor = color;
     }
 
@@ -270,7 +269,7 @@ public class RuleController {
         System.out.println("============================= Game State Report ========================================");
         System.out.println("Current matchable color : " + getMatchableColor());
         System.out.println("Current matchable number : " + getMatchableNumber());
-        System.out.println("Current matchable symbol : " + getCurrentMatchableSymbol());
+        System.out.println("Current matchable symbol : " + getMatchableSymbol());
         System.out.println("Game order : " + (getIsClockwise() ? "clockwise" : "counterclockwise"));
         System.out.println("Player skip level is " + descSkipLevel());
         System.out.println("Player will be forced to draw " + cumulativePenaltyDraw + " cards");