From 0d0090ccaa2185fb543d0afb74d42440139c8554 Mon Sep 17 00:00:00 2001
From: FrederickPi1969 <pixinyudeyouxiang@gmail.com>
Date: Thu, 4 Feb 2021 02:33:41 -0600
Subject: [PATCH] judge card playability tests done

---
 .../sp21-cs242-assignment1/CmdUI.class        | Bin 4564 -> 4566 bytes
 .../RuleController.class                      | Bin 7111 -> 7103 bytes
 .../RuleControllerTest.class                  | Bin 4717 -> 9198 bytes
 src/Test/RuleControllerTest.java              | 396 +++++++++++++++---
 src/UNO/CmdUI.java                            |   4 +-
 src/UNO/RuleController.java                   |  17 +-
 6 files changed, 355 insertions(+), 62 deletions(-)

diff --git a/out/production/sp21-cs242-assignment1/CmdUI.class b/out/production/sp21-cs242-assignment1/CmdUI.class
index ed707a5d848bfe36341a91d099a66097d3c0b42e..9e4a053d8df256d5f7e95477d0e4e5fc5397a49c 100644
GIT binary patch
delta 26
icmcbjd`)@7dsbe-;?xq~#FFHU#H5_m&A(W0aRUIBEejU_

delta 24
gcmcbnd_{S~dsc4#;?xqyoSgjf)RfJCSZ{Fy0D<fZTmS$7

diff --git a/out/production/sp21-cs242-assignment1/RuleController.class b/out/production/sp21-cs242-assignment1/RuleController.class
index cfcfdeff757385315eabfaa03c3974a8e2ef7467..3cbec0e8bc6d73ca34e345d23260d98e2851eae0 100644
GIT binary patch
delta 1188
zcmY+De{54#6vsceudlBiTSp&jyTWE*$TB;1sc1?_HVu$5HIR@H-9(843q*%en8t`Q
zjnfb(KQBKvfiad$j2WYBqv%U?s0+l*gvEa(5maV~5Pqqse~EbdI&tPD_n!Mb=iKl4
zo^#)+<WMqQ>n#YaPc<)UY+kvhaYa*VV2QU}8Gg3t3+61fO;7SIS3C5xz9-dAeacr=
z5MVcZEZXzw;C<a{CVYPODe85?D%CNoI?%}hi>`bQ>Jw&}UTXCl_UhEYWWQ}x+7pQu
zzqEEmYMsLO{J8Ny@4&;8j+l8K121{N584x|v%@jJ{aA)X2Z4BHhWcJZKM~qutfNF<
z4kcQa@i;4~XDtn^XBit<&PJYQ6OFWyqMcRjWi`iG!^b?w7c}t|FYpa7a+YS!2+^t>
z9b^0?Cn4q{mr$<t9X1}<x<U+tX$*6fpp-ZZhjaJyJtmb5N>UIX3Hta^EQ=%`a$YRI
zl+(yHNe*y9F1nX|Jz`H+N?*3Gx4a_RuS(PgqP#|l#Ll3FIBznWx0pjK)x6C--r-S^
zw3K&6W}8TSk7w8{qPOxg+vSEGlBFejr=Yv#YiFO#sz=s7IvL=Ai0|Svx?RC>DIbOy
z(+x#Usz;wJs)=z!bXo$}Nta(=WYm=2o#Bmc=IYY$%$ArhK1k9XgK6}(8tTxkVQ;TQ
zd-+z@auJ76nH-^zv<NvWSU>j(b&WLVA;D`o?vmFDO9^+9?W|X#rn>z!B{n$TM2iRc
zO}s|78h0v5vBb=c#bmw|`@59;hoJc~s2uXAAlVKVVBEyActp+7-pD;_NRJkW^}<Lr
zGWV#sJ#NK$vcs2>I;?L-qPi_orAFMq(MW}PTJTZ9Yt<PSYlv2uX9YXw#_o?+sh?eZ
zELx#1xma28%=w$s(xgIf7e0HdYnoYed)n4%;WAv_JKP>$k@c#)x@)5HI$?gHlwX<7
z4ZW#&q54biu2z5RU~Ha3FNxJE%Vj$po2>%+d~89>E_-i={r&8UXXtkL0B#>YayUHU
z*yqS7{`2;C;J1$*!nBV&d@{k|IDC5hILH)79?N)I<sc_AoOBrZ7g>;lzIHh6LfN+F
z<i)eUk}ANjf<#pz<!Ukys1S>l%~NU$O{$2ED$F(&(HE!Q73#bt<MUYLS$v+|J9XK#
Go__!pLovVr

delta 1189
zcmYk4eQZ-@6vlrq?Y+0OldiXGyKZ2R1sok@&X3HPh`Qk@8W&8A&W{Z-6pWTl2S`*{
z7eS35!@)Z~#y5*dV#cW3sM@GZqhjKs^DhN6M2ra<K19)fgv`^s3jA~LInO!od!FYx
z@8Rkr)#*BS(7!yf;;v+}WmRHvZA-GHRT0w49UN$O`_wfPS<hP*ods-Qquyp#`Mh+o
z$zpQ>TlCG=G?#~Nz1o<rw(B0FN$u3id`#`uO=hK3_UdoUM%`egz0swK6}2l{TNBL#
zK9B9XzEJY~(E63jo=C`4vpF9WULiCP_Z>96>LPBuz^GP%cwsQ=u^-G()y>RUMTQ3b
zXkfjonNoc^P?cK5Lp)6b&+-V*)5vNT@(Pdh8jIOXf^L>Dz)~_i#gKF!p@k8i;TX&L
zK}IYYAH+$1kxWK%ir-L9^dmMCoai)BT$J(|XP6}9rt^Vx9>=(W3i|m;K$9wZIU$in
zHSh4VL>{5Dh_iBdBEQN-v+?N>d#XNfpG&R65W<sqfe0@$nKfKT8!_6siI=#QwcO4+
zYIvD@d6fr5(8Ih=6K{yHH(4fodX7#xy@3=PrBl<vCXu{_9c*PE+v#JcNZ%z?ck>B*
z9l0?f4~IFa7ZxSe+j_WYPE;vTX$ibQ++A~@YtEEe8QOcO(Pg2sR6iY2GlPzru|cYx
zH5jhmbuP7k>?3!toO1KMd}EG}2SijKeh!MDG&6XQ8^xa67^IFv#HCg*baKAOW#VLJ
zk@MIsozom=4e1Z(?X;N3pWJPW@j~tLf)?Z#WQZ?+aY3m6E%gFf**Nl#AUUu7xGrH?
z+@t>GPJJ;nTMg;XXh`1?j_4;N0poM&|3bG#B6@AOQVlz`ufpZVh~VEjctNC69d+>g
zBjv`Z;Kv28Q>Ps4SfpJ2?(~%um(^}fi#vYz9!z_i6B@a2N7~+%7A`KwqH7(K&&c<z
zm~~Es|3QfJOc9w=xuDyN=c!B1-J`|jYD}Ba8m097Xr1y18dqL@G&(ocVegS`$W~$*
zdb0A+<Z0*Ace5P0D(%aP|5vL0-FWOn`!VeIvwV0}A)Dpn%jqD&th|=|v5G;4GJKik
z>;I9t<Ir%HZyiV`<mEXpK*^(5ej=)n87jan%BEfgX;eidRfskfrc*`qiISOtt})r!
Q1Pialr@4QZE-BsjA5zIOv;Y7A

diff --git a/out/test/sp21-cs242-assignment1/RuleControllerTest.class b/out/test/sp21-cs242-assignment1/RuleControllerTest.class
index da9badcd08ce0b4609ba10d8fa911d6f7329d88c..193d470dab21a84f25e59a09e3affae987875f93 100644
GIT binary patch
literal 9198
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
R35ZiB$=3>h<&QXg^gn8Sd9DBe

literal 4717
zcmdT|TX+;_8Ga|bo7rq8$r4B)5Drobn*@jr=OjQw2)K4Rl!QR28YkIdGccJ=XLf;5
zdeVBRTCpCgAXc<Wv_(bwJfRdHs~6tbE4|S>Z@luVj~8C_5##&K?6FxSxAL$v|Ne*X
z|GxKqzwiGyfBet8zXi~Pn-NqYpdzRtglYxRGx|Bb)6(r!=aI29#&||Sb+2ignLP>u
zv9{p|!l+RZ(NGIbLF2KkW%Q@*jFYx3!x=JME?72Y>C=WYddx_U9v(emTFL#6etzrd
zh=NG0EpgNv?NL#$puT*41a%0=W08hNELPC$8kxh!g^a&u@T@sy8Rra3K`<6?8xEt1
zUO7fmmMqn<3@r*8xTMdr(&vq2f7(hr3YubxVpM|}$Fx&DvUml}xHKuNS87-#tE0u$
zgVU2^X{&|-uhH-^tW~gho$k7ZlQGk_yWe#6G0R9QP)><~bs8SUdIhznJFHt~Qan~r
z7t4nmKh<_hMU3baed)_v8*rSo6Tt=q!st+-It<crjW9OR#W5?(R;Pkc$}tQ(jK|2y
zv>_o18(TDN6)INdP-pC3+@m9<(5u)^|GllV8Pn?Qa~yp-VY-<Jwh83huuDTXdK84s
zjN#}R0j`;B6_><w{XMnVjXf&%YIq!d)WG~H3}Hfdg*Z<&r({LHhW!{|Jhs=pByYP!
zYt+O+1&fLR#qErdGKkCp#5H^pPl$VVh5%;`&vIOb4rw@yBi!?x^dC7bj>mJJd)9Mi
zdL+yzH5|hr7wbuKS0)W#@I7s(g!AJXhH-*OPw8ZWU}%Yc-ANwxzR}VMNas@;K7~(H
z*2N(zz*`|b@%^$xnJYQ@$@)<ZpM|bqNn!qe!yR|bDbbgL4V6^;)O;n2_{KFP1)Szo
z#dHaSnADulCt?H>Fjbt<a8{5gNqOHp25mf@)h#!S$&z(lD$*SCQ!xS?PfN`pGLcw3
zaZsN$m{ii8(U6tgjS%4@wjn@7a2^*_Ol!C(ifJe^+;1_Z=y=j_O(t?7BL*{iChH1J
z0ZOJnoh0843DY(XXD7#4Xe9S2y+nFkw}y4cl<&FDU}nOk$t8*M+9I`y@@~)YJ?aNB
zze0^3ca1{967s!TMb+igm|5ts<T2{#N9@yf9lahudq|(kc@i18Fm8Bsx+-4I=btCZ
z!ia*FV_7?6P8!3eYch&H+fFlhsWA##6KN;ac_zyO%;%J(W~V-7cIJYKl?Ibfe0Q{8
z7aQfFG|1FA?U<}i7bSqD6bsiRjFfH(N$$RBL5w54v5&@9QU(f@qo=eu6nlx<cuxCD
zoN&n(M$%N#1m(q~HIq__sDg4jr>F9iwpUu*TapX;4BtZ*Y6i`eP4zew$ms<|QrS|)
z@G4KG+EPwBYbS@CY-Zx1VdpETv!MNZN+QV>h=uf2bdUfv2;^n8q;bAE(&QL!)*|eS
zD^wL$Q?bI6gyNUh5ZPdD^E+9VZ7vLr`v+{b?Ik5my55<o;&lbr78H7AJm<T+ke-To
zRNjC$4?ndfX?%eyCL`?~w{n-A$Y46_j2j0`sWVIGmy*p=!?1=YMHMenRfx!O0YsO9
zR|WP&_~DHT3NEqL$+sds?RTL3nvE(v%cl&3_4_$KHGcx0#|!)hyvWgjELMJxAX`wP
z?Xyr5_fR)-2Mvcd24)f6*tldC%^Mq+&!Y7<R$pbiBWiNwk*lb^hYg(B_FjGxm;bLx
z8y{flN~tA((tJy0lQu8Jl0WGomOf5P<#Cm4Bsc~<9LIR|18<BWEGC*wY&ElIDX(<P
zumj6^`&fZ~wDPcCg)yw=`L~AnuEm$|2wuTD+`xL=<n`+|Vt60z_!Bzt7i`1_*o=Si
z>eYZP9!G0@9&#Lolv;capC@m1N&qk63uN_+^kWg!``DqvR#CT3{;lFhAc+dTjIXdI
zw11Uv;A;hv|CS@Ujfiv=NPb}K4`IIqr3bTLHtGME{nKb6lsm}&PO{%kE_=z}ZajuP
z?A?o_=wov3Bm4clnGE0=-WgxSL0m-~*LkbFfhX`D4&e{HM!t_D_&c7&KX^<0fVZO>
z94Gt3N{lxV$x>edZ3P9aD=46~L;;Nm-^Y4i0c{VFz$=~{q)2q|BlTcjfk>4U2qm|5
z6~2zk6r3#lE45S2ci%m1W5(||Ofq+N2U~)7(W~GJ+NHHm!S8Tj7N6K2>QI_OQX{UQ
zZc|g}9VBLP^u)~EpEup2k)W4R%RPgWEN?dRB8@Ig5mkq1x}GyziS`C&+BfhjTim)(
zxB5IBB#u6O6W^kXVeG=U*$Uu0>}_U`KlWN->@|)_<}@I1AN4A>so1^gLk@qJomKcA
zKUYYX7p-!O?>hEh@}jJ6sm?_?DXn6Z>TL`)sk1oQ9cHT~Jd4kC*R<3Gy1FARHNmd#
z+LoG7SGU$Ni?QnKsGga-E6vb#EN{^ojaj6wVi{W&TUSs&gIXC5UPoYN?lOJI1GU}r
z<yjV$=OD7!!t%X~^4d#b3=oP#EDJ{&+)3ts8ZYxAe3_TvS3M9fvgo%_bl=A{g0zLd
zkA8sHQN#6n@I&@RXk{lQdW}D}2S~w>*wVPuNe^~aFet!&sQ~+>9PBdsW3J%Q!PXmW
z1-;f!*a~@6_(zV+7b=8+A%y;oYN9{K+^AC#W(o7?m{8&W->rD9pXR?$0ITMpLajI%
zD6)8id+?72l(=a29K8`CwBLh05>W17D$x<;G3Itew|GyAl5G;frzuat+&?x~aX(NG
z5h535G|j}VmB_6nYBAy^iR#O&J%>+(iR+i@D*3gX^WpiN51l1G1icLx=*U{q2K=0k
zyh-i8#eBHQljaw^0{oKM@hfb?trBNC3(h=RaAu~=8KG)*(V5`x)~NLc>N{HL)Js*$
z%-lac6#PT4*-N~4xcOZkc<=JKyNi|hjklqcDUAow&!{v(d39myrrg%TwuY+v&{(FF
z4~b)#f#mNi`@B`aibm$mxvNlvGYAIW7UxD-VV-##L&aN+{0T{JF;UceA_}2OdtB~2
KZ?d}zZ~Ygq$zAmT

diff --git a/src/Test/RuleControllerTest.java b/src/Test/RuleControllerTest.java
index 9c28204..dfc8040 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 75d95c8..9da9702 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 2c2a08e..67639ad 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");
-- 
GitLab