From 0435ad7c38f0faca6c985c69cbfea9b611026e56 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Tue, 23 Jun 2026 19:58:11 -0600 Subject: [PATCH] feat: add Pai Gow Poker game with AI opponents and hand-setting UI - Implement complete Pai Gow Poker game using Phaser with drag-and-drop hand-setting panel for splitting 7 cards into 5-card high and 2-card low - Add pure logic module (PaiGowPokerLogic.js) with full hand evaluation supporting Joker substitution, 9 hand ranks including Five Aces, foul detection, house way splitting, and commission-based resolution - Add AI bet sizing module (PaiGowPokerAI.js) for opponent betting - Register game in server registry (casino category, 1-6 players) - Register scene in main.js and GameRoomScene slug dispatch - Add comprehensive test suite (verifyPaiGowPoker.js) covering deck, evaluation, comparison, foul detection, house way, state management, chip math (wins/losses/pushes/fouls/copy rule), and AI betting - Update StrategoGame to trigger portrait emotions on piece captures - Update game-icons sprite sheet --- public/assets/images/game-icons.png | Bin 276490 -> 279831 bytes public/assets/images/game-icons.psd | Bin 718418 -> 726182 bytes public/src/games/paigow/PaiGowPokerAI.js | 9 + public/src/games/paigow/PaiGowPokerGame.js | 1317 +++++++++++++++++++ public/src/games/paigow/PaiGowPokerLogic.js | 504 +++++++ public/src/games/stratego/StrategoGame.js | 17 + public/src/main.js | 2 + public/src/scenes/GameRoomScene.js | 2 +- server/games/registry.js | 1 + verifyPaiGowPoker.js | 486 +++++++ 10 files changed, 2337 insertions(+), 1 deletion(-) create mode 100644 public/src/games/paigow/PaiGowPokerAI.js create mode 100644 public/src/games/paigow/PaiGowPokerGame.js create mode 100644 public/src/games/paigow/PaiGowPokerLogic.js create mode 100644 verifyPaiGowPoker.js diff --git a/public/assets/images/game-icons.png b/public/assets/images/game-icons.png index b075b7061dde0cea8b02da79d34c16f1e1fbfc7c..04c9e701dc3fd71dca0cf678e6505442093951b6 100644 GIT binary patch delta 65235 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 diff --git a/public/assets/images/game-icons.psd b/public/assets/images/game-icons.psd index ad59c9243e2e6a003df12b2f63276b4f3fea55ac..91ea068dcc0a5cbd8695d8b29431f4d3403bd467 100644 GIT binary patch delta 13642 zcmbuE2Uru?+JI*eB*c!rAgG`q_O2_|wSXNJ3)Z!Fv5R69MUdV@@0}1JkW4y(gj7O8 zNJ1b1q$?nZ^kVW)V0Z7m``mT?pX)ps!XqD=)xf!brg|I-_-KS~#&lXDm(fT)d|Ga?SL=jGp31veBO zlop|_Itzqr9UrG#)43#zc z-rbO}D(Le4=ZoYB8}}2?Gr}3Gbq1$xedC_2*$`QFSB<$iw7=4Hh3itebb9EHDM`xe z@vjk|TFt?d-ezpwA(VwxiT<(psq3e^mc?)Q%DIZae{?nWpw03%#{x4he{%i>2*`YR zYTAh>#AFldz=_!bx2`rGMvqfE+gfe!iS>Q*Xj8`Y!v1klowtKt1^jlC+hr%uO8(G2 z_WrsP@rr}*^KK@e>Wm)Mxc>Rw`JYRaT_ly`L&=3NYA6RYbGY4huT<22&t^TAgFV$Pp;TwOK^ z473O~K5dJ~q}r=v7GW1S%6qf6SZ)`@oHi>jO81=6Y47Pw@UIzsVceAGj;){k<)qz= zWj*_y@Uzn~giDFV^K2ZfP*V*bf2S{=hCfs3A8dH)mD2C&jwy7r&U;c!pOPE8v}uL< z_AY8vrTAfGYZ}9qweVa%L-fS%2FtudJlh4NA5HErV^bxK5ul$zSs>$wObcOU0|_8;qawRss0r z8oh0EG-;0O+@Jv{gVROFclv+*bfifJmFC^!o%#y-Eqm%=RxZGK5-x3?q_fX`lnlfk zoVRb(o;P#ruG!44g6vvXFAI8vdMF|Ny8jx|8HuEKE%D#*X?)iXO7+h3zsUT@jLlEG4GfyjTz7OAN}5^Hg@G1@3oTBXOv~gi5|yzD{W72t0z>nIv5*0&iLfl z(YmNck!ZZ7dey^L|A>gd`?jl8g7rE5ySG@3=B5Uhx9gXzEuaxN-+!Be*!vN6@b!X@ zcJ6VHt)hn7(z?QF4?4%MnwILlF+mU2AU5(V(ExLmRwo{pf4wVVS$a-!!)-l!%Re#w zRoxBao4dQ5M0tfzu+O7r&R+JxWglh7*@1n#D}G}zxP5`&>`@tI{_h&j z5SMVy3{0<1!OF(ZlH9mhm)_Rf^yv{QYYzMF5yO3K)7@56-zA=r6^i%R%${AgM+2~f zuKl(jkuh2lTpNGQeaDVHz2Yh9H=a4$MxB4ShSci0)l@zAoM5xdBmTF|(O<%9O2@9| z?Y#{czQ!9v+f5!>9(w!kwChbN#V9eUgsg!3+&h)ZUxEJUH7kdJ#)zSb2Xe6}^!(ZVb3;B4VD| z<#zl6BfG#LQ5iFW zY6za-*cfjT%Z?vh8!)Fl#NnFg?x(FOb!{mcKv1rC^Q1}2qPjhME^g8_x<=rZnI}#s zJwE=+=+<)dmYHwuv*oT!U+4yUdA0OlYCpB~&XKE&)?zPwn0G|wo4C&V(CAsW zTMgGdpSR~yCY$b9ly~3f_A%4^SEg=d>zzHarZgXOiG9P{s%se3WAJ@ZCs}YVl~PaK zdag13)=f98RdC;zi0OG#E3dL$ z+HG}-AK+bWX6byyf^(TLaqDO2MBN0RyE0njlbcURkEGpM}^sf-SZ52Qzx96JZtd+9bD8tno>Zp)*aw>a52pL+i)9(t(;*tPgZNIPmmGx_kL?)Bvr-reo(eL9(uE3-H7 zHm~)ZL&^JM>q%Dc&s)%89PnUw(QMD5=OG7+_B9_J^Dw{~fe`C$GI0`=@qh7wzLwZN;{Nf549Cf$F3luFEPTXX4z3<4v zTlgeQ5@a_xM))VB+*!2qJ9*1sPs;4z6HniGRG{X3xO%36I{WI;%q6-pfxg@8a=4K% z!Roxa_&Sg7ibg?Sh7!3F(-AVMj(^Ac*p*e2S!;6Be~ldH6yrTOO4W7a@W~pH>5KK~ z(5Gg`t`5hZ+Aj53mu$Gr(qYq{-c6@kde-(v<=ymoe8I}%9d~J`L(rzf&w55hjw&M` ze6uyV<2Z`yD2hD2T97C*<)1-&>zsaLWMR3?q9I|C|F*$rlVK7(aNLU->~kljHPmlh z7k>-pQo%(xdE+scl*(zJZ3>RY>D!oDwVyuUbo|b&7t7xT9jRPWGcc|BqFtCG^<>1k z^{3e951xN`#p?-_JPG~j^5L0=r|nlx5!;14^oFWc2jYReIjqNmq{+{2EYg+BLdM-*Ikz z)aP^0_)F&Q`nIaJ8beGhR6caGEw{C?nP6u4%s=y<*UOthlG9eGb<@M=hNJc-vmwH( zSIL>C4cC24R?na9cgzTU1yxvWA!MP9q6d%b7pu=aL}W3K9HLsIDt1qYH1-Df9b3dToFvIScOHMvcBQw6kIU+6vK)tgBfaf^Yt*)2G#$Ee_1p z1>Rv=Z!8EsY~x-0{>|(Rl%wDY=NsmRN5aNnW&Kny*AN4T#0{G^=|&oL$1D0V0m5fJ zNV&b|^OcK9ENYN`sNWqMAh2S`!OAfjK%8;U-o*FST2#lCWFrl*dsn2#hr=0=!SXXs zQ>S!6$FSCA7fcNwfqh0&V$^95fx`OY63ok?$&)ZWoLb&*XTwV7p*Rz3H-xy^%(-Jf zH;gczGnqAH%yGmVuFm-S{g;>RMs;@KlOIOiZDaCwD`UY|u7kvAya~V$(DYx&gGKSKA4K&*$wb8LUaBq+5`eWLO9jm$czQy(= ztD3t>zaCFI_I^RahJxtLPFpNCnIRu~4}2OY=bNoRb8QhczR_tP_RFs=akPfz%eG!| zPF=m~{@yF&h4y=2>aD9zdw$=1Ot}V_wLk+z7oJ=_^x?@NlT#?wuAmQyqb{~dslokO zl4qj|Z5H6BW{S=t+4slpW=1!B>u7m(>-n!C4(jadOA^_Jh6xEMB9Pbo0&o(&$h7XC zCh|IfTXt~U=l9CfTkXng6RtaN8PAq%G8sI6)U(a=+RU$oYn0WG^PprpGPATgF(NJU z)vFKfLxvOT<*`@Ju9vKCw70h2Jab1NosQgAKjBiw@$vb7hx~lgT2;UD9bcF=&fLEu zbS!Ic`Lc=DC6XQ6eldf!a8tm5VKnL}$$PnH^|BlH`iIhgJNt6uQny|6mS>(DazCW= zwEW-)HHREZ>T5TkC~7M1PMd+N{dN2PD;p9mSUOK0we|PBSmYG#n0n%chdWx7pZB@< zbDDIwW17c=D1%@Z@i$odfcLW?ZQoCd^WlG#v~?m>@{t_@WKcbSDwAvchTeAqAMPk z1GTL_AZtO(@$MZd--r*@H+dMk1C#hj*B1LyHbRz z9W#^L_U+DuOJ9>W6_EBI7F_3u zs3zXA`f6N#Wlw!reEr;MAv1_$%$j%p_Ob?LA=T$2faTWudz>(XEsCdQFYYW}C6U&~ zdtT^1zjoQeZ&$OkUXr5cr#;me~fsVqgvg*huygEoE1?$Xuk&<(Oo7#uI!Htx~r^cU1iCyqv= z(&m3K2xK}ac3OIO+&B<>$nkZDo@wfGr!=F4m?zt94^nIdSG^9+y}GloYjyf%`>@SU zzKahe-MYKg;rXXlGwh+I^c%HVK2BW+X#*NyDoPsZQH5JR_UuY_U=sGh*}35X&dP>D z){?1rHq!!FMlUD0OD*h}hh~)3bg>OeQzO^2`yP56c##~y!uDnIPgeHl{Kht0{Ved) zo%J)YL1qS9nwOcKnYc#3xva0!aq%ng0a4&_Cwl(T;HDV#BJKe8*CKQC7L>yw5##%J zJn}f|@%2>K!DY+JKYwX`^eVfXqE7djWZqk&+%nYDwR!__(ZJD(4>pgEAQn9?Tx?S+ z++}Y|blBmJXIY+oF(@T0-#YKX=3j306}{Uw?)}`yHv4vsI^B?HZr)wJZBSMbWbv8U z_H-kadhKPCQ75Tb11u0Q3&`}7>=$P5JcpjC4?Cechl-~0xmWCM&)68~cTf0DUny>V z=}u!^oOEd&^F{5O*gVIE#IrNZzgYxEklby9R?QDg1QIQ_S=by#+6LZ&AJCmL{41O;yx*S_F=G)3?hjziG(ohR0DA2+H29p>ndO)O(dl0U zypB!`Fe-YT6Utek8!+a`L=X{hp>%b?>?;!k(5%-vkwr;*;K6{bZ7w-H$w|-x0Ehsf zvl(tz2LFE@(AB^`1?Fmd)7`KAX%OD)X!ijO&R%eRz$D3hc#q`=!2|gEp&V}W)!TVe z*LhM9{^-D;QSe6>nkUucEI@(4WMCq^jRVF5W8iHpyo~`6z-V|w00w`SX-l=o41sCD zRA4$>3(*0Lo4IO>mpH^|&d!(zGeEEt=md0hocep!x&s|wiO6oC7tjR{T|GhWQ0rt` z8T0~u05~1rqSk4DKeHbg0CeV~!aF~yb-r`X4g!M!xV*Ja4eT8Ph5%5HQ>zA!3<2Na z8jKn>*n0dspa#H=)m7?Ikz)a16fpW>uS%^WUju-K!g4j(dl2v}Qv)g>8s3M1$A{pu zlJOwuQ=!&rGKMEeCr+gv)wf<-6+p5p)xd2vphf}U3|_SwOa|53u4b0OUDZwbt{s7S zdz~8W-!P;d*!A!AYQSN5jH9p(YA{D<5FS2gC~s1ORkH_xegItbwFkbCq3^x$P}cTq zuXNvFzk0OzhRv!YPOSrK@cZRHcs_tPgKC{ByU}n5Gjj*w{u6rPQgF2RyBdre-w)`3 zM}%s)(aF6)51=$N`!Plgx42$%<$0Skdez+zwt zu=GE+C4ePh0UucipRoWw&lo;?#_!99=ZQ*+#oWR?I*O6Ie3N$FCS9SIR+KBs$|_0; zTz-*ADlX72-*h*IK+4EcR8&?fl`3k1P*5x^5(x^PYS(ghUa>?f6Jg;a6-t!?Cn^$@ z7P0vyA|WSz^Z-0TNSshElPOijIjTyvYEmVeRLl{Hq>^Gz`9}qpPI)(kf@jwtk*BIC zulZQTBB@oAD^)VQP*^N2Dda=t^$oSv0y;r^M~v}FgQ`B3)l{i)IZAbV=(It5pIx0q)0=>C;8)iq_WE{9eqE2}CP!eT*wN^Xu&ds;(7eQl*|KD_dP zIju-2LuNrdLjvF{P?h9y3OVHL+=AM=#>R%)x`w*yN(CQ)XD*&8$fxi!b1G|U zYpd{?70U8*0V6#%kCH>Hs#ez_>uW#O)O}Pb%jJNPABC4sED%89)wOkXmAL$Jr9{Yp zFyUDlB<05{bq!KkRi>=^SOrg-2xXbc5ERgP#q_YEx|*6YM@UgF_2t+`V5Xmn*BP z;A@dsX5j?f!lEL4T%5eN;{I<*GDRsXB`Y$SuBcR1hFEVoe8Z;@rBqc{E0u}@%O@D9 zh$qM+g+I%$t_pvNmdYg56kJA*R9RImzJGkns^fQMl^<(rRHeo6owYuj$t&VBv#bM3 zRIC`HL?$MZlgJV!e8$HVhi%*L-6B@PE2=650CNBc&t~(Ae1lJ4D=OyaGD>Cncm|_X zrTVC z%ga@Y_u9wRD4dz+iSl%fEtT--rECH{t)i;>V{K(6^Lb>6xKu6IsVJjppXGUI%7=jH z#86I2F{_k{Cq(lrt3TG%R#&o7Y0^@WSX!w9?l;oF+uxVKlM7Zlp zWwE4GE-95MR1z%$j8|tDWa1KhMUo6jX(>N9JtVQbs#;ZA#4j$9mRE=mYuRA*n2yiD z`jO?iiJ5pZEWCd7oYeQ||(nb_QTViq;# zC^puDMn4K-7O)D4Vf}#qkz_&^S6a**X3C3fIvuwaW(q2|fQrf=hRRb+^#2T%7(9bT zr{QyPcqnbjx?!eV%pfuH^O*(g0xT^rpOJ@4*D_^-b2gQg9YpjmE6_X~B zmB{6#m{gvis3^`k1a6U6z`)UAsFleS0?IH{;s_YGl5$y@IKVN4$1WDpDcnj5Q-O~WT7m6gFuE0-%|B0(VyfS;j& zY$5@Lr^Kd96y*wON))${P6>=9;PWyg!X;%eip%9vS(%8-;qm~>S4j{)mqbYjkijQQ z5@Xox@DEOSLi(F?Zv|yCxk6DY6_rRN{6aR5Vi}b|ga{N$ng_E29@+aiCe7uUHz6zj z+*zu;Oe&ShipgokBC(LeL9t1eIcXFkkxI+;PgE$xQI}&23gWJ&Wkn{uPA!qjMe&j0 zkpXE!p{R(>;gT&g(#d3qM#TmNa1~;=7cp7*)WB?fYG{f;Qc{|D^Zad8I87uh7P5JT z8I})I(#b?BK0DkgTPjWP3?OABBxmPlC9ow@slfHoMcX^554;kIw1fxG2n-bro=74? zDQCP`CApDFw46*F5rbojrDbwymfOX1s1HQ#%cH1p7%FHCL?lN<-nl_9q(r3Ah*&&{ zP$-hh;aTALy>kslGsPuBA$yo9uG!?A-~i`~kxU*ohDL-Zo+y@lt(R5Y;lQMT0DuGE^ z*sSz84;U(kqSNAXX%KN3D)%E(lA|`lP*Je`X2_j#+*bsknq?60xxn zvGGaCVHV4Vp>irXDF>ICm7al#OH0YXM7=-_2P!YZl5?W{vq*&ObX;~qdK!&HfLVmO zH_Vi1Y!-=z^{3L(ld*)%C~|&29l~Z3vocUwQ6o@!9!;RpndHo18YMXsM~_RRGN`0H zDj|)?z~VFFt_?#aES{9lWJA={NIFEMQd9i!^gKE>3zwS5K*@NBY~ ziP1C&qKCZlAQQ;soLme+z$;=hgfy5vaG>HBAM(Bs#VcSlQ-i~)Ih6cdXAFs)o0^$H z5OCoYg@KiiH`3m|v%`|oliWyL_!cEcqiJ|DIp!^d$EBu)hYJeSLIY+2m(9u}V6;$q z9hsPvk`x?A;qiIQR39<{o8%INjm?Sm@L}@!Og5jxDdZJ0=p+(gdDSxkm5`hq8xhDT zgmISO0zpovucTrk-`G3m@C%vDLKcV3<_cK(RALP17N|~I7#|fGMB)~(8EDTO?B&Bx zG4X+?Po{9V3@V*oK+Y}T@Y&1)Lbzo{Kyq?oWNcJeGN&*P;}(>i{eD+SxO?dHV0wN& zB`GC6BMrxZ8%Gr|ND-D<>50j45m8?LVR`Jlguu|C5a(yHap4|l9EFmH^>pzGNrsq( z@Y{@z^S6A2O-_i4_6>4mMNKK5vLexAWM1mrHo_hsjXv_i%br>q{$%zqf@87icB9M}OBK)J1;zJ1xGL?i& z2?>b_ij2u7Qpx0}!%Xpr33YmM>(F^9H`O=%O>~$$7Glv0s1yP!HUW>#%E`^aL-E5< zaSng-;l=&^@!6QrFjSP6dvrD{FOS7w5Ms!Aq@2twO2!CO&;f5RIP80qiSZ3bKk)MQ z49bPF)2Pe>Jb_3e;>p>=fy%1Lu&W2RT*jol4vC2MeEr7dEuNH}MuA_`bQ+10wR;di z!I8@Ss5fu-9rD8lpj@0^J3hH|=3W|wfG6iOXk;2Gei$mDUXHg1$i@{~*B+c$yt&LRP2Y7o2dAxrPL*;N>W^!_RbjmPPt~q~jb6E#N<#7rwFlZPm z=Nuo^Lyf(9&%upX!Ka`v7zL(*IUo`I2z~_{z#dSeqpLGbXO7NHovAvL;BS+448b9| zyd7)=RUj3_fUZzTzh1lU#+%@C&~Lat9xkr}JHRHe7u0~?;hM9C>yOu&4u78t4*Xd^ zAIt(hAcp#n`o3T^m=5AV3fzAu_z4_lniQPl4+X{-yq>QKRAhV*y{l z8{S-i*MJic1|-4Xf`L%L3rK)Be;@|Hz~Y|?(BW^1KpH@SzmWkJKz5yIFdCX@pf55t zRBFccc6BzC)%NwZ$!mMnY7X>qss2T9TBT;v_iE|Cgicr@uN>k*JC^G|0_W6drmI_; zzn1(}>y%#y1Q4`B9|aoMYG(DT{=3|XYkGvx`c?X_;DUM$vg>2nzYK5UUktCPQ3U0! z*7pX@8Z-uN!XH~+vlu$KR^K07*r*vZMEwWX`yz&F*69;L^Cr!LUim*6Uv)9pvK@ErX6`*Oa#(0SLBg?G%E`sQ` z@aoU+g@?}ld)KV!ErtS)!FQKQk7jl!3->p|sq7R&m+bVp;M{J_%+G&nXMTBedxJdf z5AAF%f|i`rF92utXbh@H+>`TpXh?(TWRJLKwE${ArJo2+@73rJv9tnO(%-MqSJ$y% z0hPjd39{D@0}XpLdhJv?qe|VQ(f!_BUe&{gR-Dy;4eEDmbiOFsiLTk_^r7r?h(IeX z;<~@KSMkbvdYZ*m!-(4*fw(k+I63)Wep$dQ;0*Ghv`EBbE#fAq8|$0dBbNCu$t-Py z$6ykT7(rZb$$wYPd=-qim>7gBxVT<3w?oSNd*9^Oi8O;6lcDg#==(GD=0N-65O=h= zGx-Aly!0ahZ4yJIcto%kck_mF|G`2(i=o4b2*NP#dbt1Oq9rXQkbW|PJ&e27{GSj~ zh)Psw)mkIYvJ zgKl9yVgz(uw7>UXQBN^6SODKwTF`ai{@sGp|ILDnI)spbg%|-{L-rpooFV_*RwqsS zLxmfQpg=Za1a$HdAI8=WgATSjtq+$9pc7m~+6d?fS}A7sX+igq3`;SiUjXUw5mCdS zYfDQ>lMREeNi6N;L$LzHyJ66^2wRD+3xx=1q0pdp7<8R2EoD@8XICSqtXmt)O&){% z9dv?}e>pEUD?YlP2R$8&{5_VdRyGj-YQFpycnq!Mkgtbhxt_xR?!P!$w-CBB0qLfV z<>r22k^bI+^D0G9&qSmbXbHouHTB0L{80=;ah~UF^u@V)bDWAj^!%pnqIQpN8PVX&&jx2`fLQBJz*dL2JwN(slTY?;+q4dYL zt`b43mLbbV!anMcoSg&H5V->RI}J1bUfc`1i=pb3$PpU02mHIfC;gkg=d}r;%+<&d z8diDyA@N?)&+T>c>^~&_V-fUhEpmj0yb+UkDIe5^ecTa~FBCw(tVjM%!z8WE<9f9; ztf9j;pWY{c8aE(EX!s@IgQsAGh9dq~KIF0qIYPtc{7*y(xf#jxGgSUHvCKhBg~&G( zD*q$9%tPB1BT*A-{v*XKK+B7f&SPu;m1h>BPl=Gv#?`~g=09@HBD6$=e1dHFBjGGY zTZ@qok&S<3oyBOH80j;n>Ce=23Hm?@GJMRZk^D0lIkpu2xdi!qY%`!UoP`GEYozE) z5~RnNmOr!6GIYBH>1)sejHIPy=+~vlcLvSCNPb#|){`Pb$20?fB&ucTXl=n~U^rt9 zHW^FN8)ZmWZJ*l2HQ2Yl6rC?a1|#87jbyJS=#z3}?3k~AX0Rpb0XZ^b%(p+&*d^$c zGGxM-u0M0xV)Ow8GIwmx9|>&{po7kwpf?k3RE~5U2dANbPi||=1rzj)(WG+Zb8Y$W ziSA;!{EN2ySOxOgB)FOXNO}v=!U|;4jPC!E`7VN!?&!@E^%kNdmB=?!dj6UQ2NDEm zV-+%C#(zzP3jj6RbE4jS^d}Y48?OA9v^XC=oIO!*0Xm`*>8(GKA}2zYRmep%{txlc B>QVpz delta 6461 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 UU>mG~(Y_7V!jFX80i}=r5B this.scene.start('GameMenu'), { + variant: 'ghost', width: 140, fontSize: 20, + }); + + await this.loadPlayerChips(); + this.initGame(); + } + + // ── Playfield ───────────────────────────────────────────────────────────── + buildPlayfield() { + const pf = this.playfield; + if (pf?.key && this.textures.exists(pf.key)) { + this.add.image(CX, GAME_HEIGHT / 2, pf.key) + .setDisplaySize(GAME_WIDTH, GAME_HEIGHT).setDepth(D.bg + 1); + } + } + + // ── Table ───────────────────────────────────────────────────────────────── + buildTable() { + const g = this.add.graphics().setDepth(D.table); + g.fillStyle(0x1a5c2a, 1); + g.fillEllipse(CX, TABLE_CY, 1500, 680); + g.lineStyle(8, 0x2e7d32, 1); + g.strokeEllipse(CX, TABLE_CY, 1500, 680); + g.lineStyle(3, 0x4caf50, 0.4); + g.strokeEllipse(CX, TABLE_CY, 1440, 620); + } + + buildTableMarkings() { + const g = this.add.graphics().setDepth(D.table + 1); + + for (let seat = 0; seat < SEAT_POS.length; seat++) { + const pos = SEAT_POS[seat]; + g.lineStyle(2, 0xffffff, 0.5); + g.strokeRoundedRect(pos.x - CARD_W / 2 - 4, pos.y - CARD_H / 2 - 4, CARD_W + 8, CARD_H + 8, CARD_R + 2); + const { x: bx, y: by } = this.betCirclePos(seat); + g.lineStyle(2, 0xffffff, 0.55); + g.strokeCircle(bx, by, 30); + } + + this.drawArcText('PAI GOW POKER', CX, 580, 760, { + fontSize: 32, color: COLORS.goldHex, bold: true, advanceFactor: 0.96, + }); + this.drawArcText('BANKER WINS ALL TIES · 5% COMMISSION ON WINS', CX, 636, 720, { + fontSize: 19, color: COLORS.mutedHex, advanceFactor: 0.84, + }); + } + + drawArcText(text, centerX, baseY, radius, opts = {}) { + const fontSize = opts.fontSize ?? 24; + const anglePer = ((opts.advanceFactor ?? 0.92) * fontSize) / radius; + const cy = baseY - radius; + const start = -anglePer * (text.length - 1) / 2; + const style = { + fontFamily: opts.fontFamily ?? '"Julius Sans One"', + fontSize: `${fontSize}px`, + color: opts.color ?? COLORS.textHex, + ...(opts.bold ? { fontStyle: 'bold' } : {}), + }; + const depth = opts.depth ?? (D.table + 1); + for (let i = 0; i < text.length; i++) { + if (text[i] === ' ') continue; + const a = start + i * anglePer; + this.add.text(centerX + radius * Math.sin(a), cy + radius * Math.cos(a), text[i], style) + .setOrigin(0.5).setRotation(-a).setDepth(depth); + } + } + + // ── Dealer area ─────────────────────────────────────────────────────────── + buildDealerArea() { + this.add.text(CX, 55, 'Pai Gow Poker', { + fontFamily: 'Righteous', fontSize: '48px', color: COLORS.textHex, + }).setOrigin(0.5).setDepth(D.ui); + + this.dealerHighLabel = this.add.text(CX - 170, DEALER_Y - CARD_H / 2 - 24, '', { + fontFamily: '"Julius Sans One"', fontSize: '16px', color: COLORS.mutedHex, + }).setOrigin(0.5).setDepth(D.ui); + + this.dealerLowLabel = this.add.text(CX + 170, DEALER_Y - CARD_H / 2 - 24, '', { + fontFamily: '"Julius Sans One"', fontSize: '16px', color: COLORS.mutedHex, + }).setOrigin(0.5).setDepth(D.ui); + } + + // ── Seats ───────────────────────────────────────────────────────────────── + buildSeats() { + for (let seat = 0; seat < SEAT_POS.length; seat++) { + const pos = SEAT_POS[seat]; + const opp = seat === 0 ? null : this.opponents[seat - 1] ?? null; + const active = seat === 0 ? true : !!opp; + if (!active) continue; + + const px = pos.portraitX ?? pos.x; + const py = pos.portraitY ?? (pos.y - CARD_H / 2 - (pos.portraitR ?? 58) - 60); + const labelX = px + (pos.labelDX ?? 0); + const nameY = py + (pos.portraitR ?? 58) + 18; + const chipY = nameY + 24; + + this.nameTxts[seat] = this.add.text(labelX, nameY, seat === 0 ? 'You' : opp.name, { + fontFamily: '"Julius Sans One"', fontSize: '20px', color: COLORS.textHex, + }).setOrigin(0.5).setDepth(D.ui); + + this.chipTxts[seat] = this.add.text(labelX, chipY, '', { + fontFamily: '"Julius Sans One"', fontSize: '18px', color: COLORS.mutedHex, + }).setOrigin(0.5).setDepth(D.ui); + + { + const maxTW = Math.max(this.nameTxts[seat].width, 130); + const rectW = maxTW + 20; + const rectH = (chipY - nameY) + 36; + const bg = this.add.graphics().setDepth(D.ui - 1); + bg.fillStyle(0x000000, 0.60); + bg.fillRoundedRect(labelX - rectW / 2, (nameY + chipY) / 2 - rectH / 2, rectW, rectH, 6); + } + + this.scoreTxts[seat] = this.add.text(pos.x, pos.y - CARD_H / 2 - 11, '', { + fontFamily: '"Julius Sans One"', fontSize: '18px', color: COLORS.textHex, + }).setOrigin(0.5).setDepth(D.ui); + + if (seat === 0) { + this.portraits[seat] = createPlayerPortrait(this, px, py, pos.portraitR ?? 72, D.ui, 'PaiGowPokerGame'); + } else { + this.portraits[seat] = createOpponentPortrait(this, opp, px, py, pos.portraitR ?? 58, D.ui); + } + } + } + + // ── Betting UI ──────────────────────────────────────────────────────────── + buildBettingUI() { + const y = GAME_HEIGHT - 80; + const cx = CX + 60; + + const panel = this.add.graphics().setDepth(D.ui); + panel.fillStyle(0x000000, 1); + panel.fillRoundedRect(cx - 174, y - 69, 726, 116, 18); + panel.lineStyle(3, COLORS.accent, 1); + panel.strokeRoundedRect(cx - 174, y - 69, 726, 116, 18); + this.bettingUIGroup.push(panel); + + CHIP_AMOUNTS.forEach((amt, i) => { + const bx = cx - 120 + i * 80; + const container = this.add.container(bx, y).setDepth(D.ui + 1); + const g = this.add.graphics(); + g.lineStyle(3, 0xffffff, 0.4); + g.strokeCircle(0, 0, 28); + g.fillStyle(CHIP_COLORS[amt], 1); + g.fillCircle(0, 0, 28); + container.add(g); + container.setInteractive(new Phaser.Geom.Circle(0, 0, 28), Phaser.Geom.Circle.Contains); + container.on('pointerdown', () => this.onChipClick(amt)); + container.on('pointerover', () => container.setAlpha(0.8)); + container.on('pointerout', () => container.setAlpha(1)); + + const t = this.add.text(bx, y, `$${amt}`, { + fontFamily: '"Julius Sans One"', fontSize: '13px', + color: '#ffffff', fontStyle: 'bold', + }).setOrigin(0.5).setDepth(D.ui + 2); + + this.bettingUIGroup.push(container, t); + this.chipBtnGraphics.push(container); + }); + + this.betDisplayText = this.add.text(cx + 170, y, 'Bet: $0', { + fontFamily: '"Julius Sans One"', fontSize: '22px', color: COLORS.textHex, + }).setOrigin(0, 0.5).setDepth(D.ui + 1); + + this.balanceText = this.add.text(cx + 170, y - 32, '', { + fontFamily: '"Julius Sans One"', fontSize: '18px', color: COLORS.mutedHex, + }).setOrigin(0, 0.5).setDepth(D.ui + 1); + + const clearBtn = new Button(this, cx + 360, y, 'Clear', () => this.onClearBet(), { + width: 100, height: 50, fontSize: 18, variant: 'ghost', + }); + this.dealBtn = new Button(this, cx + 470, y, 'Deal', () => this.onDealClick(), { + width: 110, height: 50, fontSize: 20, + }); + this.dealBtn.setEnabled(false); + clearBtn.setDepth(D.ui + 1); + this.dealBtn.setDepth(D.ui + 1); + + this.bettingUIGroup.push(this.betDisplayText, this.balanceText, clearBtn, this.dealBtn); + this.hideBettingUI(); + } + + showBettingUI() { + for (const o of this.bettingUIGroup) o.setVisible?.(true) ?? (o.visible = true); + } + hideBettingUI() { + for (const o of this.bettingUIGroup) o.setVisible?.(false) ?? (o.visible = false); + } + + // ── Hand-setting panel ──────────────────────────────────────────────────── + buildHandSetPanel() { + const panelBg = this.add.graphics().setDepth(D.panel).setVisible(false); + panelBg.fillStyle(0x000000, 0.90); + panelBg.fillRoundedRect(40, PANEL_Y0, GAME_WIDTH - 80, PANEL_H, 14); + panelBg.lineStyle(2, COLORS.accent, 0.7); + panelBg.strokeRoundedRect(40, PANEL_Y0, GAME_WIDTH - 80, PANEL_H, 14); + this.setPanelGroup.push(panelBg); + + // Zone labels + const labelStyle = { fontFamily: '"Julius Sans One"', fontSize: '17px', color: COLORS.mutedHex }; + const hiLabel = this.add.text(HIGH_SLOT_CX, PANEL_Y0 + 20, 'HIGH HAND (5 cards)', labelStyle) + .setOrigin(0.5).setDepth(D.panel + 1).setVisible(false); + const loLabel = this.add.text(LOW_SLOT_CX, PANEL_Y0 + 20, 'LOW HAND (2 cards)', labelStyle) + .setOrigin(0.5).setDepth(D.panel + 1).setVisible(false); + this.setPanelGroup.push(hiLabel, loLabel); + + // Separator line between high and low zones + const sep = this.add.graphics().setDepth(D.panel + 1).setVisible(false); + sep.lineStyle(1, 0xffffff, 0.15); + sep.beginPath(); + sep.moveTo(1060, PANEL_Y0 + 10); + sep.lineTo(1060, PANEL_Y0 + PANEL_H - 10); + sep.strokePath(); + this.setPanelGroup.push(sep); + + // 5 drop-zone slots for high hand + this.setHighSlots = []; + for (let i = 0; i < 5; i++) { + const x = HIGH_SLOT_CX - 2 * SLOT_GAP + i * SLOT_GAP; + const g = this.add.graphics().setDepth(D.panel + 1).setVisible(false); + this.drawEmptySlot(g, x, SLOT_Y); + const zone = this.add.zone(x, SLOT_Y, CARD_W + 10, CARD_H + 10) + .setDepth(D.panel + 2).setDropZone().setVisible(false); + zone._pgSlot = { type: 'high', idx: i }; + zone.on('pointerdown', () => this.onHighSlotClick(i)); + this.setHighSlots.push({ g, zone, x, y: SLOT_Y }); + this.setPanelGroup.push(g, zone); + } + + // 2 drop-zone slots for low hand + this.setLowSlots = []; + for (let i = 0; i < 2; i++) { + const x = LOW_SLOT_CX - SLOT_GAP / 2 + i * SLOT_GAP; + const g = this.add.graphics().setDepth(D.panel + 1).setVisible(false); + this.drawEmptySlot(g, x, SLOT_Y); + const zone = this.add.zone(x, SLOT_Y, CARD_W + 10, CARD_H + 10) + .setDepth(D.panel + 2).setDropZone().setVisible(false); + zone._pgSlot = { type: 'low', idx: i }; + zone.on('pointerdown', () => this.onLowSlotClick(i)); + this.setLowSlots.push({ g, zone, x, y: SLOT_Y }); + this.setPanelGroup.push(g, zone); + } + + // Phaser drop-zone events — handle the actual card placement on drop + this.input.on('drop', (_ptr, gameObj, dropZone) => { + if (!this.panelVisible || !dropZone._pgSlot) return; + const cardIdx = this.setCardConts.indexOf(gameObj); + if (cardIdx === -1) return; + const { type, idx } = dropZone._pgSlot; + if (type === 'high') this._dropToHighSlot(cardIdx, idx); + else this._dropToLowSlot(cardIdx, idx); + }); + + this.input.on('dragenter', (_ptr, _obj, zone) => { + if (!this.panelVisible || !zone._pgSlot) return; + const { type, idx } = zone._pgSlot; + const slot = type === 'high' ? this.setHighSlots[idx] : this.setLowSlots[idx]; + this._drawHighlightSlot(slot.g, slot.x, SLOT_Y); + }); + + this.input.on('dragleave', (_ptr, _obj, zone) => { + if (!this.panelVisible || !zone._pgSlot) return; + const { type, idx } = zone._pgSlot; + const slot = type === 'high' ? this.setHighSlots[idx] : this.setLowSlots[idx]; + this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + }); + + // Live rank labels below the slots + this.highRankTxt = this.add.text(HIGH_SLOT_CX, SLOT_Y + CARD_H / 2 + 14, '', { + fontFamily: '"Julius Sans One"', fontSize: '20px', color: COLORS.goldHex, + }).setOrigin(0.5).setDepth(D.panel + 1).setVisible(false); + + this.lowRankTxt = this.add.text(LOW_SLOT_CX, SLOT_Y + CARD_H / 2 + 14, '', { + fontFamily: '"Julius Sans One"', fontSize: '20px', color: COLORS.goldHex, + }).setOrigin(0.5).setDepth(D.panel + 1).setVisible(false); + + // Foul warning + this.foulWarnTxt = this.add.text(CX, SLOT_Y + CARD_H / 2 + 14, '', { + fontFamily: '"Julius Sans One"', fontSize: '16px', color: '#e06c75', + }).setOrigin(0.5).setDepth(D.panel + 1).setVisible(false); + + this.setPanelGroup.push(this.highRankTxt, this.lowRankTxt, this.foulWarnTxt); + + // Buttons + this.houseWayBtn = new Button(this, HIGH_SLOT_CX - 100, PANEL_Y0 + PANEL_H - 28, 'House Way', () => this.applyHouseWayUI(), { + width: 150, height: 44, fontSize: 16, + }); + this.clearSetBtn = new Button(this, HIGH_SLOT_CX + 75, PANEL_Y0 + PANEL_H - 28, 'Clear', () => this.clearHandSet(), { + width: 110, height: 44, fontSize: 16, variant: 'ghost', + }); + this.setHandBtn = new Button(this, CX + 20, PANEL_Y0 + PANEL_H - 28, 'Set Hand', () => this.onSetHand(), { + width: 160, height: 44, fontSize: 18, + }); + this.setHandBtn.setEnabled(false); + this.houseWayBtn.setDepth(D.panel + 2); + this.clearSetBtn.setDepth(D.panel + 2); + this.setHandBtn.setDepth(D.panel + 2); + this.setPanelGroup.push(this.houseWayBtn, this.clearSetBtn, this.setHandBtn); + + this.hideHandSetPanel(); + } + + drawEmptySlot(g, cx, cy) { + g.clear(); + g.lineStyle(2, 0xffffff, 0.25); + g.strokeRoundedRect(cx - CARD_W / 2, cy - CARD_H / 2, CARD_W, CARD_H, CARD_R); + } + + drawSelectedSlot(g, cx, cy) { + g.clear(); + g.lineStyle(3, 0xf5d020, 0.9); + g.strokeRoundedRect(cx - CARD_W / 2, cy - CARD_H / 2, CARD_W, CARD_H, CARD_R); + } + + showHandSetPanel() { + this.panelVisible = true; + for (const o of this.setPanelGroup) o.setVisible(true); + // Hide all portraits and their seat labels so they don't overlap the panel + for (const p of this.portraits) p?.hide?.(); + for (const t of Object.values(this.nameTxts)) t.setVisible(false); + for (const t of Object.values(this.chipTxts)) t.setVisible(false); + // Build and place the 7 card containers in the source area + this.buildSetCardContainers(); + this.updateHandSetUI(); + } + + hideHandSetPanel() { + this.panelVisible = false; + for (const o of this.setPanelGroup) o.setVisible(false); + for (const c of this.setCardConts) c.destroy(); + this.setCardConts = []; + // Restore portraits and seat labels + for (const p of this.portraits) p?.show?.(); + for (const t of Object.values(this.nameTxts)) t.setVisible(true); + for (const t of Object.values(this.chipTxts)) t.setVisible(true); + } + + buildSetCardContainers() { + for (const c of this.setCardConts) c.destroy(); + this.setCardConts = []; + const hand = this.gs.players[0].hand; + hand.forEach((card, i) => { + const sx = this.sourceCardX(i); + const cont = this.add.container(sx, SOURCE_Y).setDepth(D.panel + 3); + this.drawCard(cont, card, true); + cont.setSize(CARD_W, CARD_H); + cont.setInteractive({ useHandCursor: true }); + this.input.setDraggable(cont); + + let _dragged = false; + + cont.on('dragstart', () => { + _dragged = true; + this.selectedCardIdx = null; + if (this._selRings) { for (const r of this._selRings) r.destroy(); this._selRings = []; } + cont.setDepth(D.panel + 10); + }); + + cont.on('drag', (_ptr, dragX, dragY) => { + cont.setPosition(dragX, dragY); + }); + + cont.on('dragend', () => { + cont.setDepth(D.panel + 3); + this._clearDragHighlights(); + // 'drop' event (fired before dragend) already placed the card if it hit a zone. + // Re-render to snap card to its slot (or back to source on a miss). + this.updateHandSetUI(); + }); + + // Only treat as a click when the pointer never moved far enough to trigger a drag + cont.on('pointerdown', () => { _dragged = false; }); + cont.on('pointerup', () => { + if (!_dragged) this.onSourceCardClick(i); + _dragged = false; // reset after the check so dragend's state is preserved + }); + + this.setCardConts.push(cont); + }); + } + + // Highlights whichever slot the card is hovering over; clears all others + _drawHighlightSlot(g, cx, cy) { + g.clear(); + g.fillStyle(0xf5d020, 0.18); + g.fillRoundedRect(cx - CARD_W / 2, cy - CARD_H / 2, CARD_W, CARD_H, CARD_R); + g.lineStyle(3, 0xf5d020, 1); + g.strokeRoundedRect(cx - CARD_W / 2, cy - CARD_H / 2, CARD_W, CARD_H, CARD_R); + } + + _clearDragHighlights() { + for (let i = 0; i < 5; i++) { + const slot = this.setHighSlots[i]; + this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + } + for (let i = 0; i < 2; i++) { + const slot = this.setLowSlots[i]; + this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + } + } + + _dropToHighSlot(cardIdx, slotIdx) { + // Remove cardIdx from its current slot (if any) + const fromHi = this.humanHighSlots.indexOf(cardIdx); + const fromLo = this.humanLowSlots.indexOf(cardIdx); + if (fromHi !== -1) this.humanHighSlots[fromHi] = null; + if (fromLo !== -1) this.humanLowSlots[fromLo] = null; + // Displaced occupant goes back to source (its slot becomes null) + // — no extra action needed; it will re-anchor in updateHandSetUI + this.humanHighSlots[slotIdx] = cardIdx; + this.selectedCardIdx = null; + this.updateHandSetUI(); + } + + _dropToLowSlot(cardIdx, slotIdx) { + const fromHi = this.humanHighSlots.indexOf(cardIdx); + const fromLo = this.humanLowSlots.indexOf(cardIdx); + if (fromHi !== -1) this.humanHighSlots[fromHi] = null; + if (fromLo !== -1) this.humanLowSlots[fromLo] = null; + this.humanLowSlots[slotIdx] = cardIdx; + this.selectedCardIdx = null; + this.updateHandSetUI(); + } + + sourceCardX(idx) { + // 7 cards spread centered at CX + return CX - 3 * SLOT_GAP + idx * SLOT_GAP; + } + + updateHandSetUI() { + const hand = this.gs.players[0].hand; + const placedSet = new Set([ + ...this.humanHighSlots.filter(v => v !== null), + ...this.humanLowSlots.filter(v => v !== null), + ]); + + // Position each card container + this.setCardConts.forEach((cont, i) => { + const highIdx = this.humanHighSlots.indexOf(i); + const lowIdx = this.humanLowSlots.indexOf(i); + if (highIdx !== -1) { + // In high hand slot + const slot = this.setHighSlots[highIdx]; + cont.setPosition(slot.x, SLOT_Y); + cont.setAlpha(1); + // Highlight slot outline if this card is "selected" (for swapping) + this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + if (this.selectedCardIdx === i) this.drawSelectedSlot(slot.g, slot.x, SLOT_Y); + } else if (lowIdx !== -1) { + // In low hand slot + const slot = this.setLowSlots[lowIdx]; + cont.setPosition(slot.x, SLOT_Y); + cont.setAlpha(1); + if (this.selectedCardIdx === i) this.drawSelectedSlot(slot.g, slot.x, SLOT_Y); + else this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + } else { + // In source zone + cont.setPosition(this.sourceCardX(i), SOURCE_Y); + cont.setAlpha(this.selectedCardIdx === i ? 0.5 : 1); + // Pulse ring for selected source card + if (this.selectedCardIdx === i) { + // Add a selection ring by re-drawing card with highlight + // (simpler: just alpha fade the others is not great; instead use a ring overlay) + } + } + }); + + // Draw selection ring on selected source card + this.drawSelectionRings(); + + // Update empty slot outlines + for (let i = 0; i < 5; i++) { + const slot = this.setHighSlots[i]; + if (this.humanHighSlots[i] === null) this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + } + for (let i = 0; i < 2; i++) { + const slot = this.setLowSlots[i]; + if (this.humanLowSlots[i] === null) this.drawEmptySlot(slot.g, slot.x, SLOT_Y); + } + + // Update rank labels + const highCards = this.humanHighSlots.filter(v => v !== null).map(i => hand[i]); + const lowCards = this.humanLowSlots.filter(v => v !== null).map(i => hand[i]); + + if (highCards.length === 5) { + const ev = evaluate5Card(highCards); + this.highRankTxt.setText(handName5(ev)); + } else { + this.highRankTxt.setText(`${highCards.length}/5 placed`); + } + + if (lowCards.length === 2) { + const ev = evaluate2Card(lowCards); + this.lowRankTxt.setText(ev.name); + } else { + this.lowRankTxt.setText(`${lowCards.length}/2 placed`); + } + + // Validate and update foul / set hand button + const complete = highCards.length === 5 && lowCards.length === 2; + let fouled = false; + if (complete) { + fouled = isFoul(highCards, lowCards); + this.foulWarnTxt.setText(fouled ? 'Invalid: High hand must outrank Low hand' : ''); + } else { + this.foulWarnTxt.setText(''); + } + this.setHandBtn.setEnabled(complete && !fouled); + } + + drawSelectionRings() { + // Remove existing rings + if (this._selRings) { + for (const r of this._selRings) r.destroy(); + } + this._selRings = []; + if (this.selectedCardIdx === null) return; + const hand = this.gs.players[0].hand; + const hi = this.humanHighSlots.indexOf(this.selectedCardIdx); + const lo = this.humanLowSlots.indexOf(this.selectedCardIdx); + let cx, cy; + if (hi !== -1) { + cx = this.setHighSlots[hi].x; cy = SLOT_Y; + } else if (lo !== -1) { + cx = this.setLowSlots[lo].x; cy = SLOT_Y; + } else { + cx = this.sourceCardX(this.selectedCardIdx); cy = SOURCE_Y; + } + const ring = this.add.graphics().setDepth(D.panel + 4); + ring.lineStyle(4, 0xf5d020, 1); + ring.strokeRoundedRect(cx - CARD_W / 2 - 3, cy - CARD_H / 2 - 3, CARD_W + 6, CARD_H + 6, CARD_R + 2); + this._selRings.push(ring); + } + + onSourceCardClick(idx) { + if (this.animating) return; + if (this.selectedCardIdx === idx) { + // Deselect + this.selectedCardIdx = null; + } else { + // If a slot card was selected, swap them + const prevSelected = this.selectedCardIdx; + if (prevSelected !== null) { + const hiPrev = this.humanHighSlots.indexOf(prevSelected); + const loPrev = this.humanLowSlots.indexOf(prevSelected); + if (hiPrev !== -1) { + // Prev was in high slot → move source card there, return prev to source + this.humanHighSlots[hiPrev] = idx; + } else if (loPrev !== -1) { + this.humanLowSlots[loPrev] = idx; + } + this.selectedCardIdx = null; + } else { + this.selectedCardIdx = idx; + } + } + this.updateHandSetUI(); + } + + onHighSlotClick(slotIdx) { + if (this.animating) return; + const currentInSlot = this.humanHighSlots[slotIdx]; + + if (this.selectedCardIdx !== null) { + // Place selected card into this slot + const prevInSlot = currentInSlot; + // Remove selected card from wherever it currently is + const hiSel = this.humanHighSlots.indexOf(this.selectedCardIdx); + const loSel = this.humanLowSlots.indexOf(this.selectedCardIdx); + if (hiSel !== -1) this.humanHighSlots[hiSel] = null; + if (loSel !== -1) this.humanLowSlots[loSel] = null; + // Put selected card in this slot + this.humanHighSlots[slotIdx] = this.selectedCardIdx; + // If there was a card here before, it stays selected (or goes to source) + this.selectedCardIdx = prevInSlot; // null if slot was empty + } else if (currentInSlot !== null) { + // No card selected — select the card in this slot + this.selectedCardIdx = currentInSlot; + } + this.updateHandSetUI(); + } + + onLowSlotClick(slotIdx) { + if (this.animating) return; + const currentInSlot = this.humanLowSlots[slotIdx]; + + if (this.selectedCardIdx !== null) { + const prevInSlot = currentInSlot; + const hiSel = this.humanHighSlots.indexOf(this.selectedCardIdx); + const loSel = this.humanLowSlots.indexOf(this.selectedCardIdx); + if (hiSel !== -1) this.humanHighSlots[hiSel] = null; + if (loSel !== -1) this.humanLowSlots[loSel] = null; + this.humanLowSlots[slotIdx] = this.selectedCardIdx; + this.selectedCardIdx = prevInSlot; + } else if (currentInSlot !== null) { + this.selectedCardIdx = currentInSlot; + } + this.updateHandSetUI(); + } + + applyHouseWayUI() { + const hand = this.gs.players[0].hand; + const { highHand, lowHand } = houseWay(hand); + // Map card objects to indices in the hand array + this.humanHighSlots = highHand.map(c => hand.indexOf(c)); + this.humanLowSlots = lowHand.map(c => hand.indexOf(c)); + this.selectedCardIdx = null; + this.updateHandSetUI(); + } + + clearHandSet() { + this.humanHighSlots = [null, null, null, null, null]; + this.humanLowSlots = [null, null]; + this.selectedCardIdx = null; + this.updateHandSetUI(); + } + + onSetHand() { + if (this.animating) return; + const hand = this.gs.players[0].hand; + const highHand = this.humanHighSlots.map(i => hand[i]); + const lowHand = this.humanLowSlots.map(i => hand[i]); + this.gs = applyHumanSplit(this.gs, highHand, lowHand); + this.hideHandSetPanel(); + this.startComparingPhase(); + } + + // ── Chip balance ────────────────────────────────────────────────────────── + async loadPlayerChips() { + try { + const { profile } = await api.get('/profile'); + this._playerChips = profile.chips ?? 2000; + } catch { + this._playerChips = 2000; + } + } + + // ── Game init ───────────────────────────────────────────────────────────── + initGame() { + this.gs = createInitialState(this.opponents, this._playerChips); + this.startNewRound(); + } + + startNewRound() { + playSound(this, SFX.CARD_SHUFFLE); + this.pendingBet = 0; + this.gs = prepareRound(this.gs); + this.clearCardGraphics(); + this.renderAll(); + this.showBettingUI(); + this.updateBetDisplay(); + } + + // ── Render ──────────────────────────────────────────────────────────────── + renderAll() { + this.renderDealer(); + for (let seat = 0; seat < SEAT_POS.length; seat++) { + const p = this.gs.players[seat]; + if (!p.active) continue; + this.renderSeat(seat); + this.renderSeatInfo(seat); + } + this.renderBetAreas(); + } + + renderDealer() { + for (const c of this.dealerCardGraphics) c.destroy(); + this.dealerCardGraphics = []; + this.dealerHighLabel.setText(''); + this.dealerLowLabel.setText(''); + + const dealer = this.gs.dealer; + if (!dealer.hand.length) return; + + if (!dealer.revealed) { + // Fan of face-down cards + dealer.hand.forEach((card, i) => { + const x = this.fanCardX(DEALER_X, i, dealer.hand.length); + const cont = this.add.container(x, DEALER_Y).setDepth(D.cards); + this.drawCard(cont, null, false); + this.dealerCardGraphics.push(cont); + }); + return; + } + + // After reveal: show split layout (5 HIGH + 2 LOW) + this.renderSplitCards(DEALER_X - 170, DEALER_Y, dealer.highHand, this.dealerCardGraphics); + this.renderSplitCards(DEALER_X + 170, DEALER_Y, dealer.lowHand, this.dealerCardGraphics); + + if (dealer.highEval) this.dealerHighLabel.setText(handName5(dealer.highEval)); + if (dealer.lowEval) this.dealerLowLabel.setText(dealer.lowEval.name); + } + + renderSeat(seat) { + if (this.seatCardGraphics[seat]) { + for (const c of this.seatCardGraphics[seat]) c.destroy(); + } + this.seatCardGraphics[seat] = []; + + const p = this.gs.players[seat]; + const pos = SEAT_POS[seat]; + + if (!p.hand.length) return; + + const phase = this.gs.phase; + const showSplit = phase === 'comparing' || phase === 'resolved'; + + if (seat === 0 && this.panelVisible) { + // Human cards are shown in the panel while it's open — don't render at seat + return; + } + + if (showSplit && p.highHand.length > 0) { + // Split view: high hand left, low hand right + if (seat === 0) { + this.renderSplitCards(pos.x - 130, pos.y, p.highHand, this.seatCardGraphics[seat]); + this.renderSplitCards(pos.x + 130, pos.y, p.lowHand, this.seatCardGraphics[seat]); + } else { + this.renderSplitCards(pos.x - 100, pos.y, p.highHand, this.seatCardGraphics[seat]); + this.renderSplitCards(pos.x + 100, pos.y, p.lowHand, this.seatCardGraphics[seat]); + } + if (this.scoreTxts[seat]) this.scoreTxts[seat].setText(''); + } else { + // Fan view: 7 face-down cards + p.hand.forEach((card, i) => { + const x = this.fanCardX(pos.x, i, p.hand.length); + const cont = this.add.container(x, pos.y).setDepth(D.cards); + // Human's cards are face-up, AI cards face-down during dealing/setting + const faceUp = seat === 0; + this.drawCard(cont, faceUp ? card : null, faceUp); + this.seatCardGraphics[seat].push(cont); + }); + } + } + + renderSplitCards(cx, cy, cards, targetArr) { + cards.forEach((card, i) => { + const total = cards.length; + const spread = CARD_SPREAD_SPLIT; + const totalW = (total - 1) * spread; + const x = cx - totalW / 2 + i * spread; + const cont = this.add.container(x, cy).setDepth(D.cards); + this.drawCard(cont, card, true); + targetArr.push(cont); + }); + } + + renderSeatInfo(seat) { + const p = this.gs.players[seat]; + if (this.chipTxts[seat]) this.chipTxts[seat].setText(`$${p.chips.toLocaleString()}`); + } + + renderBetAreas() { + for (const g of Object.values(this.betGraphics)) g.destroy(); + this.betGraphics = {}; + for (let seat = 0; seat < SEAT_POS.length; seat++) { + const p = this.gs.players[seat]; + if (!p.active || p.bet === 0) continue; + const { x: betX, y: betY } = this.betCirclePos(seat); + const cont = this.add.container(betX, betY).setDepth(D.chips); + const circle = this.add.graphics(); + circle.fillStyle(0x2a2a2a, 1); + circle.fillCircle(0, 0, 28); + circle.lineStyle(2, 0xf0e8d0, 0.8); + circle.strokeCircle(0, 0, 28); + const txt = this.add.text(0, 0, `$${p.bet}`, { + fontFamily: '"Julius Sans One"', fontSize: '14px', color: '#f0e8d0', + }).setOrigin(0.5); + cont.add([circle, txt]); + this.betGraphics[seat] = cont; + } + } + + clearCardGraphics() { + for (const cards of Object.values(this.seatCardGraphics)) { + for (const c of cards) c.destroy(); + } + this.seatCardGraphics = {}; + for (const c of this.dealerCardGraphics) c.destroy(); + this.dealerCardGraphics = []; + for (const g of Object.values(this.betGraphics)) g.destroy(); + this.betGraphics = {}; + } + + betCirclePos(seat) { + const pos = SEAT_POS[seat]; + if (pos.betX !== undefined) return { x: pos.betX, y: pos.betY }; + const t = 0.22; + return { + x: Math.round(pos.x + t * (CX - pos.x)), + y: Math.round(pos.y + t * (TABLE_CY - pos.y)), + }; + } + + fanCardX(centerX, idx, total) { + const totalW = (total - 1) * CARD_SPREAD_FAN + CARD_W; + return centerX - totalW / 2 + CARD_W / 2 + idx * CARD_SPREAD_FAN; + } + + // ── Card drawing ────────────────────────────────────────────────────────── + addCardBackToContainer(container) { + if (this.cardBack?.spriteIndex !== undefined && this.textures.exists('cardbacks')) { + container.add( + this.add.image(0, 0, 'cardbacks', this.cardBack.spriteIndex) + .setDisplaySize(CARD_W, CARD_H).setOrigin(0.5) + ); + } else { + const g = this.add.graphics(); + this.drawCardBack(g, -CARD_W / 2, -CARD_H / 2); + container.add(g); + } + } + + drawCardBack(g, x, y) { + const color = this.cardBack?.fallbackColor + ? parseInt(this.cardBack.fallbackColor.replace('#', ''), 16) : 0x1a3a6b; + g.fillStyle(color, 1); + g.fillRoundedRect(x, y, CARD_W, CARD_H, CARD_R); + g.lineStyle(2, 0xffffff, 0.25); + g.strokeRoundedRect(x + 6, y + 6, CARD_W - 12, CARD_H - 12, CARD_R - 2); + } + + drawCard(container, card, faceUp) { + container.removeAll(true); + const x = -CARD_W / 2, y = -CARD_H / 2; + if (faceUp && card) { + if (card.isJoker) { + // Special Joker rendering + const g = this.add.graphics(); + g.fillStyle(0xffffff, 1); + g.fillRoundedRect(x, y, CARD_W, CARD_H, CARD_R); + g.lineStyle(2, 0xd4a017, 1.5); + g.strokeRoundedRect(x, y, CARD_W, CARD_H, CARD_R); + container.add(g); + container.add(this.add.text(x + 7, y + 5, 'JK', { + fontFamily: '"Julius Sans One"', fontSize: '14px', color: '#7b2fbe', fontStyle: 'bold', + })); + container.add(this.add.text(0, 4, '★', { + fontFamily: '"Julius Sans One"', fontSize: '50px', color: '#d4a017', + }).setOrigin(0.5)); + container.add(this.add.text(x + CARD_W - 7, y + CARD_H - 8, 'JK', { + fontFamily: '"Julius Sans One"', fontSize: '14px', color: '#7b2fbe', fontStyle: 'bold', + }).setOrigin(1, 1)); + } else { + const g = this.add.graphics(); + g.fillStyle(0xffffff, 1); + g.fillRoundedRect(x, y, CARD_W, CARD_H, CARD_R); + g.lineStyle(1, 0xcccccc, 1); + g.strokeRoundedRect(x, y, CARD_W, CARD_H, CARD_R); + container.add(g); + const color = card.isRed ? '#c0392b' : '#1a1a2e'; + const s = (sz, bold = false) => ({ + fontFamily: '"Julius Sans One"', fontSize: `${sz}px`, color, + ...(bold ? { fontStyle: 'bold' } : {}), + }); + container.add(this.add.text(x + 7, y + 5, card.label, s(17, true))); + container.add(this.add.text(x + 7, y + 23, card.suitSymbol, s(13))); + container.add(this.add.text(0, 4, card.suitSymbol, s(40)).setOrigin(0.5)); + container.add(this.add.text(x + CARD_W - 7, y + CARD_H - 8, card.label, s(17, true)).setOrigin(1, 1)); + container.add(this.add.text(x + CARD_W - 7, y + CARD_H - 22, card.suitSymbol, s(13)).setOrigin(1, 1)); + } + } else { + this.addCardBackToContainer(container); + } + } + + // ── Betting phase ───────────────────────────────────────────────────────── + onChipClick(amount) { + if (this.animating) return; + const human = this.gs.players[0]; + if (this.pendingBet + amount > 100) return; + if (this.pendingBet + amount > human.chips) return; + this.pendingBet += amount; + this.updateBetDisplay(); + playChipBet(this); + } + + onClearBet() { + this.pendingBet = 0; + this.updateBetDisplay(); + } + + updateBetDisplay() { + if (this.betDisplayText) this.betDisplayText.setText(`Bet: $${this.pendingBet}`); + if (this.dealBtn) this.dealBtn.setEnabled(this.pendingBet >= 5); + const human = this.gs?.players[0]; + if (this.balanceText && human) this.balanceText.setText(`Balance: $${human.chips.toLocaleString()}`); + } + + onDealClick() { + if (this.animating || this.pendingBet < 5) return; + this.animating = true; + this.hideBettingUI(); + + this.gs = applyBet(this.gs, 0, this.pendingBet); + + for (let seat = 1; seat < SEAT_POS.length; seat++) { + const p = this.gs.players[seat]; + if (!p.active) continue; + this.gs = applyBet(this.gs, seat, Math.max(5, chooseBet(p))); + } + + this.gs = dealHands(this.gs); + + this.animateBets(() => { + this.animateDeal(() => { + this.animating = false; + this.renderAll(); + this.startSettingPhase(); + }); + }); + } + + // ── Animations ──────────────────────────────────────────────────────────── + animateBets(onComplete) { + this.renderBetAreas(); + playChipBet(this); + let done = 0; + const active = this.gs.players.filter(p => p.active); + if (!active.length) { onComplete(); return; } + for (const p of active) { + const pos = SEAT_POS[p.seat]; + const { x: betX, y: betY } = this.betCirclePos(p.seat); + const chip = this.add.graphics().setDepth(D.chips + 5); + chip.fillStyle(0x5cb85c, 1); chip.fillCircle(0, 0, 14); + chip.x = pos.x; chip.y = pos.y; + this.tweens.add({ + targets: chip, x: betX, y: betY, duration: 280, ease: 'Power2', + onComplete: () => { chip.destroy(); done++; if (done >= active.length) onComplete(); }, + }); + } + } + + animateDeal(onComplete) { + // All 7 cards dealt face-down to each player and dealer in sequence + const seats = PLAY_ORDER.filter(s => this.gs.players[s]?.active); + const DECK_X = CX + 200, DECK_Y = 50; + const totalDeals = (seats.length + 1) * 7; // seats + dealer + + // Pre-render all cards (face-down initially via renderAll) + this.renderAll(); + + // Hide all seat card graphics + for (const cards of Object.values(this.seatCardGraphics)) { + for (const c of cards) c.setAlpha(0); + } + for (const c of this.dealerCardGraphics) c.setAlpha(0); + + // Build deal sequence: deal 7 cards to each player in order, then dealer + const dealSeq = []; + for (let round = 0; round < 7; round++) { + for (const seat of seats) dealSeq.push({ type: 'player', seat, cardIdx: round }); + dealSeq.push({ type: 'dealer', cardIdx: round }); + } + + let idx = 0; + const stagger = 70; + const dealNext = () => { + if (idx >= dealSeq.length) { onComplete(); return; } + const entry = dealSeq[idx++]; + const flying = this.add.container(DECK_X, DECK_Y).setDepth(D.cards + 10); + this.addCardBackToContainer(flying); + + let tx, ty; + if (entry.type === 'dealer') { + tx = this.fanCardX(DEALER_X, entry.cardIdx, 7); + ty = DEALER_Y; + } else { + const pos = SEAT_POS[entry.seat]; + tx = this.fanCardX(pos.x, entry.cardIdx, 7); + ty = pos.y; + } + + this.tweens.add({ + targets: flying, x: tx, y: ty, duration: 160, ease: 'Power2', + onComplete: () => { + flying.destroy(); + playSound(this, SFX.CARD_DEAL); + if (entry.type === 'dealer') { + if (this.dealerCardGraphics[entry.cardIdx]) this.dealerCardGraphics[entry.cardIdx].setAlpha(1); + } else { + const cards = this.seatCardGraphics[entry.seat] ?? []; + if (cards[entry.cardIdx]) cards[entry.cardIdx].setAlpha(1); + } + this.time.delayedCall(stagger, dealNext); + }, + }); + }; + dealNext(); + } + + animateDealerReveal(onComplete) { + playSound(this, SFX.CARD_SHOW); + // Flip each dealer card to face-up + let done = 0; + const total = this.dealerCardGraphics.length; + if (!total) { this.renderDealer(); onComplete(); return; } + + this.dealerCardGraphics.forEach((cont, i) => { + this.time.delayedCall(i * 120, () => { + this.tweens.add({ + targets: cont, scaleX: 0, duration: 110, ease: 'Linear', + onComplete: () => { + // Reveal the face + const card = this.gs.dealer.hand[i]; + this.drawCard(cont, card, true); + this.tweens.add({ + targets: cont, scaleX: 1, duration: 110, ease: 'Linear', + onComplete: () => { + done++; + if (done === total) { + // Now show split layout + this.time.delayedCall(400, () => { + this.gs = { ...this.gs, dealer: { ...this.gs.dealer, revealed: true } }; + this.renderDealer(); + onComplete(); + }); + } + }, + }); + }, + }); + }); + }); + } + + // ── Setting phase ───────────────────────────────────────────────────────── + startSettingPhase() { + // Auto-set all AI players and dealer via House Way + for (let seat = 1; seat < SEAT_POS.length; seat++) { + if (this.gs.players[seat].active) { + this.gs = applyHouseWaySplit(this.gs, seat); + } + } + this.gs = applyDealerHouseWay(this.gs); + + // Reset human split state + this.humanHighSlots = [null, null, null, null, null]; + this.humanLowSlots = [null, null]; + this.selectedCardIdx = null; + + // Show the hand-setting panel + this.showHandSetPanel(); + } + + // ── Comparing phase ─────────────────────────────────────────────────────── + startComparingPhase() { + this.animating = true; + + // Briefly reveal all AI splits (1.5s), then reveal dealer + this.renderAll(); // shows AI split layouts + + this.time.delayedCall(1500, () => { + // Reveal dealer cards + this.animateDealerReveal(() => { + // Resolve round + this.gs = resolveRound(this.gs); + this.renderAll(); + // Show comparison results seat by seat + this.showComparisons(() => { + this.animating = false; + this.showNextRoundPrompt(); + }); + }); + }); + } + + showComparisons(onComplete) { + const activePlayers = this.gs.players.filter(p => p.active); + let done = 0; + const total = activePlayers.length; + + activePlayers.forEach((p, i) => { + this.time.delayedCall(i * 350, () => { + this.showSeatResult(p); + done++; + if (done === total) { + // Animate chip flows + this.animateAllChips(() => { + this.updateServerChips(); + this.time.delayedCall(800, onComplete); + }); + } + }); + }); + } + + showSeatResult(player) { + const pos = SEAT_POS[player.seat]; + const resultColor = RESULT_COLORS[player.result] ?? '#8a94a6'; + + // Net label for human (show commission) + let label; + if (player.result === 'win') { + label = `Win! +$${player.chipsWon}`; + } else if (player.result === 'push') { + label = 'Push'; + } else if (player.result === 'foul') { + label = 'Foul — Lose'; + } else { + label = `Lose -$${-player.chipsWon}`; + } + + const badge = this.add.text(pos.x, pos.y - CARD_H / 2 - 36, label, { + fontFamily: '"Julius Sans One"', fontSize: '24px', color: resultColor, fontStyle: 'bold', + }).setOrigin(0.5).setDepth(D.ui + 5).setAlpha(0).setScale(0.7); + + this.tweens.add({ + targets: badge, alpha: 1, scaleX: 1, scaleY: 1, duration: 200, ease: 'Back.easeOut', + onComplete: () => { + this.time.delayedCall(1800, () => { + this.tweens.add({ targets: badge, alpha: 0, y: badge.y - 30, duration: 380, ease: 'Power2', + onComplete: () => badge.destroy() }); + }); + }, + }); + + playSound(this, player.result === 'win' ? SFX.WIN : SFX.LOSE); + if (this.scoreTxts[player.seat]) this.scoreTxts[player.seat].setText(''); + } + + animateAllChips(onComplete) { + const players = this.gs.players.filter(p => p.active); + let done = 0; + const check = () => { done++; if (done >= players.length) onComplete(); }; + for (const p of players) { + if (p.result === 'win') this.animateChipsFromDealer(p.seat, check); + else if (p.result === 'push') this.animateChipReturn(p.seat, check); + else this.animateChipsToDealer(p.seat, check); + } + } + + animateChipsFromDealer(seat, onComplete) { + const { x: bx, y: by } = this.betCirclePos(seat); + const numChips = 3; + let done = 0; + for (let i = 0; i < numChips; i++) { + this.time.delayedCall(i * 60, () => { + const chip = this.add.graphics().setDepth(D.chips + 5); + chip.fillStyle(0xf5d020, 1); chip.fillCircle(0, 0, 12); + chip.x = DEALER_X; chip.y = DEALER_Y; + this.tweens.add({ + targets: chip, x: bx, y: by, duration: 380, ease: 'Power2', + onComplete: () => { chip.destroy(); done++; if (done === numChips) onComplete(); }, + }); + }); + } + } + + animateChipsToDealer(seat, onComplete) { + if (!this.betGraphics[seat]) { onComplete(); return; } + const { x: bx, y: by } = this.betCirclePos(seat); + const numChips = 2; + let done = 0; + for (let i = 0; i < numChips; i++) { + this.time.delayedCall(i * 60, () => { + const chip = this.add.graphics().setDepth(D.chips + 5); + chip.fillStyle(0xe05c5c, 1); chip.fillCircle(0, 0, 12); + chip.x = bx; chip.y = by; + this.tweens.add({ + targets: chip, x: DEALER_X, y: DEALER_Y, duration: 380, ease: 'Power2', + onComplete: () => { chip.destroy(); done++; if (done === numChips) onComplete(); }, + }); + }); + } + } + + animateChipReturn(seat, onComplete) { + // Push — chips return to player from bet circle + if (!this.betGraphics[seat]) { onComplete(); return; } + const bg = this.betGraphics[seat]; + this.tweens.add({ + targets: bg, alpha: 0, duration: 320, ease: 'Power2', + onComplete: () => { onComplete(); }, + }); + } + + async updateServerChips() { + const human = this.gs.players[0]; + const delta = human.chipsWon ?? 0; + if (delta === 0) return; + try { + await api.post('/profile/chips/adjust', { delta }); + } catch { /* silent — local state is still correct */ } + } + + // ── Next round ──────────────────────────────────────────────────────────── + showNextRoundPrompt() { + const human = this.gs.players[0]; + if (human.chips < 5) { + new Modal(this, { + title: 'Out of Chips', + body: 'You ran out of chips. Better luck next time!', + buttons: [{ label: 'Leave', onClick: () => this.scene.start('GameMenu') }], + }); + return; + } + + const btn = new Button(this, CX, GAME_HEIGHT / 2 + 200, 'Next Round', () => { + btn.destroy(); + this.startNewRound(); + }, { width: 220, height: 56, fontSize: 24 }); + btn.setDepth(D.ui + 5); + } +} diff --git a/public/src/games/paigow/PaiGowPokerLogic.js b/public/src/games/paigow/PaiGowPokerLogic.js new file mode 100644 index 0000000..bf390cd --- /dev/null +++ b/public/src/games/paigow/PaiGowPokerLogic.js @@ -0,0 +1,504 @@ +// Pai Gow Poker pure game logic — no Phaser dependencies + +import { SUITS, RANKS } from '../cards/Deck.js'; + +// ─── Card values ─────────────────────────────────────────────────────────────── + +const RANK_VALUE = Object.fromEntries(RANKS.map((r, i) => [r, i + 2])); // 2=2…A=14 + +function makeCard(rank, suit) { + return { + rank, suit, + value: RANK_VALUE[rank], + label: rank === 'T' ? '10' : rank, + isRed: suit === 'h' || suit === 'd', + suitSymbol: { s:'♠', h:'♥', d:'♦', c:'♣' }[suit], + key: `${rank}${suit}`, + isJoker: false, + }; +} + +export function makeJoker() { + return { rank: 'JK', suit: null, value: 15, label: '★', isRed: false, suitSymbol: '★', key: 'JK', isJoker: true }; +} + +export function buildDeck() { + const cards = []; + for (const suit of SUITS) { + for (const rank of RANKS) { + cards.push(makeCard(rank, suit)); + } + } + cards.push(makeJoker()); + for (let i = cards.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [cards[i], cards[j]] = [cards[j], cards[i]]; + } + return cards; +} + +// ─── Hand rank constants ─────────────────────────────────────────────────────── + +export const HAND_RANK = { + HIGH_CARD: -1, + ONE_PAIR: 0, + TWO_PAIR: 1, + THREE_OF_A_KIND: 2, + STRAIGHT: 3, + FLUSH: 4, + FULL_HOUSE: 5, + FOUR_OF_A_KIND: 6, + STRAIGHT_FLUSH: 7, + ROYAL_FLUSH: 8, + FIVE_ACES: 9, +}; + +// ─── Helpers ─────────────────────────────────────────────────────────────────── + +function cardVal(c) { return c.isJoker ? 14 : c.value; } + +export function rankLabel(val) { + const labels = { 14:'Ace', 13:'King', 12:'Queen', 11:'Jack', 10:'10', + 9:'9', 8:'8', 7:'7', 6:'6', 5:'5', 4:'4', 3:'3', 2:'2' }; + return labels[val] ?? String(val); +} + +function getCombinations(arr, k) { + if (k === arr.length) return [[...arr]]; + if (k === 0) return [[]]; + const [first, ...rest] = arr; + const withFirst = getCombinations(rest, k - 1).map(c => [first, ...c]); + const withoutFirst = getCombinations(rest, k); + return [...withFirst, ...withoutFirst]; +} + +// Groups cards by effective rank value; sorted by group size desc, then value desc +function getGroups(cards) { + const map = {}; + for (const c of cards) { + const v = cardVal(c); + if (!map[v]) map[v] = []; + map[v].push(c); + } + return Object.entries(map) + .map(([v, cs]) => ({ value: +v, cards: cs })) + .sort((a, b) => b.cards.length - a.cards.length || b.value - a.value); +} + +function checkStraight(sortedVals) { + const uniq = [...new Set(sortedVals)]; + if (uniq.length < 5) return false; + if (uniq[0] - uniq[4] === 4) return uniq[0]; // returns high card value + // Wheel: A-2-3-4-5 + if (uniq[0] === 14 && uniq[1] === 5 && uniq[2] === 4 && uniq[3] === 3 && uniq[4] === 2) return 5; + return false; +} + +// ─── 5-card evaluation (no Joker) ───────────────────────────────────────────── + +function evaluate5Pure(cards) { + const vals = cards.map(c => c.value).sort((a, b) => b - a); + const suits = cards.map(c => c.suit); + const isFlush = suits.every(s => s === suits[0]); + const straightHigh = checkStraight(vals); + + if (isFlush && straightHigh) { + if (straightHigh === 14) return { rank: HAND_RANK.ROYAL_FLUSH, name: 'Royal Flush', tiebreakers: [14] }; + return { rank: HAND_RANK.STRAIGHT_FLUSH, name: 'Straight Flush', tiebreakers: [straightHigh] }; + } + + const groups = getGroups(cards); + const counts = groups.map(g => g.cards.length); + + if (counts[0] === 4) { + return { rank: HAND_RANK.FOUR_OF_A_KIND, name: 'Four of a Kind', tiebreakers: [groups[0].value, groups[1].value] }; + } + if (counts[0] === 3 && counts[1] === 2) { + return { rank: HAND_RANK.FULL_HOUSE, name: 'Full House', tiebreakers: [groups[0].value, groups[1].value] }; + } + if (isFlush) { + return { rank: HAND_RANK.FLUSH, name: 'Flush', tiebreakers: vals }; + } + if (straightHigh) { + return { rank: HAND_RANK.STRAIGHT, name: 'Straight', tiebreakers: [straightHigh] }; + } + if (counts[0] === 3) { + return { rank: HAND_RANK.THREE_OF_A_KIND, name: 'Three of a Kind', tiebreakers: [groups[0].value, groups[1].value, groups[2].value] }; + } + if (counts[0] === 2 && counts[1] === 2) { + return { rank: HAND_RANK.TWO_PAIR, name: 'Two Pair', tiebreakers: [groups[0].value, groups[1].value, groups[2].value] }; + } + if (counts[0] === 2) { + return { rank: HAND_RANK.ONE_PAIR, name: 'One Pair', tiebreakers: [groups[0].value, groups[1].value, groups[2].value, groups[3].value] }; + } + return { rank: HAND_RANK.HIGH_CARD, name: 'High Card', tiebreakers: vals }; +} + +// ─── 5-card evaluation (Joker aware) ────────────────────────────────────────── + +export function evaluate5Card(cards) { + const joker = cards.find(c => c.isJoker); + if (!joker) return evaluate5Pure(cards); + + const others = cards.filter(c => !c.isJoker); + + // Five Aces: 4 Aces + Joker + if (others.filter(c => c.rank === 'A').length === 4) { + return { rank: HAND_RANK.FIVE_ACES, name: 'Five Aces', tiebreakers: [15, 14, 14, 14, 14] }; + } + + // Brute-force all possible Joker substitutions + const existingKeys = new Set(others.map(c => c.key)); + let best = null; + + for (const suit of SUITS) { + for (const rank of RANKS) { + const sub = makeCard(rank, suit); + if (existingKeys.has(sub.key)) continue; + const hand = [...others, sub]; + const ev = evaluate5Pure(hand); + if (!best || compare5Card(ev, best) > 0) best = ev; + } + } + + // Fallback: Joker as Ace of spades if no non-duplicate substitution works (rare) + return best ?? evaluate5Pure([...others, makeCard('A', 's')]); +} + +export function handName5(ev) { return ev.name; } + +// ─── 2-card evaluation (Joker always = Ace) ─────────────────────────────────── + +export function evaluate2Card(cards) { + const vals = cards.map(c => cardVal(c)).sort((a, b) => b - a); + if (vals[0] === vals[1]) { + return { rank: 1, name: `Pair of ${rankLabel(vals[0])}s`, tiebreakers: [vals[0]] }; + } + return { rank: 0, name: `${rankLabel(vals[0])}-${rankLabel(vals[1])} High`, tiebreakers: vals }; +} + +// ─── Comparison ──────────────────────────────────────────────────────────────── + +export function compare5Card(a, b) { + if (a.rank !== b.rank) return a.rank - b.rank; + for (let i = 0; i < Math.max(a.tiebreakers.length, b.tiebreakers.length); i++) { + const av = a.tiebreakers[i] ?? 0; + const bv = b.tiebreakers[i] ?? 0; + if (av !== bv) return av - bv; + } + return 0; +} + +export function compare2Card(a, b) { + if (a.rank !== b.rank) return a.rank - b.rank; + for (let i = 0; i < Math.max(a.tiebreakers.length, b.tiebreakers.length); i++) { + const av = a.tiebreakers[i] ?? 0; + const bv = b.tiebreakers[i] ?? 0; + if (av !== bv) return av - bv; + } + return 0; +} + +// ─── Foul detection ──────────────────────────────────────────────────────────── + +export function isFoul(highHand5, lowHand2) { + const high = evaluate5Card(highHand5); + const low = evaluate2Card(lowHand2); + + // Any 5-card rank above ONE_PAIR always beats any 2-card hand + if (high.rank > HAND_RANK.ONE_PAIR) return false; + + if (high.rank === HAND_RANK.ONE_PAIR) { + // 5-card pair vs 2-card high card: always valid + if (low.rank === 0) return false; + // Both pairs: foul only if 5-card pair rank is strictly less (equal is OK — kickers decide) + return high.tiebreakers[0] < low.tiebreakers[0]; + } + + // 5-card HIGH_CARD: foul if low hand has a pair, or if 5-card top card < 2-card top card + if (low.rank === 1) return true; // pair beats high card + const highTop2 = high.tiebreakers.slice(0, 2); + for (let i = 0; i < 2; i++) { + if (highTop2[i] > (low.tiebreakers[i] ?? 0)) return false; + if (highTop2[i] < (low.tiebreakers[i] ?? 0)) return true; + } + return false; // equal top 2: not foul (5-card wins on kickers) +} + +// ─── House Way ───────────────────────────────────────────────────────────────── + +function sortByValDesc(cards) { + return [...cards].sort((a, b) => cardVal(b) - cardVal(a)); +} + +function bestFiveCombo(cards) { + const combos = getCombinations(cards, 5); + let bestEval = null, bestCards = null; + for (const c of combos) { + const ev = evaluate5Card(c); + if (!bestEval || compare5Card(ev, bestEval) > 0) { bestEval = ev; bestCards = c; } + } + return { eval: bestEval, cards: bestCards }; +} + +export function houseWay(sevenCards) { + // Five Aces: keep in high + const joker = sevenCards.find(c => c.isJoker); + const aces = sevenCards.filter(c => c.rank === 'A'); + if (joker && aces.length >= 4) { + const high5 = [...aces.slice(0, 4), joker]; + const low2 = sevenCards.filter(c => !high5.includes(c)); + return { highHand: high5, lowHand: low2 }; + } + + const groups = getGroups(sevenCards); + const numPairs = groups.filter(g => g.cards.length === 2).length; + const numTrips = groups.filter(g => g.cards.length === 3).length; + const numQuads = groups.filter(g => g.cards.length === 4).length; + + const { eval: bestEval, cards: bestCombo } = bestFiveCombo(sevenCards); + const lowCards = sevenCards.filter(c => !bestCombo.includes(c)); + + // Straight flush / royal flush: keep in high + if (bestEval.rank >= HAND_RANK.STRAIGHT_FLUSH) { + return { highHand: bestCombo, lowHand: lowCards }; + } + + // Four of a kind + if (numQuads > 0) { + const quadGroup = groups.find(g => g.cards.length >= 4); + const quads = quadGroup.cards; + const qVal = quadGroup.value; + const rest = sortByValDesc(sevenCards.filter(c => !quads.includes(c))); + + // 2s–6s: keep quads together + if (qVal <= 6) return { highHand: [...quads, rest[0]], lowHand: [rest[1], rest[2]] }; + + // 7s–10s: split only if Ace-equivalent available for low + if (qVal <= 10) { + const hasAce = rest.some(c => cardVal(c) >= 14); + if (!hasAce) return { highHand: [...quads, rest[0]], lowHand: [rest[1], rest[2]] }; + } + + // JJ–AA (and 7-10 with Ace): split into pair+pair + return { highHand: [quads[0], quads[1], ...rest], lowHand: [quads[2], quads[3]] }; + } + + // Full house + if (bestEval.rank === HAND_RANK.FULL_HOUSE) { + const tripsGroup = groups.find(g => g.cards.length >= 3); + const pairGroup = groups.find(g => g !== tripsGroup && g.cards.length >= 2); + const trips3 = tripsGroup.cards.slice(0, 3); + const pair2 = pairGroup.cards.slice(0, 2); + const extras = sevenCards.filter(c => !trips3.includes(c) && !pair2.includes(c)); + return { highHand: [...trips3, ...extras], lowHand: pair2 }; + } + + // Flush (no sf) — keep flush in high + if (bestEval.rank === HAND_RANK.FLUSH) { + return { highHand: bestCombo, lowHand: lowCards }; + } + + // Straight (no flush) — keep straight in high + if (bestEval.rank === HAND_RANK.STRAIGHT) { + return { highHand: bestCombo, lowHand: lowCards }; + } + + // Three of a kind + if (numTrips > 0 && numPairs === 0) { + const tripsGroup = groups.find(g => g.cards.length >= 3); + const trips3 = tripsGroup.cards.slice(0, 3); + + // Three Aces: pair in high, one Ace in low + if (tripsGroup.value === 14) { + const rest = sortByValDesc(sevenCards.filter(c => !trips3.includes(c))); + return { highHand: [trips3[0], trips3[1], ...rest.slice(0, 3)], lowHand: [trips3[2], rest[3]] }; + } + + // Other trips: trips in high, 2 best singletons in low + const rest = sortByValDesc(sevenCards.filter(c => !trips3.includes(c))); + return { highHand: [...trips3, ...rest.slice(2)], lowHand: [rest[0], rest[1]] }; + } + + // Three pair + const pairGroups = groups.filter(g => g.cards.length >= 2).slice(0, 3); + if (pairGroups.length >= 3) { + // Highest pair → low hand; other two pairs + singleton in high + const highestPair = pairGroups[0]; // already sorted by value desc + const lowPairCards = highestPair.cards.slice(0, 2); + const remainPairs = sevenCards.filter(c => !lowPairCards.includes(c)); + const { eval: bestRemEval, cards: bestRemCombo } = bestFiveCombo(remainPairs); + return { highHand: bestRemCombo, lowHand: lowPairCards }; + } + + // Two pair + if (numPairs >= 2) { + const pg1 = pairGroups[0]; // higher pair + const pg2 = pairGroups[1]; // lower pair + const p1Cards = pg1.cards.slice(0, 2); + const p2Cards = pg2.cards.slice(0, 2); + const singletons = sortByValDesc(sevenCards.filter(c => !p1Cards.includes(c) && !p2Cards.includes(c))); + + if (pg1.value >= 11) { + // JJ+ high pair: split — HIGH pair → HIGH 5-card hand, LOW pair → LOW 2-card hand + return { highHand: [...p1Cards, ...singletons], lowHand: p2Cards }; + } + // Both pairs ≤ 10: keep together in high, 2 best singletons in low + return { highHand: [...p1Cards, ...p2Cards, singletons[2]], lowHand: [singletons[0], singletons[1]] }; + } + + // One pair + if (numPairs === 1) { + const pg = pairGroups[0]; + const pCards = pg.cards.slice(0, 2); + const singletons = sortByValDesc(sevenCards.filter(c => !pCards.includes(c))); + // 2 best singletons in low + return { highHand: [...pCards, ...singletons.slice(2)], lowHand: [singletons[0], singletons[1]] }; + } + + // No pair (HIGH_CARD): 2nd and 3rd best in low + const sorted = sortByValDesc(sevenCards); + return { highHand: [sorted[0], sorted[3], sorted[4], sorted[5], sorted[6]], lowHand: [sorted[1], sorted[2]] }; +} + +// ─── State creation ──────────────────────────────────────────────────────────── + +export function createInitialState(opponents, chips) { + const players = [ + { + seat: 0, name: 'You', isHuman: true, active: true, opponent: null, + chips, bet: 0, + hand: [], highHand: [], lowHand: [], + highEval: null, lowEval: null, + isFoul: false, result: null, chipsWon: 0, + }, + ]; + + for (let i = 0; i < 5; i++) { + const opp = opponents[i] ?? null; + players.push({ + seat: i + 1, name: opp?.name ?? '', isHuman: false, active: !!opp, opponent: opp, + chips: 1000, bet: 0, + hand: [], highHand: [], lowHand: [], + highEval: null, lowEval: null, + isFoul: false, result: null, chipsWon: 0, + }); + } + + return { + phase: 'betting', + deck: [], + players, + dealer: { hand: [], highHand: [], lowHand: [], highEval: null, lowEval: null, revealed: false }, + roundNumber: 0, + }; +} + +// ─── Round management ────────────────────────────────────────────────────────── + +export function prepareRound(gs) { + const deck = buildDeck(); + const players = gs.players.map(p => ({ + ...p, + bet: 0, hand: [], highHand: [], lowHand: [], + highEval: null, lowEval: null, + isFoul: false, result: null, chipsWon: 0, + })); + return { + ...gs, + phase: 'betting', + deck, + players, + dealer: { hand: [], highHand: [], lowHand: [], highEval: null, lowEval: null, revealed: false }, + roundNumber: gs.roundNumber + 1, + }; +} + +export function applyBet(gs, seat, amount) { + const players = gs.players.map(p => p.seat === seat ? { ...p, bet: amount } : p); + return { ...gs, players }; +} + +export function dealHands(gs) { + const deck = [...gs.deck]; + const players = gs.players.map(p => { + if (!p.active) return p; + const hand = deck.splice(0, 7); + return { ...p, hand }; + }); + const dealerHand = deck.splice(0, 7); + return { + ...gs, + phase: 'setting', + deck, + players, + dealer: { ...gs.dealer, hand: dealerHand }, + }; +} + +export function applyHumanSplit(gs, highHand, lowHand) { + const foul = isFoul(highHand, lowHand); + const highEval = foul ? null : evaluate5Card(highHand); + const lowEval = foul ? null : evaluate2Card(lowHand); + const players = gs.players.map(p => { + if (p.seat !== 0) return p; + return { ...p, highHand, lowHand, highEval, lowEval, isFoul: foul }; + }); + return { ...gs, players }; +} + +export function applyHouseWaySplit(gs, seat) { + const player = gs.players.find(p => p.seat === seat); + if (!player || !player.active) return gs; + const { highHand, lowHand } = houseWay(player.hand); + const highEval = evaluate5Card(highHand); + const lowEval = evaluate2Card(lowHand); + const players = gs.players.map(p => p.seat === seat ? { ...p, highHand, lowHand, highEval, lowEval, isFoul: false } : p); + return { ...gs, players }; +} + +export function applyDealerHouseWay(gs) { + const { highHand, lowHand } = houseWay(gs.dealer.hand); + const highEval = evaluate5Card(highHand); + const lowEval = evaluate2Card(lowHand); + return { ...gs, dealer: { ...gs.dealer, highHand, lowHand, highEval, lowEval } }; +} + +// ─── Resolution ──────────────────────────────────────────────────────────────── + +// Returns 'win' | 'push' | 'lose'. Ties go to dealer (copy rule). +function resolvePlayer(player, dealer) { + if (player.isFoul) return 'foul'; + + const highCmp = compare5Card(player.highEval, dealer.highEval); + const lowCmp = compare2Card(player.lowEval, dealer.lowEval); + + // copy rule: ties go to dealer (cmp <= 0 means dealer wins or ties) + const winHigh = highCmp > 0; + const winLow = lowCmp > 0; + + if (winHigh && winLow) return 'win'; + if (!winHigh && !winLow) return 'lose'; + return 'push'; +} + +export function resolveRound(gs) { + const dealer = gs.dealer; + const COMMISSION = 0.05; + + const players = gs.players.map(p => { + if (!p.active || p.bet === 0) return p; + + const result = resolvePlayer(p, dealer); + let chipsWon = 0; + if (result === 'win') { + chipsWon = p.bet - Math.floor(p.bet * COMMISSION); + } else if (result === 'lose' || result === 'foul') { + chipsWon = -p.bet; + } + + return { ...p, result, chipsWon, chips: p.chips + chipsWon }; + }); + + return { ...gs, phase: 'resolved', players }; +} diff --git a/public/src/games/stratego/StrategoGame.js b/public/src/games/stratego/StrategoGame.js index cc82977..2ffa8f0 100644 --- a/public/src/games/stratego/StrategoGame.js +++ b/public/src/games/stratego/StrategoGame.js @@ -747,6 +747,19 @@ export default class StrategoGame extends Phaser.Scene { // Map result to containers. const attackerIsHuman = mover.owner === this.humanSeat; let winnerCont, loserCont, winnerTxt, loserTxt; + + // Portrait emotion: AI upset when it loses a high-value piece; happy when it captures one. + const REACT_RANK = 6; + const aiLosesPiece = res === 'both' || + (res === 'attacker' && attackerIsHuman) || + (res === 'defender' && !attackerIsHuman); + const aiCapturesPiece = (res === 'attacker' && !attackerIsHuman) || + (res === 'defender' && attackerIsHuman); + const triggerEmotion = () => { + const ctrl = this.portraits[this.aiSeat]; + if (aiLosesPiece && aiPiece.rank >= REACT_RANK) ctrl?.playEmotion?.('upset'); + else if (aiCapturesPiece && humanPiece.rank >= REACT_RANK) ctrl?.playEmotion?.('happy'); + }; if (res === 'attacker') { [winnerCont, loserCont] = attackerIsHuman ? [humanCont, aiCont] : [aiCont, humanCont]; [winnerTxt, loserTxt] = attackerIsHuman ? [humanRankTxt, aiRankTxt] : [aiRankTxt, humanRankTxt]; @@ -805,13 +818,16 @@ export default class StrategoGame extends Phaser.Scene { if (res === 'both') { // Tie: both shoot simultaneously, both explode/fade. + let emotionFired = false; fireShot(humanStageX, STAGE_CY, aiStageX, STAGE_CY, () => { this._spawnExplosions(aiStageX, STAGE_CY); fadeOut(aiCont, aiRankTxt); + if (!emotionFired) { emotionFired = true; triggerEmotion(); } }); fireShot(aiStageX, STAGE_CY, humanStageX, STAGE_CY, () => { this._spawnExplosions(humanStageX, STAGE_CY); fadeOut(humanCont, humanRankTxt); + if (!emotionFired) { emotionFired = true; triggerEmotion(); } }); // After both explosions settle, fade outcome label and undim. this.time.delayedCall(2700, () => { @@ -828,6 +844,7 @@ export default class StrategoGame extends Phaser.Scene { fireShot(winnerX, STAGE_CY, loserX, STAGE_CY, () => { this._spawnExplosions(loserX, STAGE_CY); fadeOut(loserCont, loserTxt); + triggerEmotion(); finishWinner(); }); } diff --git a/public/src/main.js b/public/src/main.js index a2c408a..329ba66 100644 --- a/public/src/main.js +++ b/public/src/main.js @@ -83,6 +83,7 @@ import RiskGame from './games/risk/RiskGame.js'; import GeniusSquareGame from './games/geniussquare/GeniusSquareGame.js'; import KataminoGame from './games/katamino/KataminoGame.js'; import BookworkGame from './games/bookwork/BookworkGame.js'; +import PaiGowPokerGame from './games/paigow/PaiGowPokerGame.js'; const config = { type: Phaser.AUTO, @@ -179,6 +180,7 @@ const config = { GeniusSquareGame, KataminoGame, BookworkGame, + PaiGowPokerGame, ], }; diff --git a/public/src/scenes/GameRoomScene.js b/public/src/scenes/GameRoomScene.js index dfb6f22..5dd7128 100644 --- a/public/src/scenes/GameRoomScene.js +++ b/public/src/scenes/GameRoomScene.js @@ -22,7 +22,7 @@ export default class GameRoomScene extends Phaser.Scene { } create() { - const slugDispatch = { backgammon: 'Backgammon', holdem: 'HoldemGame', blackjack: 'BlackjackGame', parchisi: 'ParchisiGame', yatzi: 'YatziGame', skipbo: 'SkipBoGame', phase10: 'Phase10Game', chinesecheckers: 'ChineseCheckersGame', gofish: 'GoFishGame', uno: 'UnoGame', craps: 'CrapsGame', roulette: 'RouletteGame', mexicantrain: 'MexicanTrainGame', hearts: 'HeartsGame', catan: 'CatanGame', tickettoride: 'TicketToRideGame', nerts: 'NertsGame', bingo: 'BingoGame', baccarat: 'BaccaratGame', dominion: 'DominionGame', checkers: 'CheckersGame', chess: 'ChessGame', wordle: 'WordleGame', scrabble: 'ScrabbleGame', ghost: 'GhostGame', wordladder: 'WordLadderGame', wordsearch: 'WordSearchGame', hangman: 'HangmanGame', sudoku: 'SudokuGame', othello: 'OthelloGame', go: 'GoGame', battleship: 'BattleshipGame', mastermind: 'MastermindGame', connect4: 'Connect4Game', boggle: 'BoggleGame', oldmaid: 'OldMaidGame', blokus: 'BlokusGame', spellingbee: 'SpellingBeeGame', minicrossword: 'MiniCrosswordGame', forbiddenisland: 'ForbiddenIslandGame', solitairetour: 'SolitaireTourGame', splendor: 'SplendorGame', tectonic: 'TectonicGame', labyrinth: 'LabyrinthGame', videopoker: 'VideoPokerGame', farkel: 'FarkelGame', stratego: 'StrategoGame', kiitos: 'KiitosGame', monopoly: 'MonopolyGame', triominoes: 'TriominoesGame', freecell: 'FreecellGame', rushhour: 'RushHourGame', hexsweeper: 'HexsweeperGame', puddingmonsters: 'PuddingMonstersGame', shift: 'ShiftGame', blockfighter: 'BlockFighterGame', mahjongmatch: 'MahjongMatchGame', mahjong: 'MahjongGame', jewelquest: 'JewelQuestGame', zuma: 'ZumaGame', bejeweled: 'BejeweledGame', minimotorways: 'MiniMotorwaysGame', slots: 'SlotsGame', cribbage: 'CribbageGame', canasta: 'CanastaGame', dotlink: 'DotLinkGame', '2048': '2048Game', rummikub: 'RummikubGame', ginrummy: 'GinRummyGame', risk: 'RiskGame', geniussquare: 'GeniusSquareGame', katamino: 'KataminoGame', bookwork: 'BookworkGame' }; + const slugDispatch = { backgammon: 'Backgammon', holdem: 'HoldemGame', blackjack: 'BlackjackGame', parchisi: 'ParchisiGame', yatzi: 'YatziGame', skipbo: 'SkipBoGame', phase10: 'Phase10Game', chinesecheckers: 'ChineseCheckersGame', gofish: 'GoFishGame', uno: 'UnoGame', craps: 'CrapsGame', roulette: 'RouletteGame', mexicantrain: 'MexicanTrainGame', hearts: 'HeartsGame', catan: 'CatanGame', tickettoride: 'TicketToRideGame', nerts: 'NertsGame', bingo: 'BingoGame', baccarat: 'BaccaratGame', dominion: 'DominionGame', checkers: 'CheckersGame', chess: 'ChessGame', wordle: 'WordleGame', scrabble: 'ScrabbleGame', ghost: 'GhostGame', wordladder: 'WordLadderGame', wordsearch: 'WordSearchGame', hangman: 'HangmanGame', sudoku: 'SudokuGame', othello: 'OthelloGame', go: 'GoGame', battleship: 'BattleshipGame', mastermind: 'MastermindGame', connect4: 'Connect4Game', boggle: 'BoggleGame', oldmaid: 'OldMaidGame', blokus: 'BlokusGame', spellingbee: 'SpellingBeeGame', minicrossword: 'MiniCrosswordGame', forbiddenisland: 'ForbiddenIslandGame', solitairetour: 'SolitaireTourGame', splendor: 'SplendorGame', tectonic: 'TectonicGame', labyrinth: 'LabyrinthGame', videopoker: 'VideoPokerGame', farkel: 'FarkelGame', stratego: 'StrategoGame', kiitos: 'KiitosGame', monopoly: 'MonopolyGame', triominoes: 'TriominoesGame', freecell: 'FreecellGame', rushhour: 'RushHourGame', hexsweeper: 'HexsweeperGame', puddingmonsters: 'PuddingMonstersGame', shift: 'ShiftGame', blockfighter: 'BlockFighterGame', mahjongmatch: 'MahjongMatchGame', mahjong: 'MahjongGame', jewelquest: 'JewelQuestGame', zuma: 'ZumaGame', bejeweled: 'BejeweledGame', minimotorways: 'MiniMotorwaysGame', slots: 'SlotsGame', cribbage: 'CribbageGame', canasta: 'CanastaGame', dotlink: 'DotLinkGame', '2048': '2048Game', rummikub: 'RummikubGame', ginrummy: 'GinRummyGame', risk: 'RiskGame', geniussquare: 'GeniusSquareGame', katamino: 'KataminoGame', bookwork: 'BookworkGame', paigow: 'PaiGowPokerGame' }; if (slugDispatch[this.game.slug]) { this.scene.start(slugDispatch[this.game.slug], { game: this.game, diff --git a/server/games/registry.js b/server/games/registry.js index c628bcb..024a138 100644 --- a/server/games/registry.js +++ b/server/games/registry.js @@ -99,3 +99,4 @@ registerGame({ slug: 'risk', name: 'Risk', category: 'tabletop', minPlayers: 2, registerGame({ slug: 'geniussquare', name: 'Genius Square', category: 'logic', minPlayers: 1, maxPlayers: 2, minOpponents: 1, maxOpponents: 1, iconFrame: 70 }); registerGame({ slug: 'katamino', name: 'Katamino', category: 'logic', minPlayers: 1, maxPlayers: 1, minOpponents: 0, maxOpponents: 0, iconFrame: 71 }); registerGame({ slug: 'bookwork', name: 'Bookwork', category: 'word', minPlayers: 1, maxPlayers: 1, minOpponents: 0, maxOpponents: 0, iconFrame: 72 }); +registerGame({ slug: 'paigow', name: 'Pai Gow Poker', category: 'casino', cardGame: true, minPlayers: 1, maxPlayers: 6, minOpponents: 0, maxOpponents: 5, defaultOpponents: 5, iconFrame: 73 }); diff --git a/verifyPaiGowPoker.js b/verifyPaiGowPoker.js new file mode 100644 index 0000000..21d614a --- /dev/null +++ b/verifyPaiGowPoker.js @@ -0,0 +1,486 @@ +#!/usr/bin/env node +// verifyPaiGowPoker.js — engine tests for Pai Gow Poker + +import { + HAND_RANK, makeJoker, buildDeck, + evaluate5Card, evaluate2Card, + compare5Card, compare2Card, + isFoul, houseWay, + createInitialState, prepareRound, applyBet, dealHands, + applyHouseWaySplit, applyDealerHouseWay, applyHumanSplit, resolveRound, + rankLabel, +} from './public/src/games/paigow/PaiGowPokerLogic.js'; +import { chooseBet } from './public/src/games/paigow/PaiGowPokerAI.js'; +import { SUITS, RANKS } from './public/src/games/cards/Deck.js'; + +let pass = 0, fail = 0; +function ok(label, cond) { + if (cond) { console.log(` ✓ ${label}`); pass++; } + else { console.error(` ✗ ${label}`); fail++; } +} + +function card(rank, suit) { + const RANK_VALUE = Object.fromEntries(RANKS.map((r, i) => [r, i + 2])); + return { rank, suit, value: RANK_VALUE[rank], label: rank === 'T' ? '10' : rank, + isRed: suit === 'h' || suit === 'd', suitSymbol: { s:'♠',h:'♥',d:'♦',c:'♣' }[suit], + key: `${rank}${suit}`, isJoker: false }; +} + +// ── Deck ────────────────────────────────────────────────────────────────────── +console.log('\nDeck'); +const deck = buildDeck(); +ok('deck has 53 cards', deck.length === 53); +ok('deck contains one Joker', deck.filter(c => c.isJoker).length === 1); +ok('Joker has correct key', deck.find(c => c.isJoker)?.key === 'JK'); +const nonJoker = deck.filter(c => !c.isJoker); +ok('52 standard cards present', nonJoker.length === 52); +const keys = new Set(nonJoker.map(c => c.key)); +ok('all standard keys unique', keys.size === 52); +// Deck should be shuffled (not in insertion order) +const firstRank = deck[0].rank; +const allSame = deck.slice(0, 13).every(c => c.rank === firstRank); +ok('deck is shuffled (not all same rank in first 13)', !allSame); + +// ── 5-card eval — standard hands ───────────────────────────────────────────── +console.log('\n5-card evaluation — standard hands'); + +const royalFlush = [card('A','s'), card('K','s'), card('Q','s'), card('J','s'), card('T','s')]; +const ev = evaluate5Card(royalFlush); +ok('Royal Flush detected', ev.rank === HAND_RANK.ROYAL_FLUSH); +ok('Royal Flush name', ev.name === 'Royal Flush'); + +const sf = [card('9','h'), card('8','h'), card('7','h'), card('6','h'), card('5','h')]; +const sfEv = evaluate5Card(sf); +ok('Straight Flush detected', sfEv.rank === HAND_RANK.STRAIGHT_FLUSH); +ok('Straight Flush tiebreaker = 9', sfEv.tiebreakers[0] === 9); + +const quads = [card('A','s'), card('A','h'), card('A','d'), card('A','c'), card('K','s')]; +const qEv = evaluate5Card(quads); +ok('Four of a Kind detected', qEv.rank === HAND_RANK.FOUR_OF_A_KIND); +ok('Quads tiebreakers [14,13]', qEv.tiebreakers[0] === 14 && qEv.tiebreakers[1] === 13); + +const fh = [card('K','s'), card('K','h'), card('K','d'), card('Q','s'), card('Q','h')]; +ok('Full House detected', evaluate5Card(fh).rank === HAND_RANK.FULL_HOUSE); + +const flush = [card('A','h'), card('J','h'), card('9','h'), card('6','h'), card('2','h')]; +ok('Flush detected', evaluate5Card(flush).rank === HAND_RANK.FLUSH); + +const straight = [card('9','s'), card('8','h'), card('7','d'), card('6','c'), card('5','s')]; +ok('Straight detected', evaluate5Card(straight).rank === HAND_RANK.STRAIGHT); +ok('Straight tiebreaker = 9', evaluate5Card(straight).tiebreakers[0] === 9); + +// Wheel (A-2-3-4-5) +const wheel = [card('A','s'), card('2','h'), card('3','d'), card('4','c'), card('5','s')]; +const wheelEv = evaluate5Card(wheel); +ok('Wheel straight detected', wheelEv.rank === HAND_RANK.STRAIGHT); +ok('Wheel tiebreaker = 5', wheelEv.tiebreakers[0] === 5); + +const trips = [card('Q','s'), card('Q','h'), card('Q','d'), card('7','c'), card('3','s')]; +ok('Three of a Kind detected', evaluate5Card(trips).rank === HAND_RANK.THREE_OF_A_KIND); + +const twoPair = [card('A','s'), card('A','h'), card('K','d'), card('K','c'), card('J','s')]; +ok('Two Pair detected', evaluate5Card(twoPair).rank === HAND_RANK.TWO_PAIR); + +const onePair = [card('T','s'), card('T','h'), card('A','d'), card('K','c'), card('Q','s')]; +ok('One Pair detected', evaluate5Card(onePair).rank === HAND_RANK.ONE_PAIR); + +const hiCard = [card('A','s'), card('K','h'), card('Q','d'), card('J','c'), card('9','s')]; +ok('High Card detected', evaluate5Card(hiCard).rank === HAND_RANK.HIGH_CARD); + +// Flush SF distinction (non-SF flush) +const sfDistinct = [card('K','s'), card('Q','s'), card('J','s'), card('T','s'), card('8','s')]; +ok('Non-consecutive flush is Flush not SF', evaluate5Card(sfDistinct).rank === HAND_RANK.FLUSH); + +// ── 5-card eval — Joker ─────────────────────────────────────────────────────── +console.log('\n5-card evaluation — Joker'); +const joker = makeJoker(); + +// Five Aces +const fiveAces = [card('A','s'), card('A','h'), card('A','d'), card('A','c'), joker]; +const faEv = evaluate5Card(fiveAces); +ok('Five Aces detected', faEv.rank === HAND_RANK.FIVE_ACES); +ok('Five Aces name', faEv.name === 'Five Aces'); + +// Joker completes a flush +const flushWithJoker = [card('K','h'), card('J','h'), card('9','h'), card('6','h'), joker]; +const fjEv = evaluate5Card(flushWithJoker); +ok('Joker completes flush', fjEv.rank === HAND_RANK.FLUSH); + +// Joker completes a straight +const stWithJoker = [card('9','s'), card('8','h'), card('7','d'), card('6','c'), joker]; +const sjEv = evaluate5Card(stWithJoker); +ok('Joker completes straight', sjEv.rank === HAND_RANK.STRAIGHT); + +// Joker completes a straight flush +const sfWithJoker = [card('9','h'), card('8','h'), card('7','h'), card('6','h'), joker]; +const sfJEv = evaluate5Card(sfWithJoker); +ok('Joker completes straight flush', sfJEv.rank === HAND_RANK.STRAIGHT_FLUSH); + +// Joker as Ace (no better use in a scattered hand) +const jokerAlone = [card('K','s'), card('Q','h'), card('J','d'), card('9','c'), joker]; +const jaEv = evaluate5Card(jokerAlone); +// K-Q-J-9 + Joker can complete K-Q-J-T-9 straight with Joker as T → STRAIGHT +ok('Joker completes a straight when possible', jaEv.rank >= HAND_RANK.STRAIGHT); + +// Joker with one Ace in a hand that can make a straight (AKQJ+Joker=T → STRAIGHT) +const jokerAceStr = [card('A','s'), card('K','h'), card('Q','d'), card('J','c'), joker]; +const jaStr = evaluate5Card(jokerAceStr); +ok('Joker+AKQJ makes a straight (Joker=T)', jaStr.rank === HAND_RANK.STRAIGHT); + +// Joker with one Ace in a hand that cannot make straight or flush → pair of Aces +const jokerAcePair = [card('A','s'), card('9','h'), card('7','d'), card('5','c'), joker]; +const jaPair = evaluate5Card(jokerAcePair); +ok('Joker + Ace (no straight/flush) = pair of Aces', jaPair.rank === HAND_RANK.ONE_PAIR && jaPair.tiebreakers[0] === 14); + +// ── 2-card evaluation ───────────────────────────────────────────────────────── +console.log('\n2-card evaluation'); +const pairKings = [card('K','s'), card('K','h')]; +const hiCardAQ = [card('A','s'), card('Q','h')]; +ok('pair beats high card', compare2Card(evaluate2Card(pairKings), evaluate2Card(hiCardAQ)) > 0); + +const pairAces = [card('A','s'), card('A','h')]; +ok('pair of Aces beats pair of Kings', compare2Card(evaluate2Card(pairAces), evaluate2Card(pairKings)) > 0); + +const AK = [card('A','s'), card('K','h')]; +const AQ = [card('A','h'), card('Q','d')]; +ok('A-K beats A-Q', compare2Card(evaluate2Card(AK), evaluate2Card(AQ)) > 0); + +const jokerK = [joker, card('K','s')]; +const jokerKEv = evaluate2Card(jokerK); +ok('Joker in 2-card hand = Ace (Ace-King)', jokerKEv.rank === 0 && jokerKEv.tiebreakers[0] === 14); + +// Pair of Joker+Ace (Joker treated as Ace) +const jokerAceLow2 = [joker, card('A','s')]; +const jokerAceEv = evaluate2Card(jokerAceLow2); +ok('Joker + Ace in 2-card = pair of Aces', jokerAceEv.rank === 1 && jokerAceEv.tiebreakers[0] === 14); + +// ── compare5Card / compare2Card ──────────────────────────────────────────────── +console.log('\nComparison'); +const sfEval = evaluate5Card(sf); +const flushEval = evaluate5Card(flush); +ok('compare5Card: SF beats Flush', compare5Card(sfEval, flushEval) > 0); + +const pairAcesEv = evaluate5Card([card('A','s'), card('A','h'), card('K','d'), card('Q','c'), card('J','s')]); +const pairKingsEv = evaluate5Card([card('K','s'), card('K','h'), card('A','d'), card('Q','c'), card('J','s')]); +ok('compare5Card: pair Aces > pair Kings', compare5Card(pairAcesEv, pairKingsEv) > 0); + +ok('compare5Card: tie returns 0', compare5Card(pairAcesEv, pairAcesEv) === 0); + +const p2 = evaluate2Card([card('A','s'), card('K','h')]); +const p3 = evaluate2Card([card('A','h'), card('K','d')]); +ok('compare2Card: equal high cards returns 0', compare2Card(p2, p3) === 0); + +// ── Foul detection ───────────────────────────────────────────────────────────── +console.log('\nFoul detection'); + +// Valid: 5-card pair of 2s, 2-card A-K +const valid5 = [card('2','s'), card('2','h'), card('A','d'), card('K','c'), card('Q','s')]; +const valid2 = [card('A','s'), card('K','h')]; +ok('pair of 2s vs A-K high card: NOT foul', !isFoul(valid5, valid2)); + +// Foul: 5-card A-K-Q-J-9 high card, 2-card pair of Kings +const foul5 = [card('A','s'), card('K','h'), card('Q','d'), card('J','c'), card('9','s')]; +const foul2 = [card('K','s'), card('K','d')]; +ok('high card 5-card vs pair of Kings 2-card: IS foul', isFoul(foul5, foul2)); + +// Foul: 5-card pair of Kings, 2-card pair of Aces +const foul5b = [card('K','s'), card('K','h'), card('Q','d'), card('J','c'), card('9','s')]; +const foul2b = [card('A','s'), card('A','h')]; +ok('pair of Kings high vs pair of Aces low: IS foul', isFoul(foul5b, foul2b)); + +// Valid: 5-card pair of Aces, 2-card pair of Kings +const valid5b = [card('A','s'), card('A','h'), card('K','d'), card('Q','c'), card('J','s')]; +const valid2b = [card('K','s'), card('K','h')]; +ok('pair of Aces vs pair of Kings: NOT foul', !isFoul(valid5b, valid2b)); + +// Equal pairs: NOT a foul (5-card hand wins on kickers; this case only arises with quads) +const equalP5 = [card('K','d'), card('K','c'), card('Q','s'), card('J','h'), card('9','s')]; +const equalP2 = [card('K','s'), card('K','h')]; +ok('pair of Kings vs pair of Kings: NOT foul (equal rank, 5-card wins on kickers)', !isFoul(equalP5, equalP2)); + +// ── House Way ────────────────────────────────────────────────────────────────── +console.log('\nHouse Way — No Pair'); +const noPair7 = [card('A','s'), card('Q','h'), card('J','d'), card('9','c'), card('8','s'), card('6','h'), card('3','d')]; +const hwNP = houseWay(noPair7); +ok('no pair: high hand has 5 cards', hwNP.highHand.length === 5); +ok('no pair: low hand has 2 cards', hwNP.lowHand.length === 2); +ok('no pair: Ace in high hand', hwNP.highHand.some(c => c.rank === 'A')); +// 2nd/3rd best (Q, J) should be in low hand +ok('no pair: Q in low hand', hwNP.lowHand.some(c => c.rank === 'Q')); +ok('no pair: split not foul', !isFoul(hwNP.highHand, hwNP.lowHand)); + +console.log('\nHouse Way — One Pair'); +// Hand with no straight/flush possible so pair rule is exercised cleanly +const onePair7 = [card('7','s'), card('7','h'), card('A','d'), card('K','c'), card('9','s'), card('5','h'), card('3','d')]; +const hwOP = houseWay(onePair7); +ok('one pair: high hand has pair', evaluate5Card(hwOP.highHand).rank >= HAND_RANK.ONE_PAIR); +ok('one pair: A in low hand (best 2 singletons)', hwOP.lowHand.some(c => c.rank === 'A')); +ok('one pair: K in low hand', hwOP.lowHand.some(c => c.rank === 'K')); +ok('one pair: split not foul', !isFoul(hwOP.highHand, hwOP.lowHand)); + +console.log('\nHouse Way — Two Pair'); +// Both pairs ≤ 6s: keep together +const tp1 = [card('6','s'), card('6','h'), card('4','d'), card('4','c'), card('A','s'), card('K','h'), card('Q','d')]; +const hwTP1 = houseWay(tp1); +ok('two pair (≤6): both pairs in high', evaluate5Card(hwTP1.highHand).rank === HAND_RANK.TWO_PAIR); +ok('two pair (≤6): not foul', !isFoul(hwTP1.highHand, hwTP1.lowHand)); + +// High pair ≥ JJ: split — HIGH pair → HIGH hand, LOW pair → LOW hand +const tp2 = [card('J','s'), card('J','h'), card('5','d'), card('5','c'), card('A','s'), card('K','h'), card('Q','d')]; +const hwTP2 = houseWay(tp2); +ok('two pair (JJ+): JJ in HIGH hand', hwTP2.highHand.some(c => c.rank === 'J')); +ok('two pair (JJ+): low pair (55) in LOW hand', hwTP2.lowHand.every(c => c.rank === '5')); +ok('two pair (JJ+): not foul', !isFoul(hwTP2.highHand, hwTP2.lowHand)); + +// AA + 22: split — AA in HIGH hand, 22 in LOW hand +const tp3 = [card('A','s'), card('A','h'), card('2','d'), card('2','c'), card('K','s'), card('Q','h'), card('J','d')]; +const hwTP3 = houseWay(tp3); +ok('two pair (AA+22): AA in HIGH hand', hwTP3.highHand.some(c => c.rank === 'A')); +ok('two pair (AA+22): 22 in LOW hand', hwTP3.lowHand.every(c => c.rank === '2')); +ok('two pair (AA+22): not foul', !isFoul(hwTP3.highHand, hwTP3.lowHand)); + +console.log('\nHouse Way — Three Pair'); +const threePair = [card('A','s'), card('A','h'), card('K','d'), card('K','c'), card('Q','s'), card('Q','h'), card('J','d')]; +const hwThreePair = houseWay(threePair); +ok('three pair: low hand is a pair', evaluate2Card(hwThreePair.lowHand).rank === 1); +ok('three pair: low hand has highest pair (Aces)', hwThreePair.lowHand.some(c => c.rank === 'A')); +ok('three pair: not foul', !isFoul(hwThreePair.highHand, hwThreePair.lowHand)); + +console.log('\nHouse Way — Three of a Kind'); +const trips7 = [card('8','s'), card('8','h'), card('8','d'), card('A','c'), card('K','s'), card('Q','h'), card('J','d')]; +const hwTrips = houseWay(trips7); +ok('trips (888): trips in high hand', evaluate5Card(hwTrips.highHand).rank === HAND_RANK.THREE_OF_A_KIND); +ok('trips: A in low hand', hwTrips.lowHand.some(c => c.rank === 'A')); +ok('trips: not foul', !isFoul(hwTrips.highHand, hwTrips.lowHand)); + +// Three Aces +const tripsAces = [card('A','s'), card('A','h'), card('A','d'), card('K','c'), card('Q','s'), card('J','h'), card('T','d')]; +const hwTA = houseWay(tripsAces); +ok('three Aces: one Ace in low hand', hwTA.lowHand.some(c => c.rank === 'A')); +ok('three Aces: not foul', !isFoul(hwTA.highHand, hwTA.lowHand)); + +console.log('\nHouse Way — Full House'); +const fullHouse7 = [card('K','s'), card('K','h'), card('K','d'), card('Q','s'), card('Q','h'), card('A','c'), card('J','d')]; +const hwFH = houseWay(fullHouse7); +ok('full house: pair in low hand', evaluate2Card(hwFH.lowHand).rank === 1); +ok('full house: pair of Queens in low', hwFH.lowHand.every(c => c.rank === 'Q')); +ok('full house: trips in high', evaluate5Card(hwFH.highHand).rank === HAND_RANK.THREE_OF_A_KIND); +ok('full house: not foul', !isFoul(hwFH.highHand, hwFH.lowHand)); + +console.log('\nHouse Way — Four of a Kind'); +// Low quads (2s-6s): keep together +const quads6 = [card('6','s'), card('6','h'), card('6','d'), card('6','c'), card('A','s'), card('K','h'), card('Q','d')]; +const hwQ6 = houseWay(quads6); +ok('quads of 6s: all 4 in high hand', hwQ6.highHand.filter(c => c.rank === '6').length === 4); +ok('quads of 6s: not foul', !isFoul(hwQ6.highHand, hwQ6.lowHand)); + +// High quads (Aces): always split +const quadsA = [card('A','s'), card('A','h'), card('A','d'), card('A','c'), card('K','s'), card('Q','h'), card('J','d')]; +const hwQA = houseWay(quadsA); +ok('quads of Aces: split (2 Aces in low)', hwQA.lowHand.filter(c => c.rank === 'A').length === 2); +ok('quads of Aces: 2 Aces in high', hwQA.highHand.filter(c => c.rank === 'A').length === 2); +ok('quads of Aces: not foul', !isFoul(hwQA.highHand, hwQA.lowHand)); + +// Jack quads: split +const quadsJ = [card('J','s'), card('J','h'), card('J','d'), card('J','c'), card('K','s'), card('Q','h'), card('T','d')]; +const hwQJ = houseWay(quadsJ); +ok('quads of Jacks: split', hwQJ.lowHand.filter(c => c.rank === 'J').length === 2); +ok('quads of Jacks: not foul', !isFoul(hwQJ.highHand, hwQJ.lowHand)); + +console.log('\nHouse Way — Five Aces'); +const fiveAces7 = [card('A','s'), card('A','h'), card('A','d'), card('A','c'), makeJoker(), card('K','s'), card('Q','h')]; +const hwFA = houseWay(fiveAces7); +ok('Five Aces: 5 ace-equiv cards in high', hwFA.highHand.length === 5); +ok('Five Aces: Five Aces rank', evaluate5Card(hwFA.highHand).rank === HAND_RANK.FIVE_ACES); +ok('Five Aces: not foul', !isFoul(hwFA.highHand, hwFA.lowHand)); + +// ── State management ─────────────────────────────────────────────────────────── +console.log('\nState management'); +const opponents = Array.from({ length: 3 }, (_, i) => ({ name: `AI${i+1}`, id: i+1 })); +let gs = createInitialState(opponents, 2000); +ok('createInitialState: 6 seats total', gs.players.length === 6); +ok('seat 0 is human', gs.players[0].isHuman); +ok('3 opponents active', gs.players.filter(p => p.active && !p.isHuman).length === 3); +ok('2 empty seats inactive', gs.players.filter(p => !p.active).length === 2); + +gs = prepareRound(gs); +ok('prepareRound: phase = betting', gs.phase === 'betting'); +ok('prepareRound: deck has 53 cards', gs.deck.length === 53); +ok('prepareRound: bets reset', gs.players.every(p => p.bet === 0)); + +gs = applyBet(gs, 0, 25); +ok('applyBet: human bet = 25', gs.players[0].bet === 25); + +gs = dealHands(gs); +ok('dealHands: phase = setting', gs.phase === 'setting'); +ok('human has 7 cards', gs.players[0].hand.length === 7); +ok('AI1 has 7 cards', gs.players[1].hand.length === 7); +ok('dealer has 7 cards', gs.dealer.hand.length === 7); +// 4 active players × 7 + dealer × 7 = 35 cards dealt; 53 - 35 = 18 remaining +ok('4 active players + dealer = 35 cards dealt, 18 remaining', gs.deck.length === 53 - 35); + +// Apply house way to AI +gs = applyHouseWaySplit(gs, 1); +ok('AI1 has highHand of 5', gs.players[1].highHand.length === 5); +ok('AI1 has lowHand of 2', gs.players[1].lowHand.length === 2); +ok('AI1 not foul', !gs.players[1].isFoul); + +gs = applyDealerHouseWay(gs); +ok('dealer has highHand of 5', gs.dealer.highHand.length === 5); +ok('dealer has lowHand of 2', gs.dealer.lowHand.length === 2); + +// Human sets hands (use house way for simplicity in test) +const hwHuman = houseWay(gs.players[0].hand); +gs = applyHumanSplit(gs, hwHuman.highHand, hwHuman.lowHand); +ok('human has highHand of 5', gs.players[0].highHand.length === 5); +ok('human not foul', !gs.players[0].isFoul); + +// Apply house way to remaining AI seats too +for (let s = 2; s <= 5; s++) { + if (gs.players[s].active) gs = applyHouseWaySplit(gs, s); +} + +gs = resolveRound(gs); +ok('resolveRound: phase = resolved', gs.phase === 'resolved'); +ok('human has a result', ['win','push','lose','foul'].includes(gs.players[0].result)); + +// ── Resolution — chips math ─────────────────────────────────────────────────── +console.log('\nResolution — chips math'); + +// Simulate a known win (human wins both hands) +{ + let testGs = createInitialState([{ name: 'Bot' }], 1000); + testGs = prepareRound(testGs); + testGs = applyBet(testGs, 0, 100); + testGs = dealHands(testGs); + + // Force-set human and dealer hands for a guaranteed win + const winHigh = [card('A','s'), card('A','h'), card('A','d'), card('K','s'), card('K','h')]; // FH + const winLow = [card('Q','s'), card('Q','h')]; // pair of Qs + const looseHigh = [card('2','s'), card('3','h'), card('5','d'), card('7','c'), card('9','s')]; // garbage + const looseLow = [card('4','s'), card('6','h')]; + + testGs = { ...testGs, players: testGs.players.map(p => p.seat === 0 + ? { ...p, highHand: winHigh, lowHand: winLow, + highEval: { rank: HAND_RANK.FULL_HOUSE, name: 'Full House', tiebreakers: [14, 13] }, + lowEval: { rank: 1, tiebreakers: [12] }, isFoul: false } + : p), }; + testGs = { ...testGs, dealer: { ...testGs.dealer, highHand: looseHigh, lowHand: looseLow, + highEval: evaluate5Card(looseHigh), lowEval: evaluate2Card(looseLow) } }; + testGs = applyHouseWaySplit(testGs, 1); + testGs = resolveRound(testGs); + + ok('win result: chipsWon = 95 (100 - 5% commission)', testGs.players[0].chipsWon === 95); + ok('win result: chips increased', testGs.players[0].chips === 1095); +} + +// Simulate a known loss +{ + let testGs = createInitialState([{ name: 'Bot' }], 1000); + testGs = prepareRound(testGs); + testGs = applyBet(testGs, 0, 50); + testGs = dealHands(testGs); + + const loseHigh = [card('2','s'), card('3','h'), card('5','d'), card('7','c'), card('9','s')]; + const loseLow = [card('4','s'), card('6','h')]; + const winHigh = [card('A','s'), card('A','h'), card('A','d'), card('K','s'), card('K','h')]; + const winLow = [card('Q','s'), card('Q','h')]; + + testGs = { ...testGs, players: testGs.players.map(p => p.seat === 0 + ? { ...p, highHand: loseHigh, lowHand: loseLow, + highEval: evaluate5Card(loseHigh), lowEval: evaluate2Card(loseLow), isFoul: false } + : p) }; + testGs = { ...testGs, dealer: { ...testGs.dealer, highHand: winHigh, lowHand: winLow, + highEval: { rank: HAND_RANK.FULL_HOUSE, name: 'Full House', tiebreakers: [14, 13] }, + lowEval: { rank: 1, tiebreakers: [12] } } }; + testGs = applyHouseWaySplit(testGs, 1); + testGs = resolveRound(testGs); + + ok('lose result: chipsWon = -50', testGs.players[0].chipsWon === -50); + ok('lose result: chips = 950', testGs.players[0].chips === 950); +} + +// Push: player wins high, loses low +{ + let testGs = createInitialState([{ name: 'Bot' }], 1000); + testGs = prepareRound(testGs); + testGs = applyBet(testGs, 0, 25); + testGs = dealHands(testGs); + + const pHigh = [card('K','s'), card('K','h'), card('K','d'), card('Q','s'), card('Q','h')]; // FH KKK-QQ + const pLow = [card('3','s'), card('4','h')]; + const dHigh = [card('2','s'), card('3','h'), card('5','d'), card('7','c'), card('9','s')]; // high card + const dLow = [card('A','s'), card('A','h')]; // pair of Aces + + testGs = { ...testGs, + players: testGs.players.map(p => p.seat === 0 + ? { ...p, highHand: pHigh, lowHand: pLow, highEval: evaluate5Card(pHigh), lowEval: evaluate2Card(pLow), isFoul: false } + : p), + dealer: { ...testGs.dealer, highHand: dHigh, lowHand: dLow, highEval: evaluate5Card(dHigh), lowEval: evaluate2Card(dLow) } + }; + testGs = applyHouseWaySplit(testGs, 1); + testGs = resolveRound(testGs); + ok('push result: chipsWon = 0', testGs.players[0].chipsWon === 0); + ok('push result: result = push', testGs.players[0].result === 'push'); +} + +// Foul auto-lose +{ + let testGs = createInitialState([{ name: 'Bot' }], 1000); + testGs = prepareRound(testGs); + testGs = applyBet(testGs, 0, 40); + testGs = dealHands(testGs); + + const foulHighHand = [card('A','s'), card('K','h'), card('Q','d'), card('J','c'), card('9','s')]; + const foulLowHand = [card('A','h'), card('A','d')]; // pair Aces in low, but high hand is high card = foul + testGs = applyHumanSplit(testGs, foulHighHand, foulLowHand); + testGs = applyDealerHouseWay(testGs); + testGs = applyHouseWaySplit(testGs, 1); + testGs = resolveRound(testGs); + ok('foul: auto-lose', testGs.players[0].result === 'foul'); + ok('foul: chipsWon = -40', testGs.players[0].chipsWon === -40); +} + +// Copy rule: tied high hand → dealer wins (push if player wins low) +{ + // Force both high hands to the same rank/tiebreakers + let testGs = createInitialState([{ name: 'Bot' }], 1000); + testGs = prepareRound(testGs); + testGs = applyBet(testGs, 0, 20); + testGs = dealHands(testGs); + + const sameHighEval = { rank: HAND_RANK.FLUSH, name: 'Flush', tiebreakers: [14, 12, 10, 8, 6] }; + const winLowEval = { rank: 1, tiebreakers: [13] }; // pair Kings + const loseLowEval = { rank: 0, tiebreakers: [12, 10] }; // Q-T high + + testGs = { ...testGs, + players: testGs.players.map(p => p.seat === 0 + ? { ...p, highHand: [], lowHand: [], highEval: sameHighEval, lowEval: winLowEval, isFoul: false } + : p), + dealer: { ...testGs.dealer, highHand: [], lowHand: [], highEval: sameHighEval, lowEval: loseLowEval } + }; + testGs = applyHouseWaySplit(testGs, 1); + testGs = resolveRound(testGs); + // Player wins low (pair K > Q-T), dealer wins high (tie → dealer). Push overall. + ok('copy rule: tied high + player wins low = push', testGs.players[0].result === 'push'); +} + +// ── AI bet ──────────────────────────────────────────────────────────────────── +console.log('\nAI bet'); +const aiPlayer = { chips: 500 }; +const bets = Array.from({ length: 100 }, () => chooseBet(aiPlayer)); +ok('chooseBet: all in range [5, 100]', bets.every(b => b >= 5 && b <= 100)); +ok('chooseBet: never exceeds chips (500)', bets.every(b => b <= 500)); + +const poorPlayer = { chips: 7 }; +const poorBets = Array.from({ length: 20 }, () => chooseBet(poorPlayer)); +ok('chooseBet: never exceeds player chips (7)', poorBets.every(b => b <= 7)); + +// ── Deck coverage ───────────────────────────────────────────────────────────── +console.log('\nDeck coverage'); +// 6 players + dealer × 7 = 49 cards ≤ 53 +ok('max 5 AI opponents: 6 players + dealer = 49 cards dealt ≤ 53', 6 * 7 + 7 <= 53); + +// ── Summary ──────────────────────────────────────────────────────────────────── +console.log(`\n ${pass} passed, ${fail} failed\n`); +if (fail > 0) process.exit(1);