From 3a5dba338434178a914685d46732c50c447a1314 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Mon, 17 Nov 2025 09:54:49 -0600 Subject: [PATCH 01/24] Initial setup --- .../practice/camicia/.docs/instructions.md | 84 ++++++ exercises/practice/camicia/.meta/config.json | 23 ++ exercises/practice/camicia/build.gradle | 25 ++ .../camicia/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43453 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + exercises/practice/camicia/gradlew | 249 ++++++++++++++++++ exercises/practice/camicia/gradlew.bat | 92 +++++++ exercises/settings.gradle | 1 + 8 files changed, 480 insertions(+) create mode 100644 exercises/practice/camicia/.docs/instructions.md create mode 100644 exercises/practice/camicia/.meta/config.json create mode 100644 exercises/practice/camicia/build.gradle create mode 100644 exercises/practice/camicia/gradle/wrapper/gradle-wrapper.jar create mode 100644 exercises/practice/camicia/gradle/wrapper/gradle-wrapper.properties create mode 100755 exercises/practice/camicia/gradlew create mode 100644 exercises/practice/camicia/gradlew.bat diff --git a/exercises/practice/camicia/.docs/instructions.md b/exercises/practice/camicia/.docs/instructions.md new file mode 100644 index 000000000..9da5c14db --- /dev/null +++ b/exercises/practice/camicia/.docs/instructions.md @@ -0,0 +1,84 @@ +# Instructions + +In this exercise, you will simulate a game very similar to the classic card game **CamiciaGame**. +Your program will receive the initial configuration of two players' decks and must simulate the game until it ends (or detect that it will never end). + +## Rules + +- The deck is split between **two players**. + The player's cards are read from left to right, where the leftmost card is the top of the deck. +- A round consists of both players playing at least one card. +- Players take turns placing the **top card** of their deck onto a central pile. +- If the card is a **number card** (2-10), play simply passes to the other player. +- If the card is a **payment card**, a penalty must be paid: + - **J** → opponent must pay 1 card + - **Q** → opponent must pay 2 cards + - **K** → opponent must pay 3 cards + - **A** → opponent must pay 4 cards +- If the player paying a penalty reveals another payment card, that player stops paying the penalty. + The other player must then pay a penalty based on the new payment card. +- If the penalty is fully paid without interruption, the player who placed the **last payment card** collects the central pile and places it at the bottom of their deck. + That player then starts the next round. +- If a player runs out of cards and is unable to play a card (either while paying a penalty or when it is their turn), the other player collects the central pile. +- The moment when a player collects cards from the central pile is called a **trick**. +- If a player has all the cards in their possession after a trick, the game **ends**. +- The game **enters a loop** as soon as the decks are identical to what they were earlier during the game, **not** counting number cards! + +## Examples + +A small example of a match that ends. + +| Round | Player A | Player B | Pile | Penalty Due | +| :---- | :----------- | :------------------------- | :------------------------- | :---------- | +| 1 | 2 A 7 8 Q 10 | 3 4 5 6 K 9 J | | - | +| 1 | A 7 8 Q 10 | 3 4 5 6 K 9 J | 2 | - | +| 1 | A 7 8 Q 10 | 4 5 6 K 9 J | 2 3 | - | +| 1 | 7 8 Q 10 | 4 5 6 K 9 J | 2 3 A | Player B: 4 | +| 1 | 7 8 Q 10 | 5 6 K 9 J | 2 3 A 4 | Player B: 3 | +| 1 | 7 8 Q 10 | 6 K 9 J | 2 3 A 4 5 | Player B: 2 | +| 1 | 7 8 Q 10 | K 9 J | 2 3 A 4 5 6 | Player B: 1 | +| 1 | 7 8 Q 10 | 9 J | 2 3 A 4 5 6 K | Player A: 3 | +| 1 | 8 Q 10 | 9 J | 2 3 A 4 5 6 K 7 | Player A: 2 | +| 1 | Q 10 | 9 J | 2 3 A 4 5 6 K 7 8 | Player A: 1 | +| 1 | 10 | 9 J | 2 3 A 4 5 6 K 7 8 Q | Player B: 2 | +| 1 | 10 | J | 2 3 A 4 5 6 K 7 8 Q 9 | Player B: 1 | +| 1 | 10 | - | 2 3 A 4 5 6 K 7 8 Q 9 J | Player A: 1 | +| 1 | - | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - | +| 2 | - | 2 3 A 4 5 6 K 7 8 Q 9 J 10 | - | - | + +status: `"finished"`, cards: 13, tricks: 1 + +This is a small example of a match that loops. + +| Round | Player A | Player B | Pile | Penalty Due | +| :---- | :------- | :------- | :---- | :---------- | +| 1 | J 2 3 | 4 J 5 | - | - | +| 1 | 2 3 | 4 J 5 | J | Player B: 1 | +| 1 | 2 3 | J 5 | J 4 | - | +| 2 | 2 3 J 4 | J 5 | - | - | +| 2 | 3 J 4 | J 5 | 2 | - | +| 2 | 3 J 4 | 5 | 2 J | Player A: 1 | +| 2 | J 4 | 5 | 2 J 3 | - | +| 3 | J 4 | 5 2 J 3 | - | - | +| 3 | J 4 | 2 J 3 | 5 | - | +| 3 | 4 | 2 J 3 | 5 J | Player B: 1 | +| 3 | 4 | J 3 | 5 J 2 | - | +| 4 | 4 5 J 2 | J 3 | - | - | + +The start of round 4 matches the start of round 2. +Recall, the value of the number cards does not matter. + +status: `"loop"`, cards: 8, tricks: 3 + +## Your Task + +- Using the input, simulate the game following the rules above. +- Determine the following information regarding the game: + - **Status**: `"finished"` or `"loop"` + - **Cards**: total number of cards played throughout the game + - **Tricks**: number of times the central pile was collected + +~~~~exercism/advanced +For those who want to take on a more exciting challenge, the hunt for other records for the longest game with an end is still open. +There are 653,534,134,886,878,245,000 (approximately 654 quintillion) possibilities, and we haven't calculated them all yet! +~~~~ diff --git a/exercises/practice/camicia/.meta/config.json b/exercises/practice/camicia/.meta/config.json new file mode 100644 index 000000000..b8d1c3386 --- /dev/null +++ b/exercises/practice/camicia/.meta/config.json @@ -0,0 +1,23 @@ +{ + "authors": [], + "contributors": [ + "thibault2705" + ], + "files": { + "solution": [ + "src/main/java/Camicia.java" + ], + "test": [ + "src/test/java/CamiciaTest.java" + ], + "example": [ + ".meta/src/reference/java/Camicia.java" + ], + "invalidator": [ + "build.gradle" + ] + }, + "blurb": "Simulate the card game and determine whether the match ends or enters an infinite loop.", + "source": "Beggar-My-Neighbour", + "source_url": "https://www.richardpmann.com/beggar-my-neighbour-records.html" +} diff --git a/exercises/practice/camicia/build.gradle b/exercises/practice/camicia/build.gradle new file mode 100644 index 000000000..d28f35dee --- /dev/null +++ b/exercises/practice/camicia/build.gradle @@ -0,0 +1,25 @@ +plugins { + id "java" +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform("org.junit:junit-bom:5.10.0") + testImplementation "org.junit.jupiter:junit-jupiter" + testImplementation "org.assertj:assertj-core:3.25.1" + + testRuntimeOnly "org.junit.platform:junit-platform-launcher" +} + +test { + useJUnitPlatform() + + testLogging { + exceptionFormat = "full" + showStandardStreams = true + events = ["passed", "failed", "skipped"] + } +} diff --git a/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e6441136f3d4ba8a0da8d277868979cfbc8ad796 GIT binary patch literal 43453 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^eO3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwAyRPZo2Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1KySGG#Wql>aL~k9tLrSO()LWn*q&YxHEuzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+mg&7$u!! z-^+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{Uw%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+uPsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2d>_iO*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;sIav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{XBdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ibNBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_syQv5A2rj!Vbw8;|$@C!vfNmNV!yJIWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6QK=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%+clM1xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkSJ3?zOH)OezMT{!YkCuSSn!K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7m6ze=mZ`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%2i(Td=tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&NykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWDqZ7J&~gAm1#~maIGJ1sls^gxL9LLG_NhU!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6NoGqEkpJYJ?vc|B zOlwT3t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&FwI=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#CGS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%QiEWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/exercises/practice/camicia/gradlew.bat b/exercises/practice/camicia/gradlew.bat new file mode 100644 index 000000000..25da30dbd --- /dev/null +++ b/exercises/practice/camicia/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/exercises/settings.gradle b/exercises/settings.gradle index 1119f4b98..616dfa038 100644 --- a/exercises/settings.gradle +++ b/exercises/settings.gradle @@ -44,6 +44,7 @@ include 'practice:bob' include 'practice:book-store' include 'practice:bottle-song' include 'practice:bowling' +include 'practice:camicia' include 'practice:change' include 'practice:circular-buffer' include 'practice:clock' From 5a9b18fd29ca799a57311145e00f5893f12ddc02 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Mon, 17 Nov 2025 11:17:09 -0600 Subject: [PATCH 02/24] Add Camicia class & Implement tests --- .../camicia/src/main/java/Camicia.java | 20 + .../camicia/src/test/java/CamiciaTest.java | 518 ++++++++++++++++++ 2 files changed, 538 insertions(+) create mode 100644 exercises/practice/camicia/src/main/java/Camicia.java create mode 100644 exercises/practice/camicia/src/test/java/CamiciaTest.java diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java new file mode 100644 index 000000000..01a738452 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -0,0 +1,20 @@ +import java.util.List; + +class Camicia { + + void simulateGame(List playerA, List playerB) { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } + + String getStatus() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } + + int getCards() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } + + int getTricks() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } +} \ No newline at end of file diff --git a/exercises/practice/camicia/src/test/java/CamiciaTest.java b/exercises/practice/camicia/src/test/java/CamiciaTest.java new file mode 100644 index 000000000..f5da6eac1 --- /dev/null +++ b/exercises/practice/camicia/src/test/java/CamiciaTest.java @@ -0,0 +1,518 @@ +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CamiciaTest { + private static final String FINISHED = "finished"; + private static final String LOOP = "loop"; + + private Camicia simulateGame(List playerA, List playerB) { + Camicia camicia = new Camicia(); + camicia.simulateGame(playerA, playerB); + + return camicia; + } + + @Test + @DisplayName("two cards, one trick") + public void twoCardsOneTrick() { + List playerA = List.of("2"); + List playerB = List.of("3"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(2, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Test + @DisplayName("three cards, one trick") + public void threeCardsOneTrick() { + List playerA = List.of("2", "4"); + List playerB = List.of("3"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(3, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Test + @DisplayName("four cards, one trick") + public void fourCardsOneTrick() { + List playerA = List.of("2", "4"); + List playerB = List.of("3", "5", "6"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(4, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Test + @DisplayName("the ace reigns supreme") + public void theAceReignsSupreme() { + List playerA = List.of("2", "A"); + List playerB = List.of("3", "4", "5", "6", "7"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("the king beats ace") + public void theKingBeatsAce() { + List playerA = List.of("2", "A"); + List playerB = List.of("3", "4", "5", "6", "K"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("the queen seduces the king") + public void theQueenSeducesTheKing() { + List playerA = List.of("2", "A", "7", "8", "Q"); + List playerB = List.of("3", "4", "5", "6", "K"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(10, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("the jack betrays the queen") + public void theJackBetraysTheQueen() { + List playerA = List.of("2", "A", "7", "8", "Q"); + List playerB = List.of("3", "4", "5", "6", "K", "9", "J"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(12, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("the 10 just wants to put on a show") + public void theTenJustWantsToPutOnAShow() { + List playerA = List.of("2", "A", "7", "8", "Q", "10"); + List playerB = List.of("3", "4", "5", "6", "K", "9", "J"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(13, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("simple loop with decks of 3 cards") + public void simpleLoopWithDecksOfThreeCards() { + List playerA = List.of("J", "2", "3"); + List playerB = List.of("4", "J", "5"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(LOOP, camicia.getStatus()); + assertEquals(8, camicia.getCards()); + assertEquals(3, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("the story is starting to get a bit complicated") + public void theStoryIsStartingToGetAbitComplicated() { + List playerA = List.of( + "2", "6", "6", "J", "4", "K", "Q", "10", "K", "J", "Q", "2", "3", "K", "5", "6", "Q", "Q", "A", "A", + "6", "9", "K", "A", "8", "K", "2", "A", "9", "A", "Q", "4", "K", "K", "K", "3", "5", "K", "8", "Q", + "3", "Q", "7", "J", "K", "J", "9", "J", "3", "3", "K", "K", "Q", "A", "K", "7", "10", "A", "Q", "7", + "10", "J", "4", "5", "J", "9", "10", "Q", "J", "J", "K", "6", "10", "J", "6", "Q", "J", "5", "J", "Q", + "Q", "8", "3", "8", "A", "2", "6", "9", "K", "7", "J", "K", "K", "8", "K", "Q", "6", "10", "J", "10", + "J", "Q", "J", "10", "3", "8", "K", "A", "6", "9", "K", "2", "A", "A", "10", "J", "6", "A", "4", "J", + "A", "J", "J", "6", "2", "J", "3", "K", "2", "5", "9", "J", "9", "6", "K", "A", "5", "Q", "J", "2", + "Q", "K", "A", "3", "K", "J", "K", "2", "5", "6", "Q", "J", "Q", "Q", "J", "2", "J", "9", "Q", "7", + "7", "A", "Q", "7", "Q", "J", "K", "J", "A", "7", "7", "8", "Q", "10", "J", "10", "J", "J", "9", "2", + "A", "2" + ); + List playerB = List.of( + "7", "2", "10", "K", "8", "2", "J", "9", "A", "5", "6", "J", "Q", "6", "K", "6", "5", "A", "4", "Q", + "7", "J", "7", "10", "2", "Q", "8", "2", "2", "K", "J", "A", "5", "5", "A", "4", "Q", "6", "Q", "K", + "10", "8", "Q", "2", "10", "J", "A", "Q", "8", "Q", "Q", "J", "J", "A", "A", "9", "10", "J", "K", "4", + "Q", "10", "10", "J", "K", "10", "2", "J", "7", "A", "K", "K", "J", "A", "J", "10", "8", "K", "A", "7", + "Q", "Q", "J", "3", "Q", "4", "A", "3", "A", "Q", "Q", "Q", "5", "4", "K", "J", "10", "A", "Q", "J", + "6", "J", "A", "10", "A", "5", "8", "3", "K", "5", "9", "Q", "8", "7", "7", "J", "7", "Q", "Q", "Q", + "A", "7", "8", "9", "A", "Q", "A", "K", "8", "A", "A", "J", "8", "4", "8", "K", "J", "A", "10", "Q", + "8", "J", "8", "6", "10", "Q", "J", "J", "A", "A", "J", "5", "Q", "6", "J", "K", "Q", "8", "K", "4", + "Q", "Q", "6", "J", "K", "4", "7", "J", "J", "9", "9", "A", "Q", "Q", "K", "A", "6", "5", "K" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(361, camicia.getCards()); + assertEquals(1, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("two tricks") + public void twoTricks() { + List playerA = List.of("J"); + List playerB = List.of("3", "J"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(5, camicia.getCards()); + assertEquals(2, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("more tricks") + public void moreTricks() { + List playerA = List.of("J", "2", "4"); + List playerB = List.of("3", "J", "A"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(12, camicia.getCards()); + assertEquals(4, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("simple loop with decks of 4 cards") + public void simpleLoopWithDecksOfFourCards() { + List playerA = List.of("2", "3", "J", "6"); + List playerB = List.of("K", "5", "J", "7"); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(LOOP, camicia.getStatus()); + assertEquals(16, camicia.getCards()); + assertEquals(4, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("easy card combination") + public void easyCardCombination() { + List playerA = List.of( + "4", "8", "7", "5", "4", "10", "3", "9", "7", "3", "10", "10", "6", "8", "2", "8", "5", "4", "5", + "9", "6", "5", "2", "8", "10", "9" + ); + List playerB = List.of( + "6", "9", "4", "7", "2", "2", "3", "6", "7", "3", "A", "A", "A", "A", "K", "K", "K", "K", "Q", "Q", + "Q", "Q", "J", "J", "J", "J" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(40, camicia.getCards()); + assertEquals(4, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("easy card combination, inverted decks") + public void easyCardCombinationInvertedDecks() { + List playerA = List.of( + "3", "3", "5", "7", "3", "2", "10", "7", "6", "7", "A", "A", "A", "A", "K", "K", "K", "K", "Q", + "Q", "Q", "Q", "J", "J", "J", "J" + ); + List playerB = List.of( + "5", "10", "8", "2", "6", "7", "2", "4", "9", "2", "6", "10", "10", "5", "4", "8", "4", "8", "6", + "9", "8", "5", "9", "3", "4", "9" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(40, camicia.getCards()); + assertEquals(4, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("mirrored decks") + public void mirroredDecks() { + List playerA = List.of( + "2", "A", "3", "A", "3", "K", "4", "K", "2", "Q", "2", "Q", "10", "J", "5", "J", "6", "10", "2", + "9", "10", "7", "3", "9", "6", "9" + ); + List playerB = List.of( + "6", "A", "4", "A", "7", "K", "4", "K", "7", "Q", "7", "Q", "5", "J", "8", "J", "4", "5", "8", + "9", "10", "6", "8", "3", "8", "5" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(59, camicia.getCards()); + assertEquals(4, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("opposite decks") + public void oppositeDecks() { + List playerA = List.of( + "4", "A", "9", "A", "4", "K", "9", "K", "6", "Q", "8", "Q", "8", "J", "10", "J", "9", "8", "4", + "6", "3", "6", "5", "2", "4", "3" + ); + List playerB = List.of( + "10", "7", "3", "2", "9", "2", "7", "8", "7", "5", "J", "7", "J", "10", "Q", "10", "Q", "3", "K", + "5", "K", "6", "A", "2", "A", "5" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(151, camicia.getCards()); + assertEquals(21, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("random decks #1") + public void randomDecksOne() { + List playerA = List.of( + "K", "10", "9", "8", "J", "8", "6", "9", "7", "A", "K", "5", "4", "4", "J", "5", "J", "4", "3", + "5", "8", "6", "7", "7", "4", "9" + ); + List playerB = List.of( + "6", "3", "K", "A", "Q", "10", "A", "2", "Q", "8", "2", "10", "10", "2", "Q", "3", "K", "9", "7", + "A", "3", "Q", "5", "J", "2", "6" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(542, camicia.getCards()); + assertEquals(76, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("random decks #2") + public void randomDecksTwo() { + List playerA = List.of( + "8", "A", "4", "8", "5", "Q", "J", "2", "6", "2", "9", "7", "K", "A", "8", "10", "K", "8", "10", + "9", "K", "6", "7", "3", "K", "9" + ); + List playerB = List.of( + "10", "5", "2", "6", "Q", "J", "A", "9", "5", "5", "3", "7", "3", "J", "A", "2", "Q", "3", "J", + "Q", "4", "10", "4", "7", "4", "6" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(327, camicia.getCards()); + assertEquals(42, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Kleber 1999") + public void kleber1999() { + List playerA = List.of( + "4", "8", "9", "J", "Q", "8", "5", "5", "K", "2", "A", "9", "8", "5", "10", "A", "4", "J", "3", + "K", "6", "9", "2", "Q", "K", "7" + ); + List playerB = List.of( + "10", "J", "3", "2", "4", "10", "4", "7", "5", "3", "6", "6", "7", "A", "J", "Q", "A", "7", "2", + "10", "3", "K", "9", "6", "8", "Q" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(5790, camicia.getCards()); + assertEquals(805, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Collins 2006") + public void collins2006() { + List playerA = List.of( + "A", "8", "Q", "K", "9", "10", "3", "7", "4", "2", "Q", "3", "2", "10", "9", "K", "A", "8", "7", + "7", "4", "5", "J", "9", "2", "10" + ); + List playerB = List.of( + "4", "J", "A", "K", "8", "5", "6", "6", "A", "6", "5", "Q", "4", "6", "10", "8", "J", "2", "5", + "7", "Q", "J", "3", "3", "K", "9" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(6913, camicia.getCards()); + assertEquals(960, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Mann and Wu 2007") + public void mannAndWu2007() { + List playerA = List.of( + "K", "2", "K", "K", "3", "3", "6", "10", "K", "6", "A", "2", "5", "5", "7", "9", "J", "A", "A", + "3", "4", "Q", "4", "8", "J", "6" + ); + List playerB = List.of( + "4", "5", "2", "Q", "7", "9", "9", "Q", "7", "J", "9", "8", "10", "3", "10", "J", "4", "10", "8", + "6", "8", "7", "A", "Q", "5", "2" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7157, camicia.getCards()); + assertEquals(1007, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Nessler 2012") + public void nessler2012() { + List playerA = List.of( + "10", "3", "6", "7", "Q", "2", "9", "8", "2", "8", "4", "A", "10", "6", "K", "2", "10", "A", "5", + "A", "2", "4", "Q", "J", "K", "4" + ); + List playerB = List.of( + "10", "Q", "4", "6", "J", "9", "3", "J", "9", "3", "3", "Q", "K", "5", "9", "5", "K", "6", "5", + "7", "8", "J", "A", "7", "8", "7" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7207, camicia.getCards()); + assertEquals(1015, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Anderson 2013") + public void anderson2013() { + List playerA = List.of( + "6", "7", "A", "3", "Q", "3", "5", "J", "3", "2", "J", "7", "4", "5", "Q", "10", "5", "A", "J", + "2", "K", "8", "9", "9", "K", "3" + ); + List playerB = List.of( + "4", "J", "6", "9", "8", "5", "10", "7", "9", "Q", "2", "7", "10", "8", "4", "10", "A", "6", "4", + "A", "6", "8", "Q", "K", "K", "2" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7225, camicia.getCards()); + assertEquals(1016, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Rucklidge 2014") + public void rucklidge2014() { + List playerA = List.of( + "8", "J", "2", "9", "4", "4", "5", "8", "Q", "3", "9", "3", "6", "2", "8", "A", "A", "A", "9", + "4", "7", "2", "5", "Q", "Q", "3" + ); + List playerB = List.of( + "K", "7", "10", "6", "3", "J", "A", "7", "6", "5", "5", "8", "10", "9", "10", "4", "2", "7", "K", + "Q", "10", "K", "6", "J", "J", "K" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7959, camicia.getCards()); + assertEquals(1122, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Nessler 2021") + public void nessler2021() { + List playerA = List.of( + "7", "2", "3", "4", "K", "9", "6", "10", "A", "8", "9", "Q", "7", "A", "4", "8", "J", "J", "A", + "4", "3", "2", "5", "6", "6", "J" + ); + List playerB = List.of( + "3", "10", "8", "9", "8", "K", "K", "2", "5", "5", "7", "6", "4", "3", "5", "7", "A", "9", "J", + "K", "2", "Q", "10", "Q", "10", "Q" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(7972, camicia.getCards()); + assertEquals(1106, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Nessler 2022") + public void nessler2022() { + List playerA = List.of( + "2", "10", "10", "A", "J", "3", "8", "Q", "2", "5", "5", "5", "9", "2", "4", "3", "10", "Q", "A", + "K", "Q", "J", "J", "9", "Q", "K" + ); + List playerB = List.of( + "10", "7", "6", "3", "6", "A", "8", "9", "4", "3", "K", "J", "6", "K", "4", "9", "7", "8", "5", + "7", "8", "2", "A", "7", "4", "6" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(FINISHED, camicia.getStatus()); + assertEquals(8344, camicia.getCards()); + assertEquals(1164, camicia.getTricks()); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Casella 2024, first infinite game found") + public void casella2024FirstInfiniteGameFound() { + List playerA = List.of( + "2", "8", "4", "K", "5", "2", "3", "Q", "6", "K", "Q", "A", "J", "3", "5", "9", "8", "3", "A", + "A", "J", "4", "4", "J", "7", "5" + ); + List playerB = List.of( + "7", "7", "8", "6", "10", "10", "6", "10", "7", "2", "Q", "6", "3", "2", "4", "K", "Q", "10", "J", + "5", "9", "8", "9", "9", "K", "A" + ); + + Camicia camicia = simulateGame(playerA, playerB); + + assertEquals(LOOP, camicia.getStatus()); + assertEquals(474, camicia.getCards()); + assertEquals(66, camicia.getTricks()); + } +} \ No newline at end of file From 6bafc4596c451d2b1e339953898d43e79c343c8c Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 10:32:35 -0600 Subject: [PATCH 03/24] Implement solution --- .../camicia/src/main/java/Camicia.java | 31 +- .../practice/camicia/src/main/java/Card.java | 36 +++ .../camicia/src/main/java/MatchResult.java | 75 +++++ .../practice/camicia/src/main/java/Turn.java | 278 ++++++++++++++++++ 4 files changed, 414 insertions(+), 6 deletions(-) create mode 100644 exercises/practice/camicia/src/main/java/Card.java create mode 100644 exercises/practice/camicia/src/main/java/MatchResult.java create mode 100644 exercises/practice/camicia/src/main/java/Turn.java diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java index 01a738452..fdeb2876b 100644 --- a/exercises/practice/camicia/src/main/java/Camicia.java +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -1,20 +1,39 @@ -import java.util.List; +import java.util.*; class Camicia { - void simulateGame(List playerA, List playerB) { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + private MatchResult matchResult; + + void simulateGame(List playerAList, List playerBList) { + Turn initialTurn = new Turn(playerAList, playerBList); + boolean win = initialTurn.playTurn(); + System.out.println(initialTurn); + Turn turn = initialTurn; + + while (!win) { + Turn newTurn = new Turn(turn); + win = newTurn.playTurn(); + System.out.println(newTurn); + + turn = newTurn; + } + + matchResult = MatchResult.builder() + .withStatus(MatchResult.Status.FINISHED) + .withCards(turn.getPlayedCardCounter()) + .withTricks(turn.getTrick()) + .build(); } String getStatus() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + return matchResult.getStatus().name().toLowerCase(); } int getCards() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + return matchResult.getCards(); } int getTricks() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + return matchResult.getTricks(); } } \ No newline at end of file diff --git a/exercises/practice/camicia/src/main/java/Card.java b/exercises/practice/camicia/src/main/java/Card.java new file mode 100644 index 000000000..ccd24a356 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/Card.java @@ -0,0 +1,36 @@ +class Card { + + private final String symbol; + private final int penalty; + + protected Card(String symbol) { + this.symbol = symbol; + this.penalty = getPenalty(symbol); + } + + int getPenalty() { + return penalty; + } + + public boolean isPaymentCard() { + return switch (symbol) { + case "J", "Q", "K", "A" -> true; + default -> false; + }; + } + + @Override + public String toString() { + return symbol; + } + + static int getPenalty(String card) { + return switch (card) { + case "J" -> 1; + case "Q" -> 2; + case "K" -> 3; + case "A" -> 4; + default -> 0; + }; + } +} diff --git a/exercises/practice/camicia/src/main/java/MatchResult.java b/exercises/practice/camicia/src/main/java/MatchResult.java new file mode 100644 index 000000000..20b7e8fd6 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/MatchResult.java @@ -0,0 +1,75 @@ +class MatchResult { + /** + * Match status: finished or loop + */ + Status status; + + /** + * Total number of cards played throughout the game + */ + int cards; + + /** + * Number of times the central pile was collected + */ + int tricks; + + private MatchResult() { + + } + + private MatchResult(Status status, int cards, int tricks) { + this.status = status; + this.cards = cards; + this.tricks = tricks; + } + + Status getStatus() { + return status; + } + + int getCards() { + return cards; + } + + int getTricks() { + return tricks; + } + + static MatchBuilder builder() { + return new MatchBuilder(); + } + + static final class MatchBuilder { + private Status status; + private int cards; + private int tricks; + + private MatchBuilder() { + } + + MatchBuilder withStatus(Status status) { + this.status = status; + return this; + } + + MatchBuilder withCards(int cards) { + this.cards = cards; + return this; + } + + MatchBuilder withTricks(int tricks) { + this.tricks = tricks; + return this; + } + + MatchResult build() { + return new MatchResult(status, cards, tricks); + } + } + + enum Status { + FINISHED, + LOOP + } +} \ No newline at end of file diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java new file mode 100644 index 000000000..6df0f3536 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -0,0 +1,278 @@ +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; + +class Turn { + private final int roundNumber; + private final ArrayDeque playerACards; + private final ArrayDeque playerBCards; + private ArrayDeque pile = new ArrayDeque<>(); + private Penalty penalty; + private Turn previousRound; + private Player playerPlacedLastPaymentCard; + private int trick = 0; + private int playedCardCounter = 0; + + private Player player; + private Card playedCard; + + Turn(List playerAList, List playerBList) { + roundNumber = 0; + playerACards = playerAList.stream() + .map(Card::new) + .collect(Collectors.toCollection(ArrayDeque::new)); + + playerBCards = playerBList.stream() + .map(Card::new) + .collect(Collectors.toCollection(ArrayDeque::new)); + } + + Turn(Turn previousRound) { + this.roundNumber = previousRound.roundNumber + 1; + this.playerACards = previousRound.playerACards; + this.playerBCards = previousRound.playerBCards; + this.previousRound = previousRound; + this.pile = previousRound.pile; + this.penalty = previousRound.penalty; + this.playerPlacedLastPaymentCard = previousRound.playerPlacedLastPaymentCard; + this.trick = previousRound.trick; + this.playedCardCounter = previousRound.playedCardCounter; + } + + boolean playTurn() { + if (isInitialRound()) { + return false; + } + + if (isFirstRound()) { + return playFirstTurn(); + } + + player = definePlayer(previousRound); + nextMove(); + return win(); + } + + private boolean playFirstTurn() { + player = Player.A; + nextMove(); + + return win(); + } + + boolean isInitialRound() { + return roundNumber == 0; + } + + boolean isFirstRound() { + return roundNumber == 1; + } + + private boolean win() { + return getCards(player).size() == totalCards(); + } + + private Card nextMove() { + if (collectPile()) { + return null; + } + + return playCard(); + } + + private Card playCard() { + if (getCards(player).isEmpty()) { + // player cannot play + return null; + } + + playedCard = switch (player) { + case A -> playerACards.removeFirst(); + case B -> playerBCards.removeFirst(); + }; + + pile.add(playedCard); + increasePlayedCard(); + deductPenalty(); + setPlayerPlacedLastPaymentCard(); + return playedCard; + } + + private void increasePlayedCard() { + playedCardCounter++; + } + + private void deductPenalty() { + if (penalty == null){ + return; + } + + if(!player.equals(penalty.getPlayer())) { + return; + } + + if (playedCard.isPaymentCard()) { + penalty = new Penalty(passPlayer(player), playedCard.getPenalty()); + return; + } + + penalty.deduct(); + } + + private void definePenalty(Card playedCard) { + if (!playedCard.isPaymentCard()) { + return; + } + + Player penaltyPlayer = passPlayer(player); + this.penalty = new Penalty(penaltyPlayer, playedCard.getPenalty()); + } + + private void setPlayerPlacedLastPaymentCard() { + if (!playedCard.isPaymentCard()) { + return; + } + + this.playerPlacedLastPaymentCard = player; + definePenalty(playedCard); + } + + private boolean collectPile() { + Player otherPlayer = passPlayer(player); + + boolean otherPlayerCanPlayNoMore = otherPlayer.equals(previousRound.player) && + previousRound.playedCard == null && + getCards(otherPlayer).isEmpty(); + + boolean otherPlayerHasToPayPenalty = getCards(otherPlayer).isEmpty() && + penalty != null && + penalty.getPlayer().equals(otherPlayer) && + penalty.getPenalty() > 0; + + boolean currentPlayerPlacedLastPaymentCard = player.equals(playerPlacedLastPaymentCard) && + penalty != null && + !penalty.isInterrupted(); + + if (otherPlayerCanPlayNoMore || otherPlayerHasToPayPenalty || currentPlayerPlacedLastPaymentCard) { + switch (player) { + case A -> playerACards.addAll(pile); + case B -> playerBCards.addAll(pile); + } + + pile.clear(); + + trick++; + + return true; + } + + return false; + } + + private int totalCards() { + return playerACards.size() + playerBCards.size() + pile.size(); + } + + private Player definePlayer(Turn previousRound) { + Penalty previousPenalty = previousRound.penalty; + + if (previousPenalty != null && previousPenalty.getPenalty() > 0 && !getCards(previousPenalty.getPlayer()).isEmpty()) { + return previousRound.penalty.player; + } + + return passPlayer(previousRound.player); + } + + private Player passPlayer(Player player) { + if (player == null) { + return Player.A; + } + + + return switch (player) { + case Player.A -> Player.B; + case Player.B -> Player.A; + }; + } + + private Deque getCards(Player player) { + return switch (player) { + case A -> playerACards; + case B -> playerBCards; + }; + } + + int getPlayedCardCounter() { + return playedCardCounter; + } + + int getTrick() { + return trick; + } + + public Card getPlayedCard() { + return playedCard; + } + + @Override + public String toString() { + return "MatchRound{" + + "roundNumber=" + roundNumber + + ", player=" + player + + ", playedCard=" + playedCard + + ", playerACards=" + playerACards + + ", playerBCards=" + playerBCards + + ", pile=" + pile + + ", penalty=" + penalty + + ", trick=" + trick + + '}'; + } + + enum Player { + A, + B + } + + class Penalty { + private Player player; + private int penalty; + private boolean interrupted = false; + + Penalty(Player player, int penalty) { + this.player = player; + this.penalty = penalty; + } + + Player getPlayer() { + return player; + } + + int getPenalty() { + return penalty; + } + + void deduct() { + if (penalty > 0) { + penalty -= 1; + } + } + + public void setInterrupted(boolean interrupted) { + this.interrupted = interrupted; + } + + public boolean isInterrupted() { + return interrupted; + } + + @Override + public String toString() { + return "Penalty{" + + "player=" + player + + ", penalty=" + penalty + + '}'; + } + } + +} From df80e368348c360a64dd0971349ec94128794f95 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 11:00:41 -0600 Subject: [PATCH 04/24] Implement solution --- .../practice/camicia/src/main/java/Turn.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 6df0f3536..e147487aa 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -16,6 +16,7 @@ class Turn { private Player player; private Card playedCard; + private Player collector = null; Turn(List playerAList, List playerBList) { roundNumber = 0; @@ -30,12 +31,12 @@ class Turn { Turn(Turn previousRound) { this.roundNumber = previousRound.roundNumber + 1; - this.playerACards = previousRound.playerACards; - this.playerBCards = previousRound.playerBCards; + this.playerACards = new ArrayDeque<>(previousRound.playerACards); + this.playerBCards = new ArrayDeque<>(previousRound.playerBCards); this.previousRound = previousRound; this.pile = previousRound.pile; this.penalty = previousRound.penalty; - this.playerPlacedLastPaymentCard = previousRound.playerPlacedLastPaymentCard; + this.penalty = previousRound.penalty != null ? new Penalty(previousRound.penalty) : null; this.trick = previousRound.trick; this.playedCardCounter = previousRound.playedCardCounter; } @@ -104,11 +105,11 @@ private void increasePlayedCard() { } private void deductPenalty() { - if (penalty == null){ + if (penalty == null) { return; } - if(!player.equals(penalty.getPlayer())) { + if (!player.equals(penalty.getPlayer())) { return; } @@ -145,16 +146,21 @@ private boolean collectPile() { previousRound.playedCard == null && getCards(otherPlayer).isEmpty(); - boolean otherPlayerHasToPayPenalty = getCards(otherPlayer).isEmpty() && + boolean otherPlayerCannotPayPenalty = getCards(otherPlayer).isEmpty() && penalty != null && penalty.getPlayer().equals(otherPlayer) && penalty.getPenalty() > 0; +// +// boolean currentPlayerPlacedLastPaymentCard = player.equals(playerPlacedLastPaymentCard) && +// penalty != null && +// !penalty.isInterrupted(); - boolean currentPlayerPlacedLastPaymentCard = player.equals(playerPlacedLastPaymentCard) && + boolean penaltyFullyPaidByOpponent = player.equals(playerPlacedLastPaymentCard) && penalty != null && - !penalty.isInterrupted(); + penalty.getPlayer().equals(otherPlayer) && + penalty.getPenalty() == 0; - if (otherPlayerCanPlayNoMore || otherPlayerHasToPayPenalty || currentPlayerPlacedLastPaymentCard) { + if (otherPlayerCanPlayNoMore || otherPlayerCannotPayPenalty || penaltyFullyPaidByOpponent) { switch (player) { case A -> playerACards.addAll(pile); case B -> playerBCards.addAll(pile); @@ -163,6 +169,7 @@ private boolean collectPile() { pile.clear(); trick++; + this.collector = player; return true; } @@ -175,6 +182,10 @@ private int totalCards() { } private Player definePlayer(Turn previousRound) { + if (previousRound.collector != null) { + return previousRound.collector; + } + Penalty previousPenalty = previousRound.penalty; if (previousPenalty != null && previousPenalty.getPenalty() > 0 && !getCards(previousPenalty.getPlayer()).isEmpty()) { @@ -244,6 +255,12 @@ class Penalty { this.penalty = penalty; } + Penalty(Penalty other) { + this.player = other.player; + this.penalty = other.penalty; + this.interrupted = other.interrupted; + } + Player getPlayer() { return player; } From dcb0d76220ea32a560c4206f9ea60f2b617a97d4 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 14:11:11 -0600 Subject: [PATCH 05/24] Implement solution --- .../camicia/src/main/java/Penalty.java | 43 +++++ .../practice/camicia/src/main/java/Turn.java | 164 +++++++----------- 2 files changed, 107 insertions(+), 100 deletions(-) create mode 100644 exercises/practice/camicia/src/main/java/Penalty.java diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java new file mode 100644 index 000000000..5d2694e2a --- /dev/null +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -0,0 +1,43 @@ +class Penalty { + private Turn.Player player; + private int penalty; + + Penalty() { + } + + Turn.Player getPlayer() { + return player; + } + + int getPenalty() { + return penalty; + } + + public void set(Turn.Player player, Card card) { + this.player = player; + this.penalty = card.getPenalty(); + } + + void deduct() { + if (penalty > 0) { + penalty -= 1; + } + } + + boolean isActive(){ + return penalty > 0; + } + + void clear() { + this.player = null; + this.penalty = 0; + } + + @Override + public String toString() { + return "Penalty{" + + "player=" + player + + ", penalty=" + penalty + + '}'; + } +} diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index e147487aa..0c5492456 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -5,10 +5,10 @@ class Turn { private final int roundNumber; - private final ArrayDeque playerACards; - private final ArrayDeque playerBCards; + private final ArrayDeque playerADeck; + private final ArrayDeque playerBDeck; + private final Penalty penalty; private ArrayDeque pile = new ArrayDeque<>(); - private Penalty penalty; private Turn previousRound; private Player playerPlacedLastPaymentCard; private int trick = 0; @@ -16,88 +16,76 @@ class Turn { private Player player; private Card playedCard; + private Player nextPlayer; private Player collector = null; Turn(List playerAList, List playerBList) { roundNumber = 0; - playerACards = playerAList.stream() + playerADeck = playerAList.stream() .map(Card::new) .collect(Collectors.toCollection(ArrayDeque::new)); - playerBCards = playerBList.stream() + playerBDeck = playerBList.stream() .map(Card::new) .collect(Collectors.toCollection(ArrayDeque::new)); + + penalty = new Penalty(); } Turn(Turn previousRound) { this.roundNumber = previousRound.roundNumber + 1; - this.playerACards = new ArrayDeque<>(previousRound.playerACards); - this.playerBCards = new ArrayDeque<>(previousRound.playerBCards); + this.playerADeck = new ArrayDeque<>(previousRound.playerADeck); + this.playerBDeck = new ArrayDeque<>(previousRound.playerBDeck); this.previousRound = previousRound; this.pile = previousRound.pile; this.penalty = previousRound.penalty; - this.penalty = previousRound.penalty != null ? new Penalty(previousRound.penalty) : null; this.trick = previousRound.trick; this.playedCardCounter = previousRound.playedCardCounter; + this.player = previousRound.nextPlayer; } boolean playTurn() { if (isInitialRound()) { + defineNextPlayer(); return false; } - if (isFirstRound()) { - return playFirstTurn(); - } - - player = definePlayer(previousRound); nextMove(); - return win(); - } - - private boolean playFirstTurn() { - player = Player.A; - nextMove(); - - return win(); + defineNextPlayer(); + return win(); } boolean isInitialRound() { return roundNumber == 0; } - boolean isFirstRound() { - return roundNumber == 1; - } - private boolean win() { return getCards(player).size() == totalCards(); } - private Card nextMove() { + private void nextMove() { if (collectPile()) { - return null; + return; } - return playCard(); + playCard(); } - private Card playCard() { + private void playCard() { if (getCards(player).isEmpty()) { // player cannot play - return null; + return; } playedCard = switch (player) { - case A -> playerACards.removeFirst(); - case B -> playerBCards.removeFirst(); + case A -> playerADeck.removeFirst(); + case B -> playerBDeck.removeFirst(); }; pile.add(playedCard); increasePlayedCard(); deductPenalty(); setPlayerPlacedLastPaymentCard(); - return playedCard; } private void increasePlayedCard() { @@ -114,7 +102,8 @@ private void deductPenalty() { } if (playedCard.isPaymentCard()) { - penalty = new Penalty(passPlayer(player), playedCard.getPenalty()); +// penalty = new Penalty(passPlayer(player), playedCard.getPenalty()); + penalty.set(passPlayer(player), playedCard); return; } @@ -127,7 +116,8 @@ private void definePenalty(Card playedCard) { } Player penaltyPlayer = passPlayer(player); - this.penalty = new Penalty(penaltyPlayer, playedCard.getPenalty()); +// this.penalty = new Penalty(penaltyPlayer, playedCard.getPenalty()); + penalty.set(penaltyPlayer, playedCard); } private void setPlayerPlacedLastPaymentCard() { @@ -146,24 +136,15 @@ private boolean collectPile() { previousRound.playedCard == null && getCards(otherPlayer).isEmpty(); - boolean otherPlayerCannotPayPenalty = getCards(otherPlayer).isEmpty() && - penalty != null && - penalty.getPlayer().equals(otherPlayer) && - penalty.getPenalty() > 0; -// -// boolean currentPlayerPlacedLastPaymentCard = player.equals(playerPlacedLastPaymentCard) && -// penalty != null && -// !penalty.isInterrupted(); - boolean penaltyFullyPaidByOpponent = player.equals(playerPlacedLastPaymentCard) && penalty != null && penalty.getPlayer().equals(otherPlayer) && penalty.getPenalty() == 0; - if (otherPlayerCanPlayNoMore || otherPlayerCannotPayPenalty || penaltyFullyPaidByOpponent) { + if (otherPlayerCanPlayNoMore || penaltyFullyPaidByOpponent) { switch (player) { - case A -> playerACards.addAll(pile); - case B -> playerBCards.addAll(pile); + case A -> playerADeck.addAll(pile); + case B -> playerBDeck.addAll(pile); } pile.clear(); @@ -178,7 +159,7 @@ private boolean collectPile() { } private int totalCards() { - return playerACards.size() + playerBCards.size() + pile.size(); + return playerADeck.size() + playerBDeck.size() + pile.size(); } private Player definePlayer(Turn previousRound) { @@ -189,12 +170,41 @@ private Player definePlayer(Turn previousRound) { Penalty previousPenalty = previousRound.penalty; if (previousPenalty != null && previousPenalty.getPenalty() > 0 && !getCards(previousPenalty.getPlayer()).isEmpty()) { - return previousRound.penalty.player; + return previousRound.penalty.getPlayer(); } return passPlayer(previousRound.player); } + private void defineNextPlayer() { + if (isInitialRound()) { + nextPlayer = Player.A; + return; + } + + if (isPenaltyActive() && !isPlayerDeckEmpty(penalty.getPlayer())) { + nextPlayer = penalty.getPlayer(); + return; + } + + nextPlayer = passPlayer(player); + } + + private boolean isPenaltyActive() { + return penalty != null && penalty.isActive(); + } + + private boolean isPenaltyActive(Player player) { + return penalty != null && penalty.isActive() && penalty.getPlayer().equals(player); + } + + private boolean isPlayerDeckEmpty(Player player) { + return switch (player) { + case A -> playerADeck.isEmpty(); + case B -> playerBDeck.isEmpty(); + }; + } + private Player passPlayer(Player player) { if (player == null) { return Player.A; @@ -209,8 +219,8 @@ private Player passPlayer(Player player) { private Deque getCards(Player player) { return switch (player) { - case A -> playerACards; - case B -> playerBCards; + case A -> playerADeck; + case B -> playerBDeck; }; } @@ -231,9 +241,10 @@ public String toString() { return "MatchRound{" + "roundNumber=" + roundNumber + ", player=" + player + + ", nextPlayer=" + nextPlayer + ", playedCard=" + playedCard + - ", playerACards=" + playerACards + - ", playerBCards=" + playerBCards + + ", playerACards=" + playerADeck + + ", playerBCards=" + playerBDeck + ", pile=" + pile + ", penalty=" + penalty + ", trick=" + trick + @@ -245,51 +256,4 @@ enum Player { B } - class Penalty { - private Player player; - private int penalty; - private boolean interrupted = false; - - Penalty(Player player, int penalty) { - this.player = player; - this.penalty = penalty; - } - - Penalty(Penalty other) { - this.player = other.player; - this.penalty = other.penalty; - this.interrupted = other.interrupted; - } - - Player getPlayer() { - return player; - } - - int getPenalty() { - return penalty; - } - - void deduct() { - if (penalty > 0) { - penalty -= 1; - } - } - - public void setInterrupted(boolean interrupted) { - this.interrupted = interrupted; - } - - public boolean isInterrupted() { - return interrupted; - } - - @Override - public String toString() { - return "Penalty{" + - "player=" + player + - ", penalty=" + penalty + - '}'; - } - } - } From 2bbcd2ddf02a9f9415a22fdcdd78d186a41d84a2 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 14:50:32 -0600 Subject: [PATCH 06/24] Implement solution --- .../camicia/src/main/java/Penalty.java | 13 +++-- .../practice/camicia/src/main/java/Turn.java | 50 +++++++++---------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java index 5d2694e2a..61be7ff1f 100644 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -28,6 +28,14 @@ boolean isActive(){ return penalty > 0; } + boolean isFullyPaid() { + return player != null && penalty == 0; + } + + boolean isFullyPaid(Turn.Player player) { + return player != null && player.equals(this.player) && penalty == 0; + } + void clear() { this.player = null; this.penalty = 0; @@ -35,9 +43,6 @@ void clear() { @Override public String toString() { - return "Penalty{" + - "player=" + player + - ", penalty=" + penalty + - '}'; + return player + ":" + penalty; } } diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 0c5492456..8fdc2d42c 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -42,6 +42,7 @@ class Turn { this.trick = previousRound.trick; this.playedCardCounter = previousRound.playedCardCounter; this.player = previousRound.nextPlayer; + this.playerPlacedLastPaymentCard = previousRound.playerPlacedLastPaymentCard; } boolean playTurn() { @@ -52,7 +53,7 @@ boolean playTurn() { nextMove(); defineNextPlayer(); - return win(); + return win(); } boolean isInitialRound() { @@ -102,7 +103,6 @@ private void deductPenalty() { } if (playedCard.isPaymentCard()) { -// penalty = new Penalty(passPlayer(player), playedCard.getPenalty()); penalty.set(passPlayer(player), playedCard); return; } @@ -116,7 +116,6 @@ private void definePenalty(Card playedCard) { } Player penaltyPlayer = passPlayer(player); -// this.penalty = new Penalty(penaltyPlayer, playedCard.getPenalty()); penalty.set(penaltyPlayer, playedCard); } @@ -137,9 +136,7 @@ private boolean collectPile() { getCards(otherPlayer).isEmpty(); boolean penaltyFullyPaidByOpponent = player.equals(playerPlacedLastPaymentCard) && - penalty != null && - penalty.getPlayer().equals(otherPlayer) && - penalty.getPenalty() == 0; + penalty.isFullyPaid(otherPlayer); if (otherPlayerCanPlayNoMore || penaltyFullyPaidByOpponent) { switch (player) { @@ -152,6 +149,11 @@ private boolean collectPile() { trick++; this.collector = player; + if (penaltyFullyPaidByOpponent) { + nextPlayer = player; + penalty.clear(); + } + return true; } @@ -162,21 +164,11 @@ private int totalCards() { return playerADeck.size() + playerBDeck.size() + pile.size(); } - private Player definePlayer(Turn previousRound) { - if (previousRound.collector != null) { - return previousRound.collector; - } - - Penalty previousPenalty = previousRound.penalty; - - if (previousPenalty != null && previousPenalty.getPenalty() > 0 && !getCards(previousPenalty.getPlayer()).isEmpty()) { - return previousRound.penalty.getPlayer(); + private void defineNextPlayer() { + if (nextPlayer != null) { + return; } - return passPlayer(previousRound.player); - } - - private void defineNextPlayer() { if (isInitialRound()) { nextPlayer = Player.A; return; @@ -187,6 +179,11 @@ private void defineNextPlayer() { return; } + if (penalty.isFullyPaid()) { + nextPlayer = playerPlacedLastPaymentCard; + return; + } + nextPlayer = passPlayer(player); } @@ -238,17 +235,16 @@ public Card getPlayedCard() { @Override public String toString() { - return "MatchRound{" + - "roundNumber=" + roundNumber + - ", player=" + player + - ", nextPlayer=" + nextPlayer + + return roundNumber + "." + + " player=" + player + ", playedCard=" + playedCard + - ", playerACards=" + playerADeck + - ", playerBCards=" + playerBDeck + + ", nextPlayer=" + nextPlayer + + ", DeckA=" + playerADeck + + ", DeckB=" + playerBDeck + ", pile=" + pile + ", penalty=" + penalty + - ", trick=" + trick + - '}'; + ", trick=" + trick + ; } enum Player { From a3b38addd2bb8aebff3c709cce8eebaed39a4fa6 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:10:59 -0600 Subject: [PATCH 07/24] Implement solution --- .../practice/camicia/src/main/java/Penalty.java | 4 ++++ .../practice/camicia/src/main/java/Turn.java | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java index 61be7ff1f..28026f485 100644 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -28,6 +28,10 @@ boolean isActive(){ return penalty > 0; } + boolean isActive(Turn.Player player) { + return player != null && player.equals(this.player) && penalty > 0; + } + boolean isFullyPaid() { return player != null && penalty == 0; } diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 8fdc2d42c..81a5f4500 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -135,10 +135,14 @@ private boolean collectPile() { previousRound.playedCard == null && getCards(otherPlayer).isEmpty(); + boolean otherPlayerCannotPayPenalty = otherPlayer.equals(previousRound.player) && + penalty.isActive(otherPlayer) && + getCards(otherPlayer).isEmpty(); + boolean penaltyFullyPaidByOpponent = player.equals(playerPlacedLastPaymentCard) && penalty.isFullyPaid(otherPlayer); - if (otherPlayerCanPlayNoMore || penaltyFullyPaidByOpponent) { + if (otherPlayerCanPlayNoMore || otherPlayerCannotPayPenalty || penaltyFullyPaidByOpponent) { switch (player) { case A -> playerADeck.addAll(pile); case B -> playerBDeck.addAll(pile); @@ -174,9 +178,14 @@ private void defineNextPlayer() { return; } - if (isPenaltyActive() && !isPlayerDeckEmpty(penalty.getPlayer())) { - nextPlayer = penalty.getPlayer(); - return; +// if (isPenaltyActive() && !isPlayerDeckEmpty(penalty.getPlayer())) { + if (isPenaltyActive()) { + if (!isPlayerDeckEmpty(penalty.getPlayer())) { + nextPlayer = penalty.getPlayer(); + return; + } else { + nextPlayer = passPlayer(player); + } } if (penalty.isFullyPaid()) { From 4fd0bb351c241497cb5ada49ef5e89ca80fdc9c3 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:33:22 -0600 Subject: [PATCH 08/24] Implement solution --- .../practice/camicia/src/main/java/Turn.java | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 81a5f4500..3721af4ca 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -17,7 +17,6 @@ class Turn { private Player player; private Card playedCard; private Player nextPlayer; - private Player collector = null; Turn(List playerAList, List playerBList) { roundNumber = 0; @@ -103,7 +102,7 @@ private void deductPenalty() { } if (playedCard.isPaymentCard()) { - penalty.set(passPlayer(player), playedCard); + penalty.set(opponent(player), playedCard); return; } @@ -115,7 +114,7 @@ private void definePenalty(Card playedCard) { return; } - Player penaltyPlayer = passPlayer(player); + Player penaltyPlayer = opponent(player); penalty.set(penaltyPlayer, playedCard); } @@ -129,20 +128,11 @@ private void setPlayerPlacedLastPaymentCard() { } private boolean collectPile() { - Player otherPlayer = passPlayer(player); + boolean opponentDeckExhausted = isOpponentDeckExhausted(); + boolean opponentUnableToPayPenalty = isOpponentUnableToPayPenalty(); + boolean penaltyFullyPaidByOpponent = isPenaltyFullyPaidByOpponent(); - boolean otherPlayerCanPlayNoMore = otherPlayer.equals(previousRound.player) && - previousRound.playedCard == null && - getCards(otherPlayer).isEmpty(); - - boolean otherPlayerCannotPayPenalty = otherPlayer.equals(previousRound.player) && - penalty.isActive(otherPlayer) && - getCards(otherPlayer).isEmpty(); - - boolean penaltyFullyPaidByOpponent = player.equals(playerPlacedLastPaymentCard) && - penalty.isFullyPaid(otherPlayer); - - if (otherPlayerCanPlayNoMore || otherPlayerCannotPayPenalty || penaltyFullyPaidByOpponent) { + if (opponentDeckExhausted || opponentUnableToPayPenalty || penaltyFullyPaidByOpponent) { switch (player) { case A -> playerADeck.addAll(pile); case B -> playerBDeck.addAll(pile); @@ -151,9 +141,8 @@ private boolean collectPile() { pile.clear(); trick++; - this.collector = player; - if (penaltyFullyPaidByOpponent) { + if (isPenaltyFullyPaidByOpponent()) { nextPlayer = player; penalty.clear(); } @@ -164,6 +153,29 @@ private boolean collectPile() { return false; } + private boolean isPenaltyFullyPaidByOpponent() { + Player otherPlayer = opponent(player); + + return player.equals(playerPlacedLastPaymentCard) && + penalty.isFullyPaid(otherPlayer); + } + + private boolean isOpponentUnableToPayPenalty() { + Player opponent = opponent(player); + + return opponent.equals(previousRound.player) && + isPenaltyActive(opponent) && + getCards(opponent).isEmpty(); + } + + private boolean isOpponentDeckExhausted() { + Player opponent = opponent(player); + + return opponent.equals(previousRound.player) && + previousRound.playedCard == null && + getCards(opponent).isEmpty(); + } + private int totalCards() { return playerADeck.size() + playerBDeck.size() + pile.size(); } @@ -178,14 +190,13 @@ private void defineNextPlayer() { return; } -// if (isPenaltyActive() && !isPlayerDeckEmpty(penalty.getPlayer())) { if (isPenaltyActive()) { - if (!isPlayerDeckEmpty(penalty.getPlayer())) { - nextPlayer = penalty.getPlayer(); - return; + if (isPlayerDeckEmpty(penalty.getPlayer())) { + nextPlayer = opponent(player); } else { - nextPlayer = passPlayer(player); + nextPlayer = penalty.getPlayer(); } + return; } if (penalty.isFullyPaid()) { @@ -193,7 +204,7 @@ private void defineNextPlayer() { return; } - nextPlayer = passPlayer(player); + nextPlayer = opponent(player); } private boolean isPenaltyActive() { @@ -201,7 +212,7 @@ private boolean isPenaltyActive() { } private boolean isPenaltyActive(Player player) { - return penalty != null && penalty.isActive() && penalty.getPlayer().equals(player); + return penalty != null && penalty.isActive(player); } private boolean isPlayerDeckEmpty(Player player) { @@ -211,7 +222,7 @@ private boolean isPlayerDeckEmpty(Player player) { }; } - private Player passPlayer(Player player) { + private Player opponent(Player player) { if (player == null) { return Player.A; } From bee81c11510b869fcdccc60889ae2423335bfc05 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:34:58 -0600 Subject: [PATCH 09/24] Implement solution --- exercises/practice/camicia/src/main/java/Penalty.java | 2 +- exercises/practice/camicia/src/main/java/Turn.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java index 28026f485..4db371199 100644 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -13,7 +13,7 @@ int getPenalty() { return penalty; } - public void set(Turn.Player player, Card card) { + void set(Turn.Player player, Card card) { this.player = player; this.penalty = card.getPenalty(); } diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 3721af4ca..5ceda8fed 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -249,10 +249,6 @@ int getTrick() { return trick; } - public Card getPlayedCard() { - return playedCard; - } - @Override public String toString() { return roundNumber + "." + From 1f7a8b5be31584fee4f891700bbe464ecc202387 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:46:57 -0600 Subject: [PATCH 10/24] Implement solution --- .../camicia/src/main/java/Penalty.java | 10 ++--- .../camicia/src/main/java/Player.java | 4 ++ .../practice/camicia/src/main/java/Turn.java | 40 ++++++++----------- 3 files changed, 26 insertions(+), 28 deletions(-) create mode 100644 exercises/practice/camicia/src/main/java/Player.java diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java index 4db371199..65a6002fb 100644 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -1,11 +1,11 @@ class Penalty { - private Turn.Player player; + private Player player; private int penalty; Penalty() { } - Turn.Player getPlayer() { + Player getPlayer() { return player; } @@ -13,7 +13,7 @@ int getPenalty() { return penalty; } - void set(Turn.Player player, Card card) { + void set(Player player, Card card) { this.player = player; this.penalty = card.getPenalty(); } @@ -28,7 +28,7 @@ boolean isActive(){ return penalty > 0; } - boolean isActive(Turn.Player player) { + boolean isActive(Player player) { return player != null && player.equals(this.player) && penalty > 0; } @@ -36,7 +36,7 @@ boolean isFullyPaid() { return player != null && penalty == 0; } - boolean isFullyPaid(Turn.Player player) { + boolean isFullyPaid(Player player) { return player != null && player.equals(this.player) && penalty == 0; } diff --git a/exercises/practice/camicia/src/main/java/Player.java b/exercises/practice/camicia/src/main/java/Player.java new file mode 100644 index 000000000..e0ee73e95 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/Player.java @@ -0,0 +1,4 @@ +enum Player { + A, + B +} diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 5ceda8fed..70cbd667c 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -5,8 +5,8 @@ class Turn { private final int roundNumber; - private final ArrayDeque playerADeck; - private final ArrayDeque playerBDeck; + private final ArrayDeque deckA; + private final ArrayDeque deckB; private final Penalty penalty; private ArrayDeque pile = new ArrayDeque<>(); private Turn previousRound; @@ -20,11 +20,11 @@ class Turn { Turn(List playerAList, List playerBList) { roundNumber = 0; - playerADeck = playerAList.stream() + deckA = playerAList.stream() .map(Card::new) .collect(Collectors.toCollection(ArrayDeque::new)); - playerBDeck = playerBList.stream() + deckB = playerBList.stream() .map(Card::new) .collect(Collectors.toCollection(ArrayDeque::new)); @@ -33,8 +33,8 @@ class Turn { Turn(Turn previousRound) { this.roundNumber = previousRound.roundNumber + 1; - this.playerADeck = new ArrayDeque<>(previousRound.playerADeck); - this.playerBDeck = new ArrayDeque<>(previousRound.playerBDeck); + this.deckA = new ArrayDeque<>(previousRound.deckA); + this.deckB = new ArrayDeque<>(previousRound.deckB); this.previousRound = previousRound; this.pile = previousRound.pile; this.penalty = previousRound.penalty; @@ -78,8 +78,8 @@ private void playCard() { } playedCard = switch (player) { - case A -> playerADeck.removeFirst(); - case B -> playerBDeck.removeFirst(); + case A -> deckA.removeFirst(); + case B -> deckB.removeFirst(); }; pile.add(playedCard); @@ -134,8 +134,8 @@ private boolean collectPile() { if (opponentDeckExhausted || opponentUnableToPayPenalty || penaltyFullyPaidByOpponent) { switch (player) { - case A -> playerADeck.addAll(pile); - case B -> playerBDeck.addAll(pile); + case A -> deckA.addAll(pile); + case B -> deckB.addAll(pile); } pile.clear(); @@ -177,7 +177,7 @@ private boolean isOpponentDeckExhausted() { } private int totalCards() { - return playerADeck.size() + playerBDeck.size() + pile.size(); + return deckA.size() + deckB.size() + pile.size(); } private void defineNextPlayer() { @@ -217,8 +217,8 @@ private boolean isPenaltyActive(Player player) { private boolean isPlayerDeckEmpty(Player player) { return switch (player) { - case A -> playerADeck.isEmpty(); - case B -> playerBDeck.isEmpty(); + case A -> deckA.isEmpty(); + case B -> deckB.isEmpty(); }; } @@ -236,8 +236,8 @@ private Player opponent(Player player) { private Deque getCards(Player player) { return switch (player) { - case A -> playerADeck; - case B -> playerBDeck; + case A -> deckA; + case B -> deckB; }; } @@ -255,17 +255,11 @@ public String toString() { " player=" + player + ", playedCard=" + playedCard + ", nextPlayer=" + nextPlayer + - ", DeckA=" + playerADeck + - ", DeckB=" + playerBDeck + + ", DeckA=" + deckA + + ", DeckB=" + deckB + ", pile=" + pile + ", penalty=" + penalty + ", trick=" + trick ; } - - enum Player { - A, - B - } - } From ec66e053d0c635ebf4e780a6fca026442ba9f5e3 Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:48:46 -0600 Subject: [PATCH 11/24] Implement solution --- .../practice/camicia/src/main/java/Turn.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index 70cbd667c..c898f1d18 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -72,7 +72,7 @@ private void nextMove() { } private void playCard() { - if (getCards(player).isEmpty()) { + if (isDeckEmpty(player)) { // player cannot play return; } @@ -165,7 +165,7 @@ private boolean isOpponentUnableToPayPenalty() { return opponent.equals(previousRound.player) && isPenaltyActive(opponent) && - getCards(opponent).isEmpty(); + isDeckEmpty(opponent); } private boolean isOpponentDeckExhausted() { @@ -173,7 +173,7 @@ private boolean isOpponentDeckExhausted() { return opponent.equals(previousRound.player) && previousRound.playedCard == null && - getCards(opponent).isEmpty(); + isDeckEmpty(opponent); } private int totalCards() { @@ -191,7 +191,7 @@ private void defineNextPlayer() { } if (isPenaltyActive()) { - if (isPlayerDeckEmpty(penalty.getPlayer())) { + if (isDeckEmpty(penalty.getPlayer())) { nextPlayer = opponent(player); } else { nextPlayer = penalty.getPlayer(); @@ -215,7 +215,7 @@ private boolean isPenaltyActive(Player player) { return penalty != null && penalty.isActive(player); } - private boolean isPlayerDeckEmpty(Player player) { + private boolean isDeckEmpty(Player player) { return switch (player) { case A -> deckA.isEmpty(); case B -> deckB.isEmpty(); @@ -223,11 +223,6 @@ private boolean isPlayerDeckEmpty(Player player) { } private Player opponent(Player player) { - if (player == null) { - return Player.A; - } - - return switch (player) { case Player.A -> Player.B; case Player.B -> Player.A; From 8b279ee816a8c4b7366c52fbc60dd6d3a2daad1d Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 15:59:15 -0600 Subject: [PATCH 12/24] Implement solution --- .../camicia/src/main/java/Penalty.java | 16 --------------- .../practice/camicia/src/main/java/Turn.java | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java index 65a6002fb..5231a6f62 100644 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ b/exercises/practice/camicia/src/main/java/Penalty.java @@ -24,22 +24,6 @@ void deduct() { } } - boolean isActive(){ - return penalty > 0; - } - - boolean isActive(Player player) { - return player != null && player.equals(this.player) && penalty > 0; - } - - boolean isFullyPaid() { - return player != null && penalty == 0; - } - - boolean isFullyPaid(Player player) { - return player != null && player.equals(this.player) && penalty == 0; - } - void clear() { this.player = null; this.penalty = 0; diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java index c898f1d18..4a3380f65 100644 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ b/exercises/practice/camicia/src/main/java/Turn.java @@ -7,12 +7,12 @@ class Turn { private final int roundNumber; private final ArrayDeque deckA; private final ArrayDeque deckB; - private final Penalty penalty; private ArrayDeque pile = new ArrayDeque<>(); - private Turn previousRound; + private final Penalty penalty; private Player playerPlacedLastPaymentCard; private int trick = 0; private int playedCardCounter = 0; + private Turn previousRound; private Player player; private Card playedCard; @@ -157,7 +157,7 @@ private boolean isPenaltyFullyPaidByOpponent() { Player otherPlayer = opponent(player); return player.equals(playerPlacedLastPaymentCard) && - penalty.isFullyPaid(otherPlayer); + isPenaltyFullyPaid(otherPlayer); } private boolean isOpponentUnableToPayPenalty() { @@ -199,7 +199,7 @@ private void defineNextPlayer() { return; } - if (penalty.isFullyPaid()) { + if (isPenaltyFullyPaid()) { nextPlayer = playerPlacedLastPaymentCard; return; } @@ -208,11 +208,19 @@ private void defineNextPlayer() { } private boolean isPenaltyActive() { - return penalty != null && penalty.isActive(); + return penalty != null && penalty.getPenalty() > 0; } private boolean isPenaltyActive(Player player) { - return penalty != null && penalty.isActive(player); + return penalty != null && penalty.getPenalty() > 0 && penalty.getPlayer().equals(player); + } + + boolean isPenaltyFullyPaid() { + return penalty != null && penalty.getPlayer() != null && penalty.getPenalty() == 0; + } + + boolean isPenaltyFullyPaid(Player player) { + return isPenaltyFullyPaid() && penalty.getPlayer().equals(player); } private boolean isDeckEmpty(Player player) { From 3e04726f97683f1070b7fb78045344fafb5e4caa Mon Sep 17 00:00:00 2001 From: thibault2705 Date: Tue, 18 Nov 2025 16:38:56 -0600 Subject: [PATCH 13/24] Implement solution --- exercises/practice/camicia/src/main/java/Card.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exercises/practice/camicia/src/main/java/Card.java b/exercises/practice/camicia/src/main/java/Card.java index ccd24a356..82758b342 100644 --- a/exercises/practice/camicia/src/main/java/Card.java +++ b/exercises/practice/camicia/src/main/java/Card.java @@ -5,7 +5,7 @@ class Card { protected Card(String symbol) { this.symbol = symbol; - this.penalty = getPenalty(symbol); + this.penalty = definePenalty(symbol); } int getPenalty() { @@ -24,7 +24,11 @@ public String toString() { return symbol; } - static int getPenalty(String card) { + static Card copyCard(Card card) { + return new Card(card.symbol); + } + + static int definePenalty(String card) { return switch (card) { case "J" -> 1; case "Q" -> 2; From a510e82d8f0c0aa40aa40a0e005449bcf10e1416 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Thu, 16 Apr 2026 10:43:38 -0600 Subject: [PATCH 14/24] Implement solution --- .../camicia/src/main/java/Camicia.java | 181 ++++++++++-- .../practice/camicia/src/main/java/Card.java | 40 --- .../camicia/src/main/java/MatchResult.java | 75 ----- .../camicia/src/main/java/Penalty.java | 36 --- .../camicia/src/main/java/Player.java | 4 - .../practice/camicia/src/main/java/Turn.java | 268 ------------------ 6 files changed, 157 insertions(+), 447 deletions(-) delete mode 100644 exercises/practice/camicia/src/main/java/Card.java delete mode 100644 exercises/practice/camicia/src/main/java/MatchResult.java delete mode 100644 exercises/practice/camicia/src/main/java/Penalty.java delete mode 100644 exercises/practice/camicia/src/main/java/Player.java delete mode 100644 exercises/practice/camicia/src/main/java/Turn.java diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java index fdeb2876b..6b585989b 100644 --- a/exercises/practice/camicia/src/main/java/Camicia.java +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -1,39 +1,172 @@ -import java.util.*; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; +import java.util.Set; -class Camicia { +public class Camicia { - private MatchResult matchResult; + private Status status; + private int cards; + private int tricks; - void simulateGame(List playerAList, List playerBList) { - Turn initialTurn = new Turn(playerAList, playerBList); - boolean win = initialTurn.playTurn(); - System.out.println(initialTurn); - Turn turn = initialTurn; + private enum Player { + PLAYER_A, PLAYER_B + } + + private enum Status { + FINISHED, LOOP + } + + private static int penaltyOf(String card) { + return switch (card) { + case "J" -> 1; + case "Q" -> 2; + case "K" -> 3; + case "A" -> 4; + default -> 0; + }; + } + + private static boolean isPaymentCard(String card) { + return penaltyOf(card) > 0; + } + + /** + * Return a snapshot of the current state + */ + private static String stateKey(Deque deckA, Deque deckB) { + StringBuilder sb = new StringBuilder(); + + for (String card : deckA) { + sb.append(isPaymentCard(card) ? card : "N"); + } - while (!win) { - Turn newTurn = new Turn(turn); - win = newTurn.playTurn(); - System.out.println(newTurn); + sb.append('|'); - turn = newTurn; + for (String card : deckB) { + sb.append(isPaymentCard(card) ? card : "N"); } - matchResult = MatchResult.builder() - .withStatus(MatchResult.Status.FINISHED) - .withCards(turn.getPlayedCardCounter()) - .withTricks(turn.getTrick()) - .build(); + return sb.toString(); + } + + private static Player otherPlayer(Player player) { + return player == Player.PLAYER_A ? Player.PLAYER_B : Player.PLAYER_A; + } + + private static Deque deckOf(Player player, Deque deckA, Deque deckB) { + return player == Player.PLAYER_A ? deckA : deckB; + } + + public void simulateGame(List playerA, List playerB) { + Deque deckA = new ArrayDeque<>(playerA); + Deque deckB = new ArrayDeque<>(playerB); + + int cardsPlayed = 0; + int tricksCount = 0; + Player current = Player.PLAYER_A; + + Set seenStates = new HashSet<>(); + + while (true) { + String key = stateKey(deckA, deckB); + // Key already exists, which means this is a loop + if (!seenStates.add(key)) { + finishGame(Status.LOOP, cardsPlayed, tricksCount); + return; + } + + // Otherwise, play next round + RoundResult result = playRound(deckA, deckB, current); + + cardsPlayed += result.pileSize(); + tricksCount++; + + // Check if someone wins and finish the game + if (hasWinner(deckA, deckB)) { + finishGame(Status.FINISHED, cardsPlayed, tricksCount); + return; + } + + // Otherwise, play next round + current = result.nextStarter(); + } + } + + private RoundResult playRound(Deque deckA, Deque deckB, Player startingPlayer) { + Deque pile = new ArrayDeque<>(); // cards played in this round + Player currentPlayer = startingPlayer; + int pendingPenalty = 0; + + while (true) { + Deque currentPlayerDeck = deckOf(currentPlayer, deckA, deckB); + Player opponent = otherPlayer(currentPlayer); + Deque opponentDeck = deckOf(opponent, deckA, deckB); + + // Current player deck is empty, opponent collects all pile, end this round + if (currentPlayerDeck.isEmpty()) { + opponentDeck.addAll(pile); + return new RoundResult(opponent, pile.size()); + } + + // Otherwise, current player plays 1 card, add to pile + String card = currentPlayerDeck.poll(); + pile.addLast(card); + + // Current player must pay off pending penalty + if (pendingPenalty > 0) { + // And player reveals a payment card + if (isPaymentCard(card)) { + // reset penalty based on new card, switch turn + pendingPenalty = penaltyOf(card); + currentPlayer = opponent; + } else { + // Otherwise, deduct penalty + pendingPenalty--; + // No pending penalty + if (pendingPenalty == 0) { + // Opponent collects all pile and win the round + deckOf(opponent, deckA, deckB).addAll(pile); + return new RoundResult(opponent, pile.size()); + } + } + } else { + // Normal gameplay, without pending penalty + // If player reveals a payment card, update penalty + if (isPaymentCard(card)) { + pendingPenalty = penaltyOf(card); + } + currentPlayer = opponent; + } + } + } + + private void finishGame(Status status, int cardsPlayed, int tricksCount) { + this.status = status; + this.cards = cardsPlayed; + this.tricks = tricksCount; + } + + private boolean hasWinner(Deque deckA, Deque deckB) { + return deckA.isEmpty() || deckB.isEmpty(); + } + + public String getStatus() { + return status != null ? status.name().toLowerCase() : ""; } - String getStatus() { - return matchResult.getStatus().name().toLowerCase(); + public int getCards() { + return cards; } - int getCards() { - return matchResult.getCards(); + public int getTricks() { + return tricks; } - int getTricks() { - return matchResult.getTricks(); + /** + * Immutable round result + */ + private record RoundResult(Player nextStarter, int pileSize) { } } \ No newline at end of file diff --git a/exercises/practice/camicia/src/main/java/Card.java b/exercises/practice/camicia/src/main/java/Card.java deleted file mode 100644 index 82758b342..000000000 --- a/exercises/practice/camicia/src/main/java/Card.java +++ /dev/null @@ -1,40 +0,0 @@ -class Card { - - private final String symbol; - private final int penalty; - - protected Card(String symbol) { - this.symbol = symbol; - this.penalty = definePenalty(symbol); - } - - int getPenalty() { - return penalty; - } - - public boolean isPaymentCard() { - return switch (symbol) { - case "J", "Q", "K", "A" -> true; - default -> false; - }; - } - - @Override - public String toString() { - return symbol; - } - - static Card copyCard(Card card) { - return new Card(card.symbol); - } - - static int definePenalty(String card) { - return switch (card) { - case "J" -> 1; - case "Q" -> 2; - case "K" -> 3; - case "A" -> 4; - default -> 0; - }; - } -} diff --git a/exercises/practice/camicia/src/main/java/MatchResult.java b/exercises/practice/camicia/src/main/java/MatchResult.java deleted file mode 100644 index 20b7e8fd6..000000000 --- a/exercises/practice/camicia/src/main/java/MatchResult.java +++ /dev/null @@ -1,75 +0,0 @@ -class MatchResult { - /** - * Match status: finished or loop - */ - Status status; - - /** - * Total number of cards played throughout the game - */ - int cards; - - /** - * Number of times the central pile was collected - */ - int tricks; - - private MatchResult() { - - } - - private MatchResult(Status status, int cards, int tricks) { - this.status = status; - this.cards = cards; - this.tricks = tricks; - } - - Status getStatus() { - return status; - } - - int getCards() { - return cards; - } - - int getTricks() { - return tricks; - } - - static MatchBuilder builder() { - return new MatchBuilder(); - } - - static final class MatchBuilder { - private Status status; - private int cards; - private int tricks; - - private MatchBuilder() { - } - - MatchBuilder withStatus(Status status) { - this.status = status; - return this; - } - - MatchBuilder withCards(int cards) { - this.cards = cards; - return this; - } - - MatchBuilder withTricks(int tricks) { - this.tricks = tricks; - return this; - } - - MatchResult build() { - return new MatchResult(status, cards, tricks); - } - } - - enum Status { - FINISHED, - LOOP - } -} \ No newline at end of file diff --git a/exercises/practice/camicia/src/main/java/Penalty.java b/exercises/practice/camicia/src/main/java/Penalty.java deleted file mode 100644 index 5231a6f62..000000000 --- a/exercises/practice/camicia/src/main/java/Penalty.java +++ /dev/null @@ -1,36 +0,0 @@ -class Penalty { - private Player player; - private int penalty; - - Penalty() { - } - - Player getPlayer() { - return player; - } - - int getPenalty() { - return penalty; - } - - void set(Player player, Card card) { - this.player = player; - this.penalty = card.getPenalty(); - } - - void deduct() { - if (penalty > 0) { - penalty -= 1; - } - } - - void clear() { - this.player = null; - this.penalty = 0; - } - - @Override - public String toString() { - return player + ":" + penalty; - } -} diff --git a/exercises/practice/camicia/src/main/java/Player.java b/exercises/practice/camicia/src/main/java/Player.java deleted file mode 100644 index e0ee73e95..000000000 --- a/exercises/practice/camicia/src/main/java/Player.java +++ /dev/null @@ -1,4 +0,0 @@ -enum Player { - A, - B -} diff --git a/exercises/practice/camicia/src/main/java/Turn.java b/exercises/practice/camicia/src/main/java/Turn.java deleted file mode 100644 index 4a3380f65..000000000 --- a/exercises/practice/camicia/src/main/java/Turn.java +++ /dev/null @@ -1,268 +0,0 @@ -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.List; -import java.util.stream.Collectors; - -class Turn { - private final int roundNumber; - private final ArrayDeque deckA; - private final ArrayDeque deckB; - private ArrayDeque pile = new ArrayDeque<>(); - private final Penalty penalty; - private Player playerPlacedLastPaymentCard; - private int trick = 0; - private int playedCardCounter = 0; - private Turn previousRound; - - private Player player; - private Card playedCard; - private Player nextPlayer; - - Turn(List playerAList, List playerBList) { - roundNumber = 0; - deckA = playerAList.stream() - .map(Card::new) - .collect(Collectors.toCollection(ArrayDeque::new)); - - deckB = playerBList.stream() - .map(Card::new) - .collect(Collectors.toCollection(ArrayDeque::new)); - - penalty = new Penalty(); - } - - Turn(Turn previousRound) { - this.roundNumber = previousRound.roundNumber + 1; - this.deckA = new ArrayDeque<>(previousRound.deckA); - this.deckB = new ArrayDeque<>(previousRound.deckB); - this.previousRound = previousRound; - this.pile = previousRound.pile; - this.penalty = previousRound.penalty; - this.trick = previousRound.trick; - this.playedCardCounter = previousRound.playedCardCounter; - this.player = previousRound.nextPlayer; - this.playerPlacedLastPaymentCard = previousRound.playerPlacedLastPaymentCard; - } - - boolean playTurn() { - if (isInitialRound()) { - defineNextPlayer(); - return false; - } - - nextMove(); - defineNextPlayer(); - return win(); - } - - boolean isInitialRound() { - return roundNumber == 0; - } - - private boolean win() { - return getCards(player).size() == totalCards(); - } - - private void nextMove() { - if (collectPile()) { - return; - } - - playCard(); - } - - private void playCard() { - if (isDeckEmpty(player)) { - // player cannot play - return; - } - - playedCard = switch (player) { - case A -> deckA.removeFirst(); - case B -> deckB.removeFirst(); - }; - - pile.add(playedCard); - increasePlayedCard(); - deductPenalty(); - setPlayerPlacedLastPaymentCard(); - } - - private void increasePlayedCard() { - playedCardCounter++; - } - - private void deductPenalty() { - if (penalty == null) { - return; - } - - if (!player.equals(penalty.getPlayer())) { - return; - } - - if (playedCard.isPaymentCard()) { - penalty.set(opponent(player), playedCard); - return; - } - - penalty.deduct(); - } - - private void definePenalty(Card playedCard) { - if (!playedCard.isPaymentCard()) { - return; - } - - Player penaltyPlayer = opponent(player); - penalty.set(penaltyPlayer, playedCard); - } - - private void setPlayerPlacedLastPaymentCard() { - if (!playedCard.isPaymentCard()) { - return; - } - - this.playerPlacedLastPaymentCard = player; - definePenalty(playedCard); - } - - private boolean collectPile() { - boolean opponentDeckExhausted = isOpponentDeckExhausted(); - boolean opponentUnableToPayPenalty = isOpponentUnableToPayPenalty(); - boolean penaltyFullyPaidByOpponent = isPenaltyFullyPaidByOpponent(); - - if (opponentDeckExhausted || opponentUnableToPayPenalty || penaltyFullyPaidByOpponent) { - switch (player) { - case A -> deckA.addAll(pile); - case B -> deckB.addAll(pile); - } - - pile.clear(); - - trick++; - - if (isPenaltyFullyPaidByOpponent()) { - nextPlayer = player; - penalty.clear(); - } - - return true; - } - - return false; - } - - private boolean isPenaltyFullyPaidByOpponent() { - Player otherPlayer = opponent(player); - - return player.equals(playerPlacedLastPaymentCard) && - isPenaltyFullyPaid(otherPlayer); - } - - private boolean isOpponentUnableToPayPenalty() { - Player opponent = opponent(player); - - return opponent.equals(previousRound.player) && - isPenaltyActive(opponent) && - isDeckEmpty(opponent); - } - - private boolean isOpponentDeckExhausted() { - Player opponent = opponent(player); - - return opponent.equals(previousRound.player) && - previousRound.playedCard == null && - isDeckEmpty(opponent); - } - - private int totalCards() { - return deckA.size() + deckB.size() + pile.size(); - } - - private void defineNextPlayer() { - if (nextPlayer != null) { - return; - } - - if (isInitialRound()) { - nextPlayer = Player.A; - return; - } - - if (isPenaltyActive()) { - if (isDeckEmpty(penalty.getPlayer())) { - nextPlayer = opponent(player); - } else { - nextPlayer = penalty.getPlayer(); - } - return; - } - - if (isPenaltyFullyPaid()) { - nextPlayer = playerPlacedLastPaymentCard; - return; - } - - nextPlayer = opponent(player); - } - - private boolean isPenaltyActive() { - return penalty != null && penalty.getPenalty() > 0; - } - - private boolean isPenaltyActive(Player player) { - return penalty != null && penalty.getPenalty() > 0 && penalty.getPlayer().equals(player); - } - - boolean isPenaltyFullyPaid() { - return penalty != null && penalty.getPlayer() != null && penalty.getPenalty() == 0; - } - - boolean isPenaltyFullyPaid(Player player) { - return isPenaltyFullyPaid() && penalty.getPlayer().equals(player); - } - - private boolean isDeckEmpty(Player player) { - return switch (player) { - case A -> deckA.isEmpty(); - case B -> deckB.isEmpty(); - }; - } - - private Player opponent(Player player) { - return switch (player) { - case Player.A -> Player.B; - case Player.B -> Player.A; - }; - } - - private Deque getCards(Player player) { - return switch (player) { - case A -> deckA; - case B -> deckB; - }; - } - - int getPlayedCardCounter() { - return playedCardCounter; - } - - int getTrick() { - return trick; - } - - @Override - public String toString() { - return roundNumber + "." + - " player=" + player + - ", playedCard=" + playedCard + - ", nextPlayer=" + nextPlayer + - ", DeckA=" + deckA + - ", DeckB=" + deckB + - ", pile=" + pile + - ", penalty=" + penalty + - ", trick=" + trick - ; - } -} From c15e3fe9fd10f20418a190a20450cf13367a37b6 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Thu, 16 Apr 2026 10:54:25 -0600 Subject: [PATCH 15/24] Move solution to the .meta package --- .../practice/camicia/.meta/src/Camicia.java | 172 ++++++++++++++++++ .../camicia/src/main/java/Camicia.java | 168 +---------------- 2 files changed, 180 insertions(+), 160 deletions(-) create mode 100644 exercises/practice/camicia/.meta/src/Camicia.java diff --git a/exercises/practice/camicia/.meta/src/Camicia.java b/exercises/practice/camicia/.meta/src/Camicia.java new file mode 100644 index 000000000..6b585989b --- /dev/null +++ b/exercises/practice/camicia/.meta/src/Camicia.java @@ -0,0 +1,172 @@ +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class Camicia { + + private Status status; + private int cards; + private int tricks; + + private enum Player { + PLAYER_A, PLAYER_B + } + + private enum Status { + FINISHED, LOOP + } + + private static int penaltyOf(String card) { + return switch (card) { + case "J" -> 1; + case "Q" -> 2; + case "K" -> 3; + case "A" -> 4; + default -> 0; + }; + } + + private static boolean isPaymentCard(String card) { + return penaltyOf(card) > 0; + } + + /** + * Return a snapshot of the current state + */ + private static String stateKey(Deque deckA, Deque deckB) { + StringBuilder sb = new StringBuilder(); + + for (String card : deckA) { + sb.append(isPaymentCard(card) ? card : "N"); + } + + sb.append('|'); + + for (String card : deckB) { + sb.append(isPaymentCard(card) ? card : "N"); + } + + return sb.toString(); + } + + private static Player otherPlayer(Player player) { + return player == Player.PLAYER_A ? Player.PLAYER_B : Player.PLAYER_A; + } + + private static Deque deckOf(Player player, Deque deckA, Deque deckB) { + return player == Player.PLAYER_A ? deckA : deckB; + } + + public void simulateGame(List playerA, List playerB) { + Deque deckA = new ArrayDeque<>(playerA); + Deque deckB = new ArrayDeque<>(playerB); + + int cardsPlayed = 0; + int tricksCount = 0; + Player current = Player.PLAYER_A; + + Set seenStates = new HashSet<>(); + + while (true) { + String key = stateKey(deckA, deckB); + // Key already exists, which means this is a loop + if (!seenStates.add(key)) { + finishGame(Status.LOOP, cardsPlayed, tricksCount); + return; + } + + // Otherwise, play next round + RoundResult result = playRound(deckA, deckB, current); + + cardsPlayed += result.pileSize(); + tricksCount++; + + // Check if someone wins and finish the game + if (hasWinner(deckA, deckB)) { + finishGame(Status.FINISHED, cardsPlayed, tricksCount); + return; + } + + // Otherwise, play next round + current = result.nextStarter(); + } + } + + private RoundResult playRound(Deque deckA, Deque deckB, Player startingPlayer) { + Deque pile = new ArrayDeque<>(); // cards played in this round + Player currentPlayer = startingPlayer; + int pendingPenalty = 0; + + while (true) { + Deque currentPlayerDeck = deckOf(currentPlayer, deckA, deckB); + Player opponent = otherPlayer(currentPlayer); + Deque opponentDeck = deckOf(opponent, deckA, deckB); + + // Current player deck is empty, opponent collects all pile, end this round + if (currentPlayerDeck.isEmpty()) { + opponentDeck.addAll(pile); + return new RoundResult(opponent, pile.size()); + } + + // Otherwise, current player plays 1 card, add to pile + String card = currentPlayerDeck.poll(); + pile.addLast(card); + + // Current player must pay off pending penalty + if (pendingPenalty > 0) { + // And player reveals a payment card + if (isPaymentCard(card)) { + // reset penalty based on new card, switch turn + pendingPenalty = penaltyOf(card); + currentPlayer = opponent; + } else { + // Otherwise, deduct penalty + pendingPenalty--; + // No pending penalty + if (pendingPenalty == 0) { + // Opponent collects all pile and win the round + deckOf(opponent, deckA, deckB).addAll(pile); + return new RoundResult(opponent, pile.size()); + } + } + } else { + // Normal gameplay, without pending penalty + // If player reveals a payment card, update penalty + if (isPaymentCard(card)) { + pendingPenalty = penaltyOf(card); + } + currentPlayer = opponent; + } + } + } + + private void finishGame(Status status, int cardsPlayed, int tricksCount) { + this.status = status; + this.cards = cardsPlayed; + this.tricks = tricksCount; + } + + private boolean hasWinner(Deque deckA, Deque deckB) { + return deckA.isEmpty() || deckB.isEmpty(); + } + + public String getStatus() { + return status != null ? status.name().toLowerCase() : ""; + } + + public int getCards() { + return cards; + } + + public int getTricks() { + return tricks; + } + + /** + * Immutable round result + */ + private record RoundResult(Player nextStarter, int pileSize) { + } +} \ No newline at end of file diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java index 6b585989b..7818944a8 100644 --- a/exercises/practice/camicia/src/main/java/Camicia.java +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -1,172 +1,20 @@ -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashSet; import java.util.List; -import java.util.Set; public class Camicia { - private Status status; - private int cards; - private int tricks; - - private enum Player { - PLAYER_A, PLAYER_B - } - - private enum Status { - FINISHED, LOOP - } - - private static int penaltyOf(String card) { - return switch (card) { - case "J" -> 1; - case "Q" -> 2; - case "K" -> 3; - case "A" -> 4; - default -> 0; - }; - } - - private static boolean isPaymentCard(String card) { - return penaltyOf(card) > 0; - } - - /** - * Return a snapshot of the current state - */ - private static String stateKey(Deque deckA, Deque deckB) { - StringBuilder sb = new StringBuilder(); - - for (String card : deckA) { - sb.append(isPaymentCard(card) ? card : "N"); - } - - sb.append('|'); - - for (String card : deckB) { - sb.append(isPaymentCard(card) ? card : "N"); - } - - return sb.toString(); - } - - private static Player otherPlayer(Player player) { - return player == Player.PLAYER_A ? Player.PLAYER_B : Player.PLAYER_A; - } - - private static Deque deckOf(Player player, Deque deckA, Deque deckB) { - return player == Player.PLAYER_A ? deckA : deckB; - } - - public void simulateGame(List playerA, List playerB) { - Deque deckA = new ArrayDeque<>(playerA); - Deque deckB = new ArrayDeque<>(playerB); - - int cardsPlayed = 0; - int tricksCount = 0; - Player current = Player.PLAYER_A; - - Set seenStates = new HashSet<>(); - - while (true) { - String key = stateKey(deckA, deckB); - // Key already exists, which means this is a loop - if (!seenStates.add(key)) { - finishGame(Status.LOOP, cardsPlayed, tricksCount); - return; - } - - // Otherwise, play next round - RoundResult result = playRound(deckA, deckB, current); - - cardsPlayed += result.pileSize(); - tricksCount++; - - // Check if someone wins and finish the game - if (hasWinner(deckA, deckB)) { - finishGame(Status.FINISHED, cardsPlayed, tricksCount); - return; - } - - // Otherwise, play next round - current = result.nextStarter(); - } - } - - private RoundResult playRound(Deque deckA, Deque deckB, Player startingPlayer) { - Deque pile = new ArrayDeque<>(); // cards played in this round - Player currentPlayer = startingPlayer; - int pendingPenalty = 0; - - while (true) { - Deque currentPlayerDeck = deckOf(currentPlayer, deckA, deckB); - Player opponent = otherPlayer(currentPlayer); - Deque opponentDeck = deckOf(opponent, deckA, deckB); - - // Current player deck is empty, opponent collects all pile, end this round - if (currentPlayerDeck.isEmpty()) { - opponentDeck.addAll(pile); - return new RoundResult(opponent, pile.size()); - } - - // Otherwise, current player plays 1 card, add to pile - String card = currentPlayerDeck.poll(); - pile.addLast(card); - - // Current player must pay off pending penalty - if (pendingPenalty > 0) { - // And player reveals a payment card - if (isPaymentCard(card)) { - // reset penalty based on new card, switch turn - pendingPenalty = penaltyOf(card); - currentPlayer = opponent; - } else { - // Otherwise, deduct penalty - pendingPenalty--; - // No pending penalty - if (pendingPenalty == 0) { - // Opponent collects all pile and win the round - deckOf(opponent, deckA, deckB).addAll(pile); - return new RoundResult(opponent, pile.size()); - } - } - } else { - // Normal gameplay, without pending penalty - // If player reveals a payment card, update penalty - if (isPaymentCard(card)) { - pendingPenalty = penaltyOf(card); - } - currentPlayer = opponent; - } - } - } - - private void finishGame(Status status, int cardsPlayed, int tricksCount) { - this.status = status; - this.cards = cardsPlayed; - this.tricks = tricksCount; - } - - private boolean hasWinner(Deque deckA, Deque deckB) { - return deckA.isEmpty() || deckB.isEmpty(); - } - - public String getStatus() { - return status != null ? status.name().toLowerCase() : ""; + void simulateGame(List playerA, List playerB) { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } - public int getCards() { - return cards; + String getStatus() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } - public int getTricks() { - return tricks; + int getCards() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } - /** - * Immutable round result - */ - private record RoundResult(Player nextStarter, int pileSize) { + int getTricks() { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } } \ No newline at end of file From a170168cd4dbde3ff0e2118acc6016b7ff7a5c5e Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Thu, 16 Apr 2026 14:38:48 -0600 Subject: [PATCH 16/24] Move to .meta/src/reference/java/ --- .../practice/camicia/.meta/src/{ => reference/java}/Camicia.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/practice/camicia/.meta/src/{ => reference/java}/Camicia.java (100%) diff --git a/exercises/practice/camicia/.meta/src/Camicia.java b/exercises/practice/camicia/.meta/src/reference/java/Camicia.java similarity index 100% rename from exercises/practice/camicia/.meta/src/Camicia.java rename to exercises/practice/camicia/.meta/src/reference/java/Camicia.java From b6257d3c0bc8e6caf440182ecff3fd8df833e9bb Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Fri, 17 Apr 2026 09:49:49 -0600 Subject: [PATCH 17/24] Config Camicia exercise --- config.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/config.json b/config.json index 92dfd05b1..d85ddef5f 100644 --- a/config.json +++ b/config.json @@ -1275,6 +1275,19 @@ ], "difficulty": 6 }, + { + "slug": "camicia", + "name": "Camicia", + "uuid": "b4f7c3b0-6d3c-45e2-a328-05e09c7467f4", + "practices": [], + "prerequisites": [ + "strings", + "for-loops", + "arrays", + "if-else-statements" + ], + "difficulty": 6 + }, { "slug": "etl", "name": "ETL", From 937484f8eda628ece5afe249ae0e96e249260e69 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Mon, 20 Apr 2026 09:06:35 -0600 Subject: [PATCH 18/24] End file with a new line --- .../practice/camicia/.meta/src/reference/java/Camicia.java | 2 +- exercises/practice/camicia/src/main/java/Camicia.java | 2 +- exercises/practice/camicia/src/test/java/CamiciaTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/practice/camicia/.meta/src/reference/java/Camicia.java b/exercises/practice/camicia/.meta/src/reference/java/Camicia.java index 6b585989b..235ef89fb 100644 --- a/exercises/practice/camicia/.meta/src/reference/java/Camicia.java +++ b/exercises/practice/camicia/.meta/src/reference/java/Camicia.java @@ -169,4 +169,4 @@ public int getTricks() { */ private record RoundResult(Player nextStarter, int pileSize) { } -} \ No newline at end of file +} diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java index 7818944a8..16fc0db9f 100644 --- a/exercises/practice/camicia/src/main/java/Camicia.java +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -17,4 +17,4 @@ int getCards() { int getTricks() { throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } -} \ No newline at end of file +} diff --git a/exercises/practice/camicia/src/test/java/CamiciaTest.java b/exercises/practice/camicia/src/test/java/CamiciaTest.java index f5da6eac1..bcdc7ad3d 100644 --- a/exercises/practice/camicia/src/test/java/CamiciaTest.java +++ b/exercises/practice/camicia/src/test/java/CamiciaTest.java @@ -515,4 +515,4 @@ public void casella2024FirstInfiniteGameFound() { assertEquals(474, camicia.getCards()); assertEquals(66, camicia.getTricks()); } -} \ No newline at end of file +} From cd1b2662ca3373da10a5221181006a48531a1aaa Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Mon, 20 Apr 2026 09:10:09 -0600 Subject: [PATCH 19/24] Update author --- exercises/practice/camicia/.meta/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/practice/camicia/.meta/config.json b/exercises/practice/camicia/.meta/config.json index b8d1c3386..79a1b9a01 100644 --- a/exercises/practice/camicia/.meta/config.json +++ b/exercises/practice/camicia/.meta/config.json @@ -1,8 +1,8 @@ { - "authors": [], - "contributors": [ + "authors": [ "thibault2705" ], + "contributors": [], "files": { "solution": [ "src/main/java/Camicia.java" From 59e777bf342e3f27a1a2da283d25d9a3ccc315c2 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Mon, 20 Apr 2026 09:29:12 -0600 Subject: [PATCH 20/24] Make simulateGame static and return result record --- .../camicia/src/main/java/Camicia.java | 13 +-------- .../camicia/src/main/java/CamiciaResult.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 exercises/practice/camicia/src/main/java/CamiciaResult.java diff --git a/exercises/practice/camicia/src/main/java/Camicia.java b/exercises/practice/camicia/src/main/java/Camicia.java index 16fc0db9f..33688ace3 100644 --- a/exercises/practice/camicia/src/main/java/Camicia.java +++ b/exercises/practice/camicia/src/main/java/Camicia.java @@ -2,19 +2,8 @@ public class Camicia { - void simulateGame(List playerA, List playerB) { + static CamiciaResult simulateGame(List playerA, List playerB) { throw new UnsupportedOperationException("Delete this statement and write your own implementation."); } - String getStatus() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); - } - - int getCards() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); - } - - int getTricks() { - throw new UnsupportedOperationException("Delete this statement and write your own implementation."); - } } diff --git a/exercises/practice/camicia/src/main/java/CamiciaResult.java b/exercises/practice/camicia/src/main/java/CamiciaResult.java new file mode 100644 index 000000000..da63ba362 --- /dev/null +++ b/exercises/practice/camicia/src/main/java/CamiciaResult.java @@ -0,0 +1,28 @@ +/** + * {@link CamiciaResult} shows the result of a Camicia game + */ +public record CamiciaResult(String status, int cards, int tricks) { + + /** + * @return the game status + */ + public String status() { + return status; + } + + /** + * @return the total played cards + */ + public int cards() { + return cards; + } + + /** + * @return the total tricks used + */ + public int tricks() { + return tricks; + } +} + + From b99d44b3bb97201023326ab082df83eb858ff4d3 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Mon, 20 Apr 2026 09:35:48 -0600 Subject: [PATCH 21/24] Update solution and disable more tests --- .../.meta/src/reference/java/Camicia.java | 30 +-- .../src/reference/java/CamiciaResult.java | 28 +++ .../camicia/src/test/java/CamiciaTest.java | 234 +++++++++--------- 3 files changed, 150 insertions(+), 142 deletions(-) create mode 100644 exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java diff --git a/exercises/practice/camicia/.meta/src/reference/java/Camicia.java b/exercises/practice/camicia/.meta/src/reference/java/Camicia.java index 235ef89fb..610558665 100644 --- a/exercises/practice/camicia/.meta/src/reference/java/Camicia.java +++ b/exercises/practice/camicia/.meta/src/reference/java/Camicia.java @@ -59,7 +59,7 @@ private static Deque deckOf(Player player, Deque deckA, Deque playerA, List playerB) { + public static CamiciaResult simulateGame(List playerA, List playerB) { Deque deckA = new ArrayDeque<>(playerA); Deque deckB = new ArrayDeque<>(playerB); @@ -73,8 +73,7 @@ public void simulateGame(List playerA, List playerB) { String key = stateKey(deckA, deckB); // Key already exists, which means this is a loop if (!seenStates.add(key)) { - finishGame(Status.LOOP, cardsPlayed, tricksCount); - return; + return finishGame(Status.LOOP, cardsPlayed, tricksCount); } // Otherwise, play next round @@ -85,8 +84,7 @@ public void simulateGame(List playerA, List playerB) { // Check if someone wins and finish the game if (hasWinner(deckA, deckB)) { - finishGame(Status.FINISHED, cardsPlayed, tricksCount); - return; + return finishGame(Status.FINISHED, cardsPlayed, tricksCount); } // Otherwise, play next round @@ -94,7 +92,7 @@ public void simulateGame(List playerA, List playerB) { } } - private RoundResult playRound(Deque deckA, Deque deckB, Player startingPlayer) { + private static RoundResult playRound(Deque deckA, Deque deckB, Player startingPlayer) { Deque pile = new ArrayDeque<>(); // cards played in this round Player currentPlayer = startingPlayer; int pendingPenalty = 0; @@ -142,28 +140,14 @@ private RoundResult playRound(Deque deckA, Deque deckB, Player s } } - private void finishGame(Status status, int cardsPlayed, int tricksCount) { - this.status = status; - this.cards = cardsPlayed; - this.tricks = tricksCount; + private static CamiciaResult finishGame(Status status, int cardsPlayed, int tricksCount) { + return new CamiciaResult(status == null ? null : status.toString().toLowerCase(), cardsPlayed, tricksCount); } - private boolean hasWinner(Deque deckA, Deque deckB) { + private static boolean hasWinner(Deque deckA, Deque deckB) { return deckA.isEmpty() || deckB.isEmpty(); } - public String getStatus() { - return status != null ? status.name().toLowerCase() : ""; - } - - public int getCards() { - return cards; - } - - public int getTricks() { - return tricks; - } - /** * Immutable round result */ diff --git a/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java b/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java new file mode 100644 index 000000000..da63ba362 --- /dev/null +++ b/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java @@ -0,0 +1,28 @@ +/** + * {@link CamiciaResult} shows the result of a Camicia game + */ +public record CamiciaResult(String status, int cards, int tricks) { + + /** + * @return the game status + */ + public String status() { + return status; + } + + /** + * @return the total played cards + */ + public int cards() { + return cards; + } + + /** + * @return the total tricks used + */ + public int tricks() { + return tricks; + } +} + + diff --git a/exercises/practice/camicia/src/test/java/CamiciaTest.java b/exercises/practice/camicia/src/test/java/CamiciaTest.java index bcdc7ad3d..f4f2b8e85 100644 --- a/exercises/practice/camicia/src/test/java/CamiciaTest.java +++ b/exercises/practice/camicia/src/test/java/CamiciaTest.java @@ -10,63 +10,59 @@ public class CamiciaTest { private static final String FINISHED = "finished"; private static final String LOOP = "loop"; - private Camicia simulateGame(List playerA, List playerB) { - Camicia camicia = new Camicia(); - camicia.simulateGame(playerA, playerB); - - return camicia; - } - @Test @DisplayName("two cards, one trick") public void twoCardsOneTrick() { List playerA = List.of("2"); List playerB = List.of("3"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(2, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(2, result.cards()); + assertEquals(1, result.tricks()); } + @Disabled("Remove to run test") @Test @DisplayName("three cards, one trick") public void threeCardsOneTrick() { List playerA = List.of("2", "4"); List playerB = List.of("3"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(3, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(3, result.cards()); + assertEquals(1, result.tricks()); } + @Disabled("Remove to run test") @Test @DisplayName("four cards, one trick") public void fourCardsOneTrick() { List playerA = List.of("2", "4"); List playerB = List.of("3", "5", "6"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(4, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(4, result.cards()); + assertEquals(1, result.tricks()); } + @Disabled("Remove to run test") @Test @DisplayName("the ace reigns supreme") public void theAceReignsSupreme() { List playerA = List.of("2", "A"); List playerB = List.of("3", "4", "5", "6", "7"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -76,11 +72,11 @@ public void theKingBeatsAce() { List playerA = List.of("2", "A"); List playerB = List.of("3", "4", "5", "6", "K"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -90,11 +86,11 @@ public void theQueenSeducesTheKing() { List playerA = List.of("2", "A", "7", "8", "Q"); List playerB = List.of("3", "4", "5", "6", "K"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(10, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(10, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -104,11 +100,11 @@ public void theJackBetraysTheQueen() { List playerA = List.of("2", "A", "7", "8", "Q"); List playerB = List.of("3", "4", "5", "6", "K", "9", "J"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(12, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(12, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -118,11 +114,11 @@ public void theTenJustWantsToPutOnAShow() { List playerA = List.of("2", "A", "7", "8", "Q", "10"); List playerB = List.of("3", "4", "5", "6", "K", "9", "J"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(13, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(13, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -132,11 +128,11 @@ public void simpleLoopWithDecksOfThreeCards() { List playerA = List.of("J", "2", "3"); List playerB = List.of("4", "J", "5"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(LOOP, camicia.getStatus()); - assertEquals(8, camicia.getCards()); - assertEquals(3, camicia.getTricks()); + assertEquals(LOOP, result.status()); + assertEquals(8, result.cards()); + assertEquals(3, result.tricks()); } @Disabled("Remove to run test") @@ -167,11 +163,11 @@ public void theStoryIsStartingToGetAbitComplicated() { "Q", "Q", "6", "J", "K", "4", "7", "J", "J", "9", "9", "A", "Q", "Q", "K", "A", "6", "5", "K" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(361, camicia.getCards()); - assertEquals(1, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(361, result.cards()); + assertEquals(1, result.tricks()); } @Disabled("Remove to run test") @@ -181,11 +177,11 @@ public void twoTricks() { List playerA = List.of("J"); List playerB = List.of("3", "J"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(5, camicia.getCards()); - assertEquals(2, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(5, result.cards()); + assertEquals(2, result.tricks()); } @Disabled("Remove to run test") @@ -195,11 +191,11 @@ public void moreTricks() { List playerA = List.of("J", "2", "4"); List playerB = List.of("3", "J", "A"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(12, camicia.getCards()); - assertEquals(4, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(12, result.cards()); + assertEquals(4, result.tricks()); } @Disabled("Remove to run test") @@ -209,11 +205,11 @@ public void simpleLoopWithDecksOfFourCards() { List playerA = List.of("2", "3", "J", "6"); List playerB = List.of("K", "5", "J", "7"); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(LOOP, camicia.getStatus()); - assertEquals(16, camicia.getCards()); - assertEquals(4, camicia.getTricks()); + assertEquals(LOOP, result.status()); + assertEquals(16, result.cards()); + assertEquals(4, result.tricks()); } @Disabled("Remove to run test") @@ -229,11 +225,11 @@ public void easyCardCombination() { "Q", "Q", "J", "J", "J", "J" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(40, camicia.getCards()); - assertEquals(4, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(40, result.cards()); + assertEquals(4, result.tricks()); } @Disabled("Remove to run test") @@ -249,11 +245,11 @@ public void easyCardCombinationInvertedDecks() { "9", "8", "5", "9", "3", "4", "9" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(40, camicia.getCards()); - assertEquals(4, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(40, result.cards()); + assertEquals(4, result.tricks()); } @Disabled("Remove to run test") @@ -269,11 +265,11 @@ public void mirroredDecks() { "9", "10", "6", "8", "3", "8", "5" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(59, camicia.getCards()); - assertEquals(4, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(59, result.cards()); + assertEquals(4, result.tricks()); } @Disabled("Remove to run test") @@ -289,11 +285,11 @@ public void oppositeDecks() { "5", "K", "6", "A", "2", "A", "5" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(151, camicia.getCards()); - assertEquals(21, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(151, result.cards()); + assertEquals(21, result.tricks()); } @Disabled("Remove to run test") @@ -309,11 +305,11 @@ public void randomDecksOne() { "A", "3", "Q", "5", "J", "2", "6" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(542, camicia.getCards()); - assertEquals(76, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(542, result.cards()); + assertEquals(76, result.tricks()); } @Disabled("Remove to run test") @@ -329,11 +325,11 @@ public void randomDecksTwo() { "Q", "4", "10", "4", "7", "4", "6" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(327, camicia.getCards()); - assertEquals(42, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(327, result.cards()); + assertEquals(42, result.tricks()); } @Disabled("Remove to run test") @@ -349,11 +345,11 @@ public void kleber1999() { "10", "3", "K", "9", "6", "8", "Q" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(5790, camicia.getCards()); - assertEquals(805, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(5790, result.cards()); + assertEquals(805, result.tricks()); } @Disabled("Remove to run test") @@ -369,11 +365,11 @@ public void collins2006() { "7", "Q", "J", "3", "3", "K", "9" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(6913, camicia.getCards()); - assertEquals(960, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(6913, result.cards()); + assertEquals(960, result.tricks()); } @Disabled("Remove to run test") @@ -389,11 +385,11 @@ public void mannAndWu2007() { "6", "8", "7", "A", "Q", "5", "2" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7157, camicia.getCards()); - assertEquals(1007, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7157, result.cards()); + assertEquals(1007, result.tricks()); } @Disabled("Remove to run test") @@ -409,11 +405,11 @@ public void nessler2012() { "7", "8", "J", "A", "7", "8", "7" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7207, camicia.getCards()); - assertEquals(1015, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7207, result.cards()); + assertEquals(1015, result.tricks()); } @Disabled("Remove to run test") @@ -429,11 +425,11 @@ public void anderson2013() { "A", "6", "8", "Q", "K", "K", "2" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7225, camicia.getCards()); - assertEquals(1016, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7225, result.cards()); + assertEquals(1016, result.tricks()); } @Disabled("Remove to run test") @@ -449,11 +445,11 @@ public void rucklidge2014() { "Q", "10", "K", "6", "J", "J", "K" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7959, camicia.getCards()); - assertEquals(1122, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7959, result.cards()); + assertEquals(1122, result.tricks()); } @Disabled("Remove to run test") @@ -469,11 +465,11 @@ public void nessler2021() { "K", "2", "Q", "10", "Q", "10", "Q" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(7972, camicia.getCards()); - assertEquals(1106, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(7972, result.cards()); + assertEquals(1106, result.tricks()); } @Disabled("Remove to run test") @@ -489,11 +485,11 @@ public void nessler2022() { "7", "8", "2", "A", "7", "4", "6" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(FINISHED, camicia.getStatus()); - assertEquals(8344, camicia.getCards()); - assertEquals(1164, camicia.getTricks()); + assertEquals(FINISHED, result.status()); + assertEquals(8344, result.cards()); + assertEquals(1164, result.tricks()); } @Disabled("Remove to run test") @@ -509,10 +505,10 @@ public void casella2024FirstInfiniteGameFound() { "5", "9", "8", "9", "9", "K", "A" ); - Camicia camicia = simulateGame(playerA, playerB); + CamiciaResult result = Camicia.simulateGame(playerA, playerB); - assertEquals(LOOP, camicia.getStatus()); - assertEquals(474, camicia.getCards()); - assertEquals(66, camicia.getTricks()); + assertEquals(LOOP, result.status()); + assertEquals(474, result.cards()); + assertEquals(66, result.tricks()); } } From 70ecce535704db3f156f4e683e7c6c932f84aa76 Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Mon, 20 Apr 2026 09:41:13 -0600 Subject: [PATCH 22/24] Update gradle version --- .../practice/camicia/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.properties b/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.properties index 2deab89d5..8d9046d01 100644 --- a/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.properties +++ b/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From bc0739a29371d307676af501f46bc767e8754f6e Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Tue, 21 Apr 2026 09:55:07 -0600 Subject: [PATCH 23/24] Update gradle --- .../camicia/gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 46175 bytes exercises/practice/camicia/gradlew | 15 +++++++-------- exercises/practice/camicia/gradlew.bat | 5 +++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.jar b/exercises/practice/camicia/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 38026 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 diff --git a/exercises/practice/camicia/gradlew b/exercises/practice/camicia/gradlew index 1aa94a426..adff685a0 100755 --- a/exercises/practice/camicia/gradlew +++ b/exercises/practice/camicia/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -170,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -203,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/exercises/practice/camicia/gradlew.bat b/exercises/practice/camicia/gradlew.bat index 25da30dbd..c4bdd3ab8 100644 --- a/exercises/practice/camicia/gradlew.bat +++ b/exercises/practice/camicia/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 93c664aeaafca01da414243f9c0078a32e1e9d4c Mon Sep 17 00:00:00 2001 From: Thibault Phan Date: Tue, 21 Apr 2026 10:03:30 -0600 Subject: [PATCH 24/24] Update result record, config, instructions and tests --- .../practice/camicia/.docs/instructions.md | 2 +- .../practice/camicia/.docs/introduction.md | 24 +++++ exercises/practice/camicia/.meta/config.json | 6 +- .../src/reference/java/CamiciaResult.java | 22 ----- exercises/practice/camicia/.meta/tests.toml | 94 +++++++++++++++++++ .../camicia/src/main/java/CamiciaResult.java | 22 ----- 6 files changed, 123 insertions(+), 47 deletions(-) create mode 100644 exercises/practice/camicia/.docs/introduction.md create mode 100644 exercises/practice/camicia/.meta/tests.toml diff --git a/exercises/practice/camicia/.docs/instructions.md b/exercises/practice/camicia/.docs/instructions.md index 9da5c14db..db62fcef2 100644 --- a/exercises/practice/camicia/.docs/instructions.md +++ b/exercises/practice/camicia/.docs/instructions.md @@ -1,6 +1,6 @@ # Instructions -In this exercise, you will simulate a game very similar to the classic card game **CamiciaGame**. +In this exercise, you will simulate a game very similar to the classic card game **Camicia**. Your program will receive the initial configuration of two players' decks and must simulate the game until it ends (or detect that it will never end). ## Rules diff --git a/exercises/practice/camicia/.docs/introduction.md b/exercises/practice/camicia/.docs/introduction.md new file mode 100644 index 000000000..761d8a82c --- /dev/null +++ b/exercises/practice/camicia/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +One rainy afternoon, you sit at the kitchen table playing cards with your grandmother. +The game is her take on [Camicia][bmn]. + +At first it feels like just another friendly match: cards slapped down, laughter across the table, the occasional victorious grin from Nonna. +But as the game stretches on, something strange happens. +The same cards keep cycling back. +You play card after card, yet the end never seems to come. + +You start to wonder. +_Will this game ever finish? +Or could we keep playing forever?_ + +Later, driven by curiosity, you search online and to your surprise you discover that what happened wasn't just bad luck. +You and your grandmother may have stumbled upon one of the longest possible sequences! +Suddenly, you're hooked. +What began as a casual game has turned into a quest: _how long can such a game really last?_ +_Can you find a sequence even longer than the one you played at the kitchen table?_ +_Perhaps even long enough to set a new world record?_ + +And so, armed with nothing but a deck of cards and some algorithmic ingenuity, you decide to investigate... + +[bmn]: https://en.wikipedia.org/wiki/Beggar-my-neighbour diff --git a/exercises/practice/camicia/.meta/config.json b/exercises/practice/camicia/.meta/config.json index 79a1b9a01..e352afa6c 100644 --- a/exercises/practice/camicia/.meta/config.json +++ b/exercises/practice/camicia/.meta/config.json @@ -5,13 +5,15 @@ "contributors": [], "files": { "solution": [ - "src/main/java/Camicia.java" + "src/main/java/Camicia.java", + "src/main/java/CamiciaResult.java" ], "test": [ "src/test/java/CamiciaTest.java" ], "example": [ - ".meta/src/reference/java/Camicia.java" + ".meta/src/reference/java/Camicia.java", + ".meta/src/reference/java/CamiciaResult.java" ], "invalidator": [ "build.gradle" diff --git a/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java b/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java index da63ba362..d064dc3ba 100644 --- a/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java +++ b/exercises/practice/camicia/.meta/src/reference/java/CamiciaResult.java @@ -3,26 +3,4 @@ */ public record CamiciaResult(String status, int cards, int tricks) { - /** - * @return the game status - */ - public String status() { - return status; - } - - /** - * @return the total played cards - */ - public int cards() { - return cards; - } - - /** - * @return the total tricks used - */ - public int tricks() { - return tricks; - } } - - diff --git a/exercises/practice/camicia/.meta/tests.toml b/exercises/practice/camicia/.meta/tests.toml new file mode 100644 index 000000000..18d3fdd99 --- /dev/null +++ b/exercises/practice/camicia/.meta/tests.toml @@ -0,0 +1,94 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[0b7f737c-3ecd-4a55-b34d-e65c62a85c28] +description = "two cards, one trick" + +[27c19d75-53a5-48e5-b33b-232c3884d4f3] +description = "three cards, one trick" + +[9b02dd49-efaf-4b71-adca-a05c18a7c5b0] +description = "four cards, one trick" + +[fa3f4479-466a-4734-a001-ab79bfe27260] +description = "the ace reigns supreme" + +[07629689-f589-4f54-a6d1-8ce22776ce72] +description = "the king beats ace" + +[54d4a1c5-76fb-4d1e-8358-0e0296ac0601] +description = "the queen seduces the king" + +[c875500c-ff3d-47a4-bd1e-b60b90da80aa] +description = "the jack betrays the queen" + +[436875da-96ca-4149-be22-0b78173b8125] +description = "the 10 just wants to put on a show" + +[5be39bb6-1b34-4ce6-a1cd-0fcc142bb272] +description = "simple loop with decks of 3 cards" + +[2795dc21-0a2a-4c38-87c2-5a42e1ff15eb] +description = "the story is starting to get a bit complicated" + +[6999dfac-3fdc-41e2-b64b-38f4be228712] +description = "two tricks" + +[83dcd4f3-e089-4d54-855a-73f5346543a3] +description = "more tricks" + +[3107985a-f43e-486a-9ce8-db51547a9941] +description = "simple loop with decks of 4 cards" + +[dca32c31-11ed-49f6-b078-79ab912c1f7b] +description = "easy card combination" + +[1f8488d0-48d3-45ae-b819-59cedad0a5f4] +description = "easy card combination, inverted decks" + +[98878d35-623a-4d05-b81a-7bdc569eb88d] +description = "mirrored decks" + +[3e0ba597-ca10-484b-87a3-31a7df7d6da3] +description = "opposite decks" + +[92334ddb-aaa7-47fa-ab36-e928a8a6a67c] +description = "random decks #1" + +[30477523-9651-4860-84a3-e1ac461bb7fa] +description = "random decks #2" + +[20967de8-9e94-4e0e-9010-14bc1c157432] +description = "Kleber 1999" + +[9f2fdfe8-27f3-4323-816d-6bce98a9c6f7] +description = "Collins 2006" + +[c90b6f8d-7013-49f3-b5cb-14ea006cca1d] +description = "Mann and Wu 2007" + +[a3f1fbc5-1d0b-499a-92a5-22932dfc6bc8] +description = "Nessler 2012" + +[9cefb1ba-e6d1-4ab7-9d8f-76d8e0976d5f] +description = "Anderson 2013" + +[d37c0318-5be6-48d0-ab72-a7aaaff86179] +description = "Rucklidge 2014" + +[4305e479-ba87-432f-8a29-cd2bd75d2f05] +description = "Nessler 2021" + +[252f5cc3-b86d-4251-87ce-f920b7a6a559] +description = "Nessler 2022" + +[b9efcfa4-842f-4542-8112-8389c714d958] +description = "Casella 2024, first infinite game found" diff --git a/exercises/practice/camicia/src/main/java/CamiciaResult.java b/exercises/practice/camicia/src/main/java/CamiciaResult.java index da63ba362..d064dc3ba 100644 --- a/exercises/practice/camicia/src/main/java/CamiciaResult.java +++ b/exercises/practice/camicia/src/main/java/CamiciaResult.java @@ -3,26 +3,4 @@ */ public record CamiciaResult(String status, int cards, int tricks) { - /** - * @return the game status - */ - public String status() { - return status; - } - - /** - * @return the total played cards - */ - public int cards() { - return cards; - } - - /** - * @return the total tricks used - */ - public int tricks() { - return tricks; - } } - -