From f6992c8cab2ff4424cf29fce8bbf342d79f5b811 Mon Sep 17 00:00:00 2001 From: thuret Date: Wed, 23 Oct 2024 11:58:29 +0200 Subject: [PATCH] first commit --- TP01/JeuNim.pdf | Bin 0 -> 50512 bytes TP01/Nim.ipynb | 496 ++++++++++++++++++++++++++++++++++++++++++++++++ TP01/code.py | 197 +++++++++++++++++++ 3 files changed, 693 insertions(+) create mode 100644 TP01/JeuNim.pdf create mode 100644 TP01/Nim.ipynb create mode 100644 TP01/code.py diff --git a/TP01/JeuNim.pdf b/TP01/JeuNim.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b0b97f8865203652a54bc9d80e7711ab039ebadd GIT binary patch literal 50512 zcmY!laBIthJulynT3L#9anKlQEFl?R|VtJNZ<9hkBQ#>93HbkdS!)VvBhD< z%mv-obeqKd9xPzm)Y06u?3wN51s*fy+dlJenshz3WM=&3SnmAa(N%4SC4=-QeVXCW zpc;Et`krO+`<>6@_Ak$WVcRNVBzIcHQ}bMsm+`Vq0bW_Awce(-)fWr3tR6jHt-Wq7 z|Av3}{&a|kCB{!{OO#UknDHy=pH%9kPM1^_OK+p8Dj_m2{H-4yTDRr>!FLYl%d9`& zxNDpHV_Mn!7y8yaa^{|M64O-Od@*yW#bm9W&x!>uZGBoWv+!i)q6g1g{Vh&y)^9xE z>~7ROsWlAf+tFR4jhD~c$%q;i;DGeU|}g27#F(*a4YM+;MI zLO##pQaiXvgC*ed{Er4ng&Hb6m(Ou`*VZMJ%?i_87;z$$YyP>M$P-WZ>=fb*wlSS{ zk~#fg+_}J_Z69kcXYM(x*c{r`yL*0Q5C4tVx{nUub`@bd^M&WIhIho2BNv4ZYXtkG z9JrM%k!l#+8PNFsY-C2`qV2i~U(EX3ZresgsL6|2a2=TMA{hTjqkvf}BPc-FLXYf{{1Rf%}-5cZ?0SVE!p%fhVJ*;-7P-pBo{Vah(DsVX{Kt^ac`N*o)eR~ z1fS2#(y=)u5F2bTX}eCrmu;+l=gbzT>7;$PJhz9RTSj?~mzz!WBMHeXPNK={HE&FG z(dlV%EIV{DTFj#AHj{h$?7-sPk9&ms?y+|-ey*)jnKJ2*SiY;~r&zhwK;7BgGkt;YUhKQuBYf3M&+TizaYxxb+3 zhsXO_j{Ld@q`Y2z`7!mA?$Rwk4gRg>whD6&@9X|0b6fYE$eF1LEII#Pou8uM_b4KE z4R?y+)^x6hm;a3au&+2fyL{LC7hj*v*uI3Z#ASB>H(&WaQ60gsyAN4ppI+stH2&y>$-Ua^AbT$fqw&$@==vBBR{7Oj@{y2EvD#`SL; z8*JmF*3yHjud}4TRfXK1Hs{Uj z8%^GO&MH67x_w6P9{XX{`~T#UG7CAPU$8z2nZ_9t*(NpVX!<6thBcp9O0=)I96C->fTU*FW&Z>e#aRetqrU$CD# zfB9=)*Y-+As~c>7#kMD{4J`aymoK`hxZ%;CrxVLrAB9}+@I7qbn)iFpnw5Ec`3uy) z&(94qu1YQX^?1hd@+;eYZwgkVE^RKHW%S})hHTB|=C$wocD*>w|7*d+^*fjqU&!?s zR$6*rS$;sY`KgP})YVGHPU!`{HP7{o52e1Fwb1nHA(7taUxa?X;kdcy@Migy^QUe3 zzs6*7{cLVl?KMZW-9AYDwYs`fTh4A*z~>jcH_qq@ZTjYW(|N}C)YZ`e>aw#oy*u-M zn)UbjA2(ihPSu+-vm!>k)R4tR=Iqf&nSOGn6*Xn6%s)O~#GCrIII_|D;KIYV_q_Qk zD_i7pCqOz&_I=&b{wCvd;g2fVc-Cz>^-`|ze3+YL_>1QY*5}=SxL8AYn$fofoEKP~ z-a1Eq;ms@P*{*r#*r$9$lZ3aW(Th|3uJ003STR#0cIJ!;zVBwXam#&bkCL7e@c*|^ z;Qy-6rI-C>mfKI0wd0TYsF?2^^Zi!Jgv>)hQ-7TLv&G_czkBRllfUUg744gTUwQRE z=(9faOyApr$CFpT{+r(#sCG!>N>1z{xzgR~U!KcEMw;8c+i_yIb&ZU`$J)rLbMvJC zu%$#RoA$h4ygi~b|FvFJQ;<_*+UGJ0yG0`9XZ><*uROKA@}lCgZuQ=|!H<6B95|ys z?Q@U1XxtYs#ZO^HE82a0IA!MWYc0Dn)Aiqdcfp(6oiFnHsVlX9^NpQ<;3@}ac5Yv8 z=Y*?pESEV`<~)i${Vpf&|E`0l)^zOU-`v6fCm`8y!7jUqgK^i{wQrp6i$AvTxISOlv$o^E zAGrLvQ~qOdm8ia|_rxmhoa>}tGdsVkqPCMc zH@zjQV`4*~O>i4)-IF)c2e&GlADPvA`~dH{XFQ*$Sss37cxRFKx7RUkz14rWO_ct0 z@>%`^w)En*%G1K`d3N(ROqYF8$vwCC&biwu^*ZwtXIxG+uP$eAuSxz@OH*^GHdSMW=#ZC|zRJMUTpsf#6R^W#mc zm8$}lELSq!e*Btp^vo63^SE?O?#9*S*!PNN$380Vd043w?kCB2HsSZ9sk~h7EBy_w z6fFJMwXW{Uf!@v^@oHQDwu)w>xYCGDVW2U#tIfNrip?jh{i6ycQknQ+%7$PeMg)U67pMtT1z9XmwnFk6neV5d-%;eM{cP9mS8`8|s2zx6N zxnVhXT6swDO|ka#d(HP=5K>Z5{UTMxsc^~KLzE@3)3YIfsjWq=%!SoWL{KvF0a1{vMCKfAjhF>o?Qi*IwVn5b&po zpmE?T4X z_{jR4Z_A%)?>;$Wy4sV4QjzB*_n6G<*&T3img>XBJuC}jW~e?$UtGhUx;Mmg7Q@r; z8kaBsnB&7>ATl%l%yYGcIh{tXB9iYqKQS?IOgUn?r--lnr)9=GhKgnBPr6t-J(HFR zUZ0Wq^u>v^UmrII|4cH}o^sgtVMm3}`7c{|`V7Py*5^-iWmJvKotZK5?OK_)ZzHcg z%lNtf=6$)k;J>yfs(y!lRC{xNo@39v$on~O*68mQWB8^LHCuM`zNw)MTXNYPo<3aT z|6YON6Dz}(dviX^wdKT3I`W7|oxA(Zo19|C`Pq8fFU)_>Z^}Qlzs>Ud%+v3FhgmNZ zw{KMT6g5tDeY$MLMM<#rIos4l)T%U@uv~Wzwi; zz@(GFE7M?HzKst(}(%CV__iMse<=NdL8mqT&}0sW6CBJJ-6A-oKe{+gh)`h^RLq{J zw1jD;>#PZUOQd)9dQ2>Q!pzpbFmZ;2*fGh+?U6kXlfn|OC3zWKosm2v%t!p0S(<=x z~45{nD?RD$BI2#_e9<|@gFSykW{0%kE>p$UhaOs{IUJ&6F8$-vYYr7rzxo9 zsDubeaXjbv+ah?#B(QOXe~D6?K;@B`B+ZR|HyrnP%BcBG7V&IT5f4()oVlej#4}4N zR?Svzuj1sBRw?d95|IvZ{_9lcE5xhvPqGh~qM;_@?hX&8UjLT; z*})We(BWWk)Cry1caV(vB^@TdZ!S-ZGGNH(&Dm^5mCCzsSGX`-L-AH8uLF##5Q6QcpLZ3Sv8C zknqDeNOEb<aFfQzx;gpyz_J8P5wXm)BbA1uFk3*zp}m_er5Y=veYc8 zeNvKAp;FULj+si%%A0j^*3((fO^$ELh~nPL67@9d`PMjtsWac52}x7k+-dvLjvzqfvbe*F5t_Y3U;=dYc=WWW3V z==xI!E-2he=ysfaaK*x|h5HldB`$uLth{RC>Wf;7qZV5qvq;`n*!9uwakSco&bgkG zJbO?22H&`HFC<~t`7P&pvY%zBnXES5eSFb|JCTuV+^#LKJZy8KW^v{0pW58E-4We$ z#qNs5>%7$o)_tubAE_D18j-u@)rMb(ZylMH9h+Qxye;c-^5%2P?mpYPcBSt9vi)ys zt!Kq&trD=YW0nm zJ(u5~8+lIi9Phcs+&tnR#INW|6kRNQxI?CBqF#z#Pkcqe!YiS-r#_B){p*bH_1@=Y zM{)Oqf>j_K>eCx)-zKIwbX`>glN?X2uN?RxEm z_m%BiU90~i@h{WgvR`*UU;ps@*Y)52EEX(lIA3rrVR2&#W4Gfr;uK;nWjTD1@!;+z zdHqZADlu2Yn4JDNm$lk(n)1Yo{wkKx(=l12_NH=2XhmH`Ig4(RtBdoI-5&iXE}d}i z?iKSED|b8Te$@4vUJ|=@B}So1eJ#MD-{vvlWw<7Ohq(D_Z&e(p~TN$8R2S zJ$|QW95Ze6n_ER&pRPQ8e%*xlgOP<=a?{o^?c0a@3{3r>8AKkjZaoinJ{Isrt!*) zE6--OZ27U}vXg3J*9PraV_WsT`iD&x8#wPem3j4DsPH0(ixYh`iX+o@&*=N-^VOqA zWwvT_B=_d5P508>Q|F%wJR|t*%ad78@=nX1{Cx6vooSkBd1?B-vVU!V4w}Bp=3Co( zZC%Xmoqpx92X{UEy6<&=u0pQI%@3#DPWPrt-_Ps1cO`H^;D&t(8JpifJLa_0De&Q5 z-E+}=IY)CubKc%f+q^dG_H?DVi(ivYKk9nquX<-&+l;Xm)5`PTAw@6vBef0sWf z<0!v#_vNn75i^q_<8EG9_aJud(=(qIecHY|{LQ|w#OT5V{>=WA{w+o;HtqFVpXGja z`Ku+b8m0PYJ=^=Ldi&eCw~pVwzW;u1{bj~p=A-O(aw0N&>Q8(R$X@H1do=OR!!?J` zzh3le*Z%bS_&3cW-rHdi+p-=~e41*UeX$Pcb{xJL%ZQ$A!o9|33KYTrIr% zWq|SGoj+JC6fHkKI{ric{X8C)f`)EVJ6D`u@v? z%X4MV$?DqA{$KN@=iAI#n@^>CpPzV6bk1zc`Q>$=oQ}1A?CunAw+b(@+qLD%rMc@i zth;x*ar*kWk2{N2-roEBPw4d3>FX?Gt!wAj?tR<#xA&Ud?s?PV-_&Kk-1iGPf5%N|@8|F(}=_G5II@ z({tCe?QdSMPwKZjwrJx{U7nOB%jeB|m2~xWcz%)h|0U6Gc<$=szuulHaKN?ix+8JjtXrGYmW$9 z!NlPgb&Y9t$tn>$Eq9yHwXa$xPIH;ITKF(Jh!e6x6R#j#Mk+;yqbp3OX<{7q4%XN!!MVOrk{{v#0{e3=i;_#F-j zZYgQy; z(W%f?OEezqXekE96l$umoibt(-{j%d5fZl5F-FtRV~T5>X{uoL&+;Opito%vS_D!9 zr*iQJJqr{Q4t-W}ZvoS~;!v@bT8mWJ6iy{JEE1{Gcv$oCoZut-|Bh@+FJ-D0iKYi| zO%*E*Qw=otUb5j#&dr~XrhB-=UM=!cR1V}~Zrl4~3M2EQ>PhAO0^-hdoL3r8sf)a| z_mFkt)u2-u!dQ*%~IaJ zoWWG#L(tWCEbj08rnKy|zJK{q{BPg;7k~bpw5mt!?xdDwN7cVy%AFQ+VbR;@-?w^8 z?(&}9u=IZBRv(dT_rG5^Uu}CKceBc#!rSZFt=@k~-&7wL)ERpA)un%>dtYu3zb;$b z|CXWN{jS6Ne|z^Hs?NK%`>fH=UcdkE@;)gapR((~-c~J5)p;u}D#zQuNV+{R` ze8ujjnOF+7Yi_yeyl&zN(@(!rv+uVrPZrJ+-@V7qPvafy#J0F^#5YbFYJX=JGlEl z^X@%rToCwn{jNllsdsZv9+&)QwCKxpPNm$Km$$bR&pdnD&Sm|yO%;*fF6OWIab5C7 zKHUB7vhN#j9xrITL-xfW4bp9Kcssz`0)8}=!b5>?<-<{|BT)9xh8Q75(*Yo`Q>&^Xl%a(jjlUTVoE3aHOSNhMri>1b2 z;sxAy%f0)xdtYR!!uAPfCO0Q~n#gU76p%T+W&bX&&XxMwtEU^Dnz?&dkQFO?^FoGge$Y# z_IpTvTIG>weC%w-gyum0>YbU!Qb84Gx>^+ZlXdP_CUBoBkou>Td1AFv?uiJ6XzLp{ z9gP&qer$fcOt8JZ<lrR%`*RXmye5MZNbI(cV^$-$@srmb~E7nN@mHkx!3oYG&7~$jhyl+Zf-!G)6snO zFL84M%AADk%Wi+$V0>`Cf2GT@YqRdo{LsGSh=p=seB_7ilbq|bCuzoo*l7o=q@42q zeb8jiMW(oBiMjjkIaV+_l}kA$i&%*~|F`L;Z|fW?(`5qnY0~{$@&l`t+T*&8JP5g#@LOeRB5vW@P%VI%4tQsY?t;t$1wVxTSRtZ%oTKXeuPK%&Q z>6h-=Z{rqB(%Zf8wu8#T*Y9Fh+fMTOe5L(V;#!Uy?weoaT+UVeY}ho@@Jy%53%-PP z{dYop-bq&9wm5tC+3Ak0Z8|YGj7=v^dND(1zUQvCmN0##8}308LNBxLE6i{*58mB! zo4LL-+4=_)Bg^au+%1_|=`TNTp1t1i(7#MJ)tK0@i$8v6Z{WY)_t=eFa;Tmnm^mFP4(G$~zlqViZ)JbAG=5#+i=Ik^{$+tU65mjDG9!eeN)6-fl2$%kNE^iyCI|%lZ1g zKNHaVZ)RSzaMrQH?Jw>2?=p@}zp_8@>_QK{@69tAo)tE>bWE3II~;j&>+7@2vbV2G zkPkSpBl~uq%vzS>Ne?#2{+~XX%Y71L+U=Y3K5p`-;X`cn$B6$ zD{gbo<1qJ^W@Qt0*H_1@rkyJ&etcF=>+mnLdtW=Gf3R+zdLcFH$?>ztI}_p_UGqtK zbVn-vX=9s>tG@7!&UcM=*8YJTZarSFGjGE!VY9=`w*{o1oiXci$vJ%Eh*_F``X%G- z43)>S`fontTy2}^Y_oxv_57SxcLt?(oB=MTaIpyUQni zb_sHvx^egOi!_Vh59aW{=Wz{U`N#d_=&6lMF3X&~E9E7d{p)O9T1Dy1XR80i8}oV2 zf7$gh`2*{*y}swCteC<4pZlp~?K)7y588%L z4<9`SHzJXSkGY~jBe}5QV+Cx($6zyHmeOtf*i^xgzyPwDf+2WZnM*$;1Ui@u8icm9 z1BDyNy@sFxW)K4uT6i1Gh8CuvQDSIdS1`VfJewzdQgGk-;42ejZoGYYf9A(rVd?HS ziXH-t)g5BphL)4uAM~G*Z#!}91kR`VbJnfl-T z&q2)_qN($yS0=K*c={zU)a}Kg(3B+_THzvFA}-78dA$1gQu12P#1>_- z`fxA(l=aJZrgma+ZUf6}!N#=@nzxJkP2DNHNr(53*9NC2t@C;wPyHbDLqhL?KIN}V^Y?@gA9 zF7+;&AmO>_M1;`M4qwCWYs>F+>8UtwsrYbcg%|$*Aq8R>71z2 zBiO9FFZ0N<1shBKj=eZM;l{!#y=EFhu{_%(Ha}QmBH3H!P?GJS;Cw*rO2usK=J0Snj<5Y*B_vx92ec>i{ zj0c%#SaB_Ixxe+?P7}eUYg?{d6X*NCZ_CnvuwQ&a^L%ePMdW@t(k18_IdP*(M^E9I zMPFAQy4k*Df#|z{&<9od+AdM-E5|%n&e1tL zOLpz7zH7Jt-ksxB6K6hq-{Lak^B*`PTsK!;)hm4Vbxz%~Zh7^ehs3LsjL#(Po;7c7 zv{X2svgbx6PU z*IWM_PXC?YKh^zyx6Co9{>J_7+PCifZ=S__b;}xa*-8In%oY8oGX0$YG%db- zdhth@uk)S1{oftwA||DhIzfAmw^zMtv zLft~uN*fm)VF~j5ygTAdQrHzP=f43}{^^E(PoG_$p?`d*b;`-7YhJ$oH+^^ZxY+wff9bjRgaZ}k7pTX1jR-$$&H8Im&P_UgU+`(CV$-Kvms zK|f0OoiraC-#m@?CP$A38qO`O@bMP0;xArvq4GiUO0kJ0r#f#eSk>H?))UGX?LWa_ zom!A?U)M^f=ZSryRWeNKASD+%Zy2=NB!|eT%}t*6ID2D=ae#r@`TaK^%w2l5=g6^@ zo3yxo39|@I(tNex{FiT!-=6w@-{1LR?T!5CUAKR&^6(bEdr5oO#M^nVO7HRsWh|Kg z`N=HDnPN9i&pocT+j;Y%*|qGN-?TfU>THcBI*^=y+{qS&pCOm>qb6{qB!sH3k+%Q~_;_f>4ltJ3dq4}Hpc&p&X+mSd}q<~%)m%^<&bmZr4W zVgCz0x8BbQJty^L;prDT=W6a}Ec1{qU|7e0HnrfpN_I-3;iSH==c9X43ZG8&DHoj8 zX5A%l`SAZINl#|zJ(~M(bI!uz938GV>T>z7?r%6c+xh;RYj4>~Hr`lQDj#`m=4zE)TsXr|uKeT2gX_KvuecwQFlkX9xB9z3K}kZ6 z{r{$)dY}37R6?un>a3FgCv|Pls83K?QGZ6x^RIkvRNVQ^!qHRH^)DO6br!BpQ(0+! zY|^1*oiMqa*3ej&7dKCD=?PETGdV@&<|+fT+|Z7VJDeNWZdldLA**}2FS~#J(WBzq zv@YDaxp})*LPBEqq~&jg=l)uKU#YuY zy25Y1gI#&sLWbSFd`~Om{(9#8U244WYv3mDgF3c9|4f~I`u7Qj{l9*#|2{#8>GARS zOQokD)xO>CR99`Wt|qI#?1T7qtINJQx447nO8RQ*JwF-sG~P#JYZIs;18tMQ8h{og zt{yM~HSbUwfS^VZX$?TI8L)N~-5P-A3Pzx*{U8PXkPyse10Yd&0}y2ife~^W8E>o4 z*w6%})weYgX_$0FrrGYBD#fRz949bvesk`Y3FB^FrqO+_#^aB`o}JGgT~4S!c<)bj z(Wn0>vp4PDWjgJcGdnlqwlB*fb;MT3?OnBV@&1dls#A_A1y{xegr$W{*{CPHbVc@y z^jjCZr|(^`OWpAAm#@LkmFMg?lYhj%Ji%OV(h`qPIZg9^+g}bkYII#yQ}FrHbH%H+ zf0@oLRAguQUp_YH<X)O%&Pv>bB%?| z`wl;i&`>PmwU__N+yCj2waWuv|5ZN8p;@vo_jH7YW!*AzvpW4K=BJj!6Sx~topb5`M$e3U43hx_taFoz8;pslrzT#x4oGv!@EsR;aa;wpO$X&RFO!5 z;~t(NMVgj9OO|v9Pi!cNk&xs(bYcd-vd>Lz%Zzh7*ypgj2l{Yd>6@n1ku+t|A+DLL z6uPD?YVvO7d8#3$GS&0p;u9VHN;x-!?Ybtfed*OF8O<;7y173|#g(mZnyY~8B&Xw% zaT@Y&nng!UjXTb|xz$J{o}Tw9u|>DL@XC#t{c=&9*zK6Xu(DS9(^vB=KqMNgM3dphUEBBs!u8PBGyRylXcq*w0sB9rpK ziu_$K_Gf&3yW6yLN|^8VWj$e~(d#vj&tLK~`&V7{Zp)n6cQ^EXh&0{uTQ=5o%RyDn zwRY<+7Bl4Ed$YT2$4#>@XJ>KMe7HL6pRc(6nY%xyoK6T_%kp%k6ZhpuQ;t7ieqFeA z+4E=L4EN5dwKI{;)mmj9%HN-H)%?rleUj^6l-WO;T$(a>>JE-`e(6m8#*YnaWq;*} zv{tKr@hJa3_v)T|k*q)dot8Ya_fG1D_qXhtYmf6A%~)UZ^VM4R6Y6*8MrThrc&9!# z`cv)g)D7-6Y`^>DQ$9%EmEBfT{{N>o$FT#6+GQ#xsgYin*C)?a^~~Fnv_jYNy}xQd zLt=`O@(M`<(_L?-yr0=fULNKc^mxHGay!+^_Whl`WZ7 ztJ)T3$M-w??{>cXrS@u>!}W>6^V2Ik-bJt2RI=+EC;!?*rE+oW_?%5`7T;dw%xbr| z>i_=6dokd-}C5+&}kt`ONUEtLs+mIvv{lsp9IpTMO5kP0!vX9WB*fc6m|9^sDJ? zy^|iU)m`m>nD5-)d3n2?Yj-#;WSaZy+=aKtt0zB8m^M4@_PdOF>n*ploE@q!ZxFNU zO!PZ(=GY{sH15oI9WL)~SKVmdq!#w0#<^_HEJx=jnjJT@I@Bdjui`u&A^&22@t<_3 zx9xdr+6C{}nMk)h%=?p3@om@9_W^?2W3zXCXw(Z|uw&^(57SG+kH2QJ_bb7-O*_Z48dCaQ|UjO-aPiEK4yN%!K<=0nL?Z0BbXa1riEB0U5 zfBUSQIp4i&H&64vF*$QSJxo`j)yCb?Y2xvfhtA~xt)l{?m@z6Lnsg_3XU&sJ*QH zL0x+9)ftQA`>xhmq)DE5ylHx4-4DJLh55y6Thq(f1^BUCduy>|S-(pz}uRT(<7D5g9rL zVm~cgkDof0}+p@7c@0J8x+Hcrs^7 z<>|vU2Rsh2_psJHFtAxXx7B{Le3gdX-Q>yLzj)O}b@&$5EnMI^S?OH&b^lKtIXe4V!ww1Vj&4Kum<_3Gty`uan$IO!r}0cT)2v7` zZOgjOeHHUnKkW5c_M!E)QqT{F`(JF+*2d4j|K44vYa+Xu>=_2<%@byRi@Ezy>hRfh zW^XqfcPhW9e>6^cj%|?-^YQ0ye4iir+!xb~%b%oS9waBe>SxjQbi40w?>~zzzPr`z z>hkm*^S10={LFJzX|U(4M@P9TwBn2>l_i3P#W|(~uBY0~6HP#B741u3R+&jYYy-i?7*f zXkmalJHIvJY~LL-p?$A4U){)6G18nk<;m?M22Af0H#4%GNZiXI(wpYyw%ug0yz&X* zC!6NhHrl>ZKKuKPd#Bc>x!Vjk3G%#|xo(-)(f-i*+N18jCdzqE=vW#SIc>6@$y3)H zu7x6BP5-*+?ya%)Sj9H!^Z9_S=jN?UL!&ud~Kg*Lqv;UH*7(#} zzR2MFHTkt*iO$q1GaZ+R|2uS9e?L20IrB=T&d@}kDJPZAwfMX^VP@o@cd})fbH?e% zCguhSt0NURYIO649b$6m+R||&XrhSLv_mYb`8F&qoYZm1Uei@5d!kl^*z?tl>ta~0 zO^u$C`9^ap>msfkBe6>w?`L(|%j-O23c&6YVW0#fpW2e+&AvE`P^NyM-)c1cxF zV!HWev*D&~O4rT4$E?a;FoSc>yIH+QrZKo~s}y;7+VrfB(q6`orA$>5i|q{%nAh-m_1A_q?j)_=YFh9jKs#QL=39fg0Y z%3Ac@FPy28JJI__Vu9$U$Nu^kikc_HZudC&#&zPdmcv4BGdEbeXPi5qxjU%o`IakF z8l{Xl)7QOSk49y?>zj*uc;fEz_Zg2e8yG-ovzU(V7?%`omc0-xF*`phxf}L7FPYL&7P34xpJME z)5|#9Wa0d4rswV6`zV?jNiA~dOgZ{-(g~)^w~YU(zrFWom->lWv3K8lUS5~A$~N_f z2kYKN+uvG5zny+x>(buu{^15A$9mo_SN3iJs*4}EWV?~uo$))P+GHY=Z0yJnp6)OFqq(|ntYiq1{^-fWfEs_)L1 zx&QZ)@72V#$=|=a+^u(1%wBcoW}LrrV`9~k-vRv6GhLDmE+jnko%1I0t^N|h@N%ir zaFs0H4??{^HvLZ3+*YxWXUfHw=S1t|L+mVn+?v>1eL^MR)WbagwzAm!J>QSdIv^UdoDF2Z04!2$GxT%&(huZZ_hp6SN+!ux2`?M+}y2jAy3@I;LBU_ z%!Kvj%pbQ!GT;96*{HMp=+pLv;*(eX-1X_QS??#8T;2Vv+yC`9uKF#s_fC1C_sR6D z-+NE1PI>i^^X2BWb7p538U(7di7U=t_2JdgOE2^Mly`YwUi8mV`1meM86EwCiF%Iv z_i|-@HEcS!x5oRBlSiV|*{@|gzkSbJb8$<2xqHY3Nezx2a&Ao-zrSy3vHKP#f3{Hn zSFUokW(UvIJkjh5<&p?b`B_A)DxOdFPP$@>=8U)(IVs2>!-s4l6 zSE695pzocTQmhcIU$4pJ}#`8S9Q+|mnDFaia6kU}hId<;7DXl#ICpL1eK zVorWKWCv3*Z0k~3YEf}!ex8E9p&odA4XPhxA}l;1kqF)`q#szlh5i;thS*yyX0p%)E33ec#07 zp#0p#JcNi_W>Im8b4Fs3f{CSqzE2_&Cp~8B`->9%`x4wfTXUNn1!(|9zKu$ zgcK$ViMKj0_2}qs6=3HpU|JG4ahoXn?ddL$4jHnmteC>w&h?dHdr|S+eK+q$C?+kr zYkq(B%Ehpa=6-ul{Y zPmbNXe?(pT>7_-|i+%TOaXQp{)b-H?uch0b9=oMyxMSPC2ff+-lE1Z=>gwBnlYCw7 zHPvY1S@o}Nt6tAGRd0E3{^;f_x0|!|eSTHG=##DF{w7*C_fdfnlb?r|XSt+kg+;}~ zZ!z(|;#;n$Px@b5vh#7$zx95<7r0k1IcvyQY30M3vFI~@?c8@;taIN^O!;?t3Y&m? zca8p(9T^W<#b(TvEz5hP8*{|KugKM4U$fnl0#?o!6&I6#O+3hQ?qMj81y7kqh|9Dm zGv67pPL?1P$Q>{0EW-qTO`mYV836kDg*Io&o>{@ziMWBo6Fd{q2Y@tH%|flJw- zperr5+wqK&@6_ubCLM3t(Ar zx1RoD^gYmiO(Y8=%Ojly^LB5q(z=~w$flU38)7@>(+76`->Ub%J`;TY^Ka7T*1FD^ z?e7xjyY%^2zWC6yzdT9G>g3#+>ASpjlBKe@lrcL0m{gV?`G@H=cMJbLhln!=^z9ns zFA9W3)yRFG(l|}{Cz})N=SG3}NZ!H^uFN;XXW3Z3y5s&_T7Wb5{Mxi!!}AWF6C@08 z1PlM#vX;+(fBG?1I!| znsw!&kl*^~kR5L|1!T2;_Drtn+>^I@z4)2g%l6Lgy)|=#rGe?>{`s`$kTgrB7J0KS6cH zL9ZuLNxK~koz8T4DWx6Z`L$)!8CkC<-D!P(ysvGJ$X^hh%pUe{>brP}w)l5!$9D1T zX#Vspph8AbYR}n_c^glPnXm|U@x&y){k5~Yx`?}2E&gQ20Cy6-O9CHG~yIP$#d z?^~+mmU5#*V%Lvt#qlrZ+FvdBof-ABExYB*q9YYrRS8>X81=-ZS%mO;JY`rE^fO|W z+VyXCsZ29-)*oGeK|!YYUy86@x{nmc+lvQWw1l|l?3~lJgzaoR)3=DvpXaAf{rFqh z-u8FZw-58IeoS2c#b8$|X?g1}n!w^EN>WM3&>AVijJF8yOla=!1(qP(f~F zY{mtut5C6-0jNAj6~o6fvj7bP7+{!W3a$su!2=v-rl3mAK*0>m!)2PO8K`@YPm;4(D^4UT|#*fGRTm>kGX5Qg!QXbk@$$tjS;CdnjY0|V5?1t{_{lNKU*K#~hm zWs5aMVXJYC4a^n5m8YSxF=(^0sR5ZauDOK)mKxX8*bt@0wSd<5&>9yMO`yHepv(mF zA2{AX4A7c1SdD9LU}*-gaZL=&L6vqUXk#+!(Kg7Nj;BU)=S&GNv-^JTbaMZ3x$`~j z)i&Sk^N$&SyJ1|%U}nbO&)9r0LFgDO6W_K%CYBAJr}DON?mp%8bW*^|JeNtUy2EZ| zT+I>657kZE#v7;=nsv)##j0CdoL0x0_C{?@)NalB#Zk7u`2YQH372dCT(kdvuXz1= z+xNxq{_6YKTKnrJ9&jk zw(zeTZI$2ep8R;xu+}Gj;oBK34)Wb*TPB_~7T0@~%x$he*RJ}|jO|ks?v$r}S+vpq z?$LN6~V?!5QzU&+J8t><-epNVg{*7yISe1cJT z>-i2H;Tiu=TuOUjw(KIy^Ug^j40k+@G`T_;nJ(|M`E%08+n=w9?_fP`EL*)ObDoRWw~Zdfzw7Jo$zhT+etd9$!p}1t1~$0~4yzqrvPYzNzPZ>vy_@SGjY!0 zp9KZ)E}iMAXRDETTv=5w>Tn_JfEY7_Cj-06#M$E0+ZuR$EncKMSV-_SottR)CfEP1 z+_~otnFUKaj~q8R@!!GchKFM2!VVih&zX+9=dF6`c&fANmc}db{UVvCX2va$Ih-;( zYP#^|8UOWHiRw?{{}6Z6DRh&RRqbq>O_+SVYdbo^ zQ>XsvTzU9Q>E-ri@iX@4?Mv>ASQlNFWSj6;`L%vd?Y7n1>a`4~^GyA-F?O?k-v4QT zMSs8kX8usmiaMq_L={6-$Y(DW|H66 zZJ2g8gEi{*-D%g>Xus%6i%s;6iT^R%y4F}}(;@vED$>}*46fq7XU!(ZRd4LjcW zu9khjndKh4xmm?ew_bc${5(p$PAvC+rN*SpGu!0P@V@6iHY@4%w`I5I*F3uX@^I9W z<*St#z6**(?$Lke*!FeHUItZ@32aHzOoC4}Y3WXi*|^HfaXt5!O^5Oh*3T&NUJgo-HZ)HOJ{niR{aZTjnXpIxnvg&s|v&TwHwlSINzix03EP$6fN@ z|2TK!+}hl)y|FXZjb~4Kc;;Q5nX9Mg(&zpU0u_I;b?f*Dsv7Bk$%(zTxqD@4;NMO2 zWO)iiCcaN>SnlyLj4eX4fIB1dWm9zP9maL9MAk5Qykf}C>}{K?7OQ(E@fz#up3O#6 z+NRj8i&(SuV#(PXM~+04#m`JFE8DVh^Jc;Pd(vOS_tgCSbd^_gVqHMFm0+dvq!*`T z&Xs7&Eo6V$BKODR-~Ql+3yVd9Q>HW>-<2v?ztn9;QmnF-y;Q{qEtjY$$@y%Ln?38; zkNwq)OWm1%F>!K<=Hw@jy8kbYnETa8q3K>~=&Xp1krK-;?3#Z=>Pl6ANv`d!r|}i# z&gGw%&1(Gc^RDmBpGz)fo&RyJA}e8wZRn+KmQmFz7j>TPj`Dt^d&W%3`D>Dw+EbBN z2V{6JpJmco*8F9L(hkl!`MZt%?|jquRyd%=Euwk#5CeB*m0KOp;SG!C7%#Tsa;R=j zY1Gkqk?Xv^K`3{^Hq9${-|YF#V9^#Xx3~4w#HsIHZm)e`D}LygW=G=&ACAx$8{UU$ zozQ(1{-Y*ic8O!<9HTWk`xkHCD=Bwd`Rg|2*&j94zqRfCdg%4WHs?a^CpT1$u5Q~F z5oE#mB(VLZqV=Sc2euhI*B;;XC->~e8K>n}W@Xx0UlsE`(xz{+{G4B^bZz5>uaDd7 z%rAXezVw?D6N@34|`4XGC%E-W|WcKE@W&Q{Deqi3F-03v$Mf{WWj#YZM4o_Uub;oP+y42H! zMx5uAP8)tYz$NX*5;*e&=W68?`Em`m|7~)DRkmT$Hvgi6l`gh?-=3bHs<$vSoAc}D zhXx#r@p&#;E+ga ztXy``mUMYFUGv-f%irH)Y_^E}_u%+n=F6YHiZUsREDe9y9_PJc?$VUymz4I-n#oZt zD5(8$-eDE@A3BqS4#i#j{c)b`=G$z)o*rbszN~c5vbZDbCH5Y?sO|T<`vcc8?Q33j zyuY;@rq1nMlKW%trCzUFac*5-PCndck$F3WYxZ)l2+8!NOlSDqWl~dpcI2h)%jxH| z3cc25lDZ|QB&WDGR<=4uEqcMmwRPwJ-JE-{@8;a8yr!a?YL;wVy?Cuv-1AGh1v+B! zKN@e?Y)k3%t_xoL+xMx~{-0NiA`WkxczD{*H6b!H6NRR(w$Lh@6I#c->v~o1lRNs_ z3ysbB)@l82*Wg+5`AOuq%kh))EhcY@ERuZ?zHQ^Azps~y3l@fEt+`vW!(8N*?Vik) zzFW5}`Cye~J@Jov*^#6e7N0jgwznr*PJJ0*ZxHCY^C<5o*^;7v|DV13^FCr(sjooP zkL(Lu3jqblXg^}YzZ;RpZ0Ns_M1A5isxy% zslPYHFkLZo&t5z2rhboTvZL-!JZ|tGfJaQqkY!5zbyY=E)T%=v- z+zWS%7d~t4S19@xdZks~`B`ttDu(3C+OJikcsAPJinhHm>-7z$q{0S|lM}UF_>z41 zUd0{YI&oEQad>xWPKEATyO4czzpf~@zIFQ&(^LKFlfGVBp*m4h+Ql^b+VpBQ;r3U* zCanzkeN3M1R{3(_y=ytoC!6j)IOEynUH7i-YLi{-`?Ia%zWCOgtJWW@nw@oO5AQo? z)5cP{_2+{g?H0N{>DX3Q8IhT>`xxab7BO^IhdkYU{Xa@b-l*`rTz{Y<0(!Nj9&oNAAc=v((y~=hmE*?Q72s&ENm^ulm{J z|31tu-*2BMCz|S1_r99@|K1Pw`FoFU%W?g)f+bh9q@h=6-qOoy{?a>Bdu^_}@HIbJ zlym0io-Z8I@3Ncw$|M*bqsT)g4h!AWAJ1syyqAZT~HnyEdP5`~SaNn7{vL{;_5w`@L=bZ65-kFr53@fAMii z$ET7ReGm32_x9^W)=2E+l&+DQZ+PzV=^rx=Pu$I=Zy$Epeln61ya4yKhaF8Jt#1IRYF=)h# z%n>*vBfKMU#>S=!AZ%g^8dEYd2aSP2NDv<#8(D(np`u&{3T7stu{$#(Lj^N)5X(Tp z%o5~Q69WSUQ$vtCQv*W<3qvCXa|3e)a{~(nGXu!ToT-JOf+^TGGXqPkBUGS~G*b%$ z1yciK1u$)5sbFkmqF`!dp#Yi)F)}q!0AW)ja|Mu#EzFHU;#{U?1`zcY1`5Vz<_abj z<_gB9h9Efw6R`VD4a^lxEJ0&`AQvKIQwz{=7evI=*aXR4ptJ2@7$T2Jf?Nf{m@=57 zl~~jeH>!u^CXg9M<_H&q_#kX*W{x_B2Z|ERbcsk{kOYS`hKHUUu?^o*ZNkjl#1z}` z9Vp@YCgPef1EnIA;X9B3%#X0)J3|9=0~7f8ovDS9r2^KYsgcL;mPTH8-lLRdJ6~nmu2uVJ;rB?zYt}8L8}IkV%81k~(L8bY z`?vdd|Nniz|Nj4PcWj@Buk6vAC=}uoLYfiEH#{1-GCR?s}^jH)?gdnsB{a z#KZ8eJ9`G(;+-ZQoVAnm7{re6eiglR!4Xa!v2!JcSB-YHzdIltyCAA{hC!K~?Sq-E zJt<$B8_#XzcF%STPH5}Bu~TI3wOfvBYlE`2E2`tF`QFx@nLpPzkTw6~Js=Y{tbIwQl)J}j;WnEaBhO*rNEg} z4iz$+xhPl~luqpu=B__|L%BQr<}v2*%qXsVKwux>nSkh`n1RO4eO`*Sgr^yzY)`+jOs` z?q1#9z4yT4#}yyAlfkO7qp$r-qvrEjZ#;G0L`Cejh}ym_w`AkFr$v2h zWBqm3#LBNN*42BY={zkc;LOqmmvUInvdO;_Ul~!Rzb1Ee^x~u5(=E>3<<7f)>!|ni zS9*zZx4wq%s*`TG__iTeieU}|UqR9vt=%&ij7;*vW!ZPc=83xq}IicE0RJo#^SQ^xKkVO*O6vnFVr(El1R>E4n|86U0V#-dZE^ao8k zymUf^-O2lj%M0EgzjEl^k!ss13G0JZtGjdFgr`ijb18et^3`kpGSy7$KK)?*-9EKC zzF*&5-=f0K@LQ{|{)qAEjN>QR^@DZS28bS;our!-qrW+z;q8*UInR$pzp2ccxJaV= zGGEnZ_G8Z;cNdCfI7cl=FRWoX&SnzuHTr_f3xyEA&;R8TX4k*Ha7V$RP9}GDe(L%i zGoRJ*mArnSCUv3caSl_QMd^$^(q?X4NH6>hW-7itI*vIP9WX5aJEWP>*g90*| zxHa1qqaK`GQy^!ys%@&^)qq?@A&bdp)*D}Tyv>@w@=0v|JGTcS_g`NB>}UQ@{)5B8 z-3ysc>}IaodOLQ;P4k-;)iJB4$W5!$sCTN16~7dFW$%jLYyb6sy>I%1$6xYw@9$oH zkx+42{i;DCs8PSPdk45>DOFBbPU3?_OOn+H!2V^W3hZshOpbF@E3DUoM|v z{I@Hn>~-4wFNKC~36Ir&%io9>-g?Kv|7cUm0N%N%$>9I-W8;1zvipHbCzv!d4p!`RkQA-?6*=A zeih!naA4J{o852Y_TJm1Y_$9PJLC4>Y)#GECgjG~{5)~(i@)^ls8xNvyl&3A3oqRH zafDCx*6ZT!zqh@c?R&rD`wZE$p(l0aX17N#aXHyL`$C8Gg0tT8UI!Dl1 z(Faa*uWeeJpX7bpmHRFue98R6v>B>r_5^yVm4q5kywI27>|EmhBBNdJJD6s2OzEikc5QD|Z z)`P}T5r&li=JEP4h@`m}`TV0~G)VHnwQJu{{Ep>%Vr%68NjoV3QxffTz`|ypYcxOrDvH96W zI}3KlJXsT?Ww~|gl*!$l%s!P*#80?B^FI-zC;89#gyU83b-j9ulexBRn&7$m_Jeb? zl~hs+t6TNjtQC|(W$o8;%bn~{F$!Mlts-}UC5ZjunYZVCOmCb#^!jVfuQ_Vhcnr5Ck_tjSQ@{FlHv1bl8-AEGm(7EFf-}vI*0Y%-V z3Rc}aN_ii)Nyqzj^j9`i#j|Nkm_a+>}POJxFPv0sP@^LzGlnwn#i&xc0q^+Ff5UC-+*%PcL| zKD7JB9kZj)w(U57=IqxaWpk`bwGQqRvKNxw5!qy>=Jt7S&uqmdKi`}&O*!-DEZ3G*MJEoJX{0S%-!!f0yyV-k z^Rgcn+|hVD^QW27+2u1XuDo|@*Q(yc{`rzux;y3+8apjqx`=00LMsk%^lJ=gB| zr>`wk3@UehtgcA(t=<$j<2B>=Lup#9kLDbA?I?^sbfwWdMf*& zf5a7o#1=O}rM+8kGEbLpbZcO`2_uKV5vpQXi*(I>hBe3hI z_R%@1nrGtH|IFiDGHu@yuaXIxZmXlsZtc)0|M&7#@%_l3t0nc^{~uZ&=TqM-S+2D9 z(Jr_B0yVGw6j_ve&n@;o&VKQ!>$Dh|Cyn#1eOcMsGZx%f_v26J%Y^PP8^1Caims30 zj(@jUeM8LAO$rm*rx)(g$=`P?hwI2B<|l5~CYh-pe;88gR-j^kLiDhD!SZvFcNeK< z*j!&BYS7}gsZnO0pO#sw!?VQbCo-#8J8Yb9G+kq6?tZ(@VX;yE1-< zEVxe@r4{pPT$P+29C`1}l{<#nH)g+;T5><{suG_!Pf66n^{!PNgGf5mQbeV|9}6@o>@E}&p5T;Y5L@w zqP!>!LRG)`0( z-P00wsW^98<;~@uY5en?dKb6#H1SwptG(!^;m=~3Hlg&yY%yUQ+sq`Ja>G4_`yTa~ z`ju%JuD^8c()GCL`!(fjAp29^IN##M8(rq%}dD}KBva9xNcO*_hStUUf{UXbCug7@wD^P`9&8U zpYC3>a0x5tlDT)J5>!2`L~mcO{g-kgQP#frS;mFKeaCY9{`Mcc%>VhuM27YMxsA48 z<~mi4?&+f;>$r@q_OwR_slkYB59eiv>CO_80`zGC`j`KD`0PIqU# z7WH3QXaDz#VuALiq^;V4tCi~i&O9P(`)gjUar~qb=`GuiaVQ)8uu8H&RG}v4oOfQC z>l!bs)0G|5Pb(KWJ$a$xYaAG@=J~;W<0&qVM=M*d=Wen6{`4vTX@31W&8>eH{4rdX zT=MtV?3efVd}w;m%DV5Rz2odwv5Ka3X-$%G83(nVPvqKDAUHi*u=C97h#6j*H%>WA zPLfhFd-{MsIA!yh;teZKX?(kJPF_6RYR}i)-FyB|_|Ys?Yb&(j_gmkot{*1{`TjC4 zE}kL$s{WE;$l2ZqCt1%#jwzh1*OU^jrYFyu)_OHHTtDj9=Wk~oc~19BnAmjSQ1OxJ z6EdBidvB<6)I9#$XxG}VsXJ3$SM@Bf7xBNh=Xct#>R;9MAJ67{t^B&9#OANb4Yrxz z7X35QtL5DqAebw?La@TP=CaF-#ailySKs(Z^ogJP;WdwcO}kn5p2}iXC!Lg=@7V4B zePkEA_grf0S^lm0?@MHESr@hE9{I|idVbB?zqLt=bd9dq>`*Uy@`L?Y(!P@_728?v zt^Fj+t}}gkP=bQjw#d#IoAzApI2AZ^{_KKVS*%l2Us$qCz2?(+{QRPs3m&FVTY9~% z&o}p`QEASLt=IoNe%RLbVaI>rAgvA04_AMXpON$8rszKPJ*$@|{%zNKZ&B-ZA>8Zx z=QZ(DbK1(IYEA@BJ#WnxmEbP*zU$)SRgB(Yq0Q^v=QB5ae08_}!?~F}E#-1&?+D52 zcu#C9_D?UoX;kn1#_JcCv|oMeS?`r6udCHtt~~imB<1aMQNFvmg)Y&WPhaR>aIoJl zxc}Adk{J!b6V6_k#dW0_tG``Q7z-!{Z%h!zc+O)~M@zMo5Uu+iAYRdd5RA5*> zan6yv=^RS6?0g$$F|$7ka<|#{Pgc(Qm7ujV%y5r{(Pk)t5-`URmSbLx%{O-Jur@r0zz)@Wlbi=qr z$WW1W>Va8a$DBIZf8KXguk`c_Ra)ofUA%^uIp*A>Df?LGh_)yhX_e1@<$CLrrn$au z*mDL}$#u_iTJs-2Eo9>>F4tImix7S41M(4*|MUMNw7SF%E zYQF7X-oN(p^QSI5zdSx^;pf-!Q-WT$->iN8aZaur+gUZa<1gP{-(xAX^}-Zpku{Z{ z*EU+maGDg|>bB^Wsx1qgoziAmS(e&7|Hf4HYx7xSKl^(mHyPw4AHE;g#2XcuAR>3& zy)My~_4RBS!=JYzRkuuDpC9mAT+Tc>DC?}%dZSfO|Gqi!qEm8y{<9-5PI%s%CzC1u z%;fI6t*Lirh{@d%=XqCMkoa)n-h-OzJg;IZ)}5dEwxM;EeP6?J)quC|I}RUWoBnFU zfsRdU?Cbo`AAf#8R&Cq$qpy$dv65m+kmlQ1yHS4b<(b{5U)ZdSJ8|J)(pBkwhpbmz zpPH5R`j8&0{=_Sve5Q%N`J2-js=t1np8fxtaFbhK_e|MUo%!&?8+Ox<(d{6dxc|10PAZM^aC>a%}KHhu0X-;lViJ|!)~qU^fe^#e&a19a}J?D<~m zs^xRFd$-jw=dF8fWuvWwzIOhu+fzR>vhMTu zzSCm*Y>!;w-nOfS`Nxkv{};Pzg5Uc1X@34i(;EyGtTWk?_e8&&c{yS2ya~)tW^~$` zy^Ba)+V`>k=e5=4bLL)rZ?pZmy1^Xv%lSskxAk+{FJ3w3`%B%5e|DbUmX|d>HQV`4 z&)Oq(@9?=cHuXNE<%gdXbO|rpxbfik`7fd)qAORdZ8@;fOe@hpq3&KUf7eExCnrP2 zjBU>7X9>*-6Fky4~qn%Wu5 zCdW;vV{3nS-r4$N9nFy zl_v!(?lqU^Jv>)+&G_SmollpEJ$OHlpLzfBtu@~q8|Ck7+&TZx=@;jm3g!68xpD2; zi6S+J9PX_!&-$))Y{lIS^D6nbH-CG4Rdv2ou=3Z$y|$a*{M%N1Pw?r+<5L9R@7%^; zbZ1gT`#%;_kDR5SV%w6Y%$*gwoMnF4+^?CesgIkU`W-auY_=9~k7EqJt$ljwm#9;! z4DYw(FVahwRXBF4b^iAHM~|*`eto27d;MGR4DF9^S!Q2&b!g_=sb8btXuo{;=a*>& zgS0^P^`eze80|SUo!{Knih0w?xx?{5b=>)8@7EP^t>2#={yeWgv!K-X?ELohL)Lrk z!#{HDsEBJlZnERV>Zj=+Z1!l)yMM~Qq1iXjL-L*@v{8~0o`{8E+(fNKymj~bfC)RO2XiVV(5+hnAmi|FH;J7Fe@f{P^_5$0m)nn>62SJ@X)W*W4)&ZWsKp$>+QJ zyYiMZ_ZE-pkAbn>KjPB3v)*a=JF+RhIwCI5wNI}*Dfuju=d{by1=suxH@f~(V$pBg z61LfS^)9Qw1io2bJKs}PoBjO!=(iR-io$*iObWM{vEV|39Ph{bE9#Rf)Cz09?z^k4 ze*T}nq>!5%7sk~_pt%m%;5ca$Q?A;Xj^Ra_C8rGgMG>;9^jdL3|j7me;=?dZ97co0Atr%X zAPkcM(dc}T7y*nnJB6$oVH%7DqCptqGn6e}pyY&^U=axpW5x<+I)zMK8FPVmr-Al* zDZuu6nHnmXnOGYyMpQR!0Cq9%o) zDN5g%PHFs;dHuqQ%a~6?)#P9sN0Mp>tBZ__OpK#!dO5qR%%{0O=l{MZE);P6{+oAy zi|*BKpI`lJum0ubamIdGCw(WWY}KC`QnmGm$Q}Jh+hXksucapLbn|(#B{#fBd#{Pk z>A+8Wv{!JPUME|5SzFC_zU0()!+i;lo_H_%Hlw#XDd^>yjJlu3Pv5NeQt##dZ651$ z@7Jr7mzT9aRg<3}{pbCpm+Mb^5 zD<;l;`TgCdn)@lfz4BM34(_?Z)1`Usy85xBF@M(c$hrNVkuYz*X4aR;{|Pfvn7>T8 ztgN9V&&$L9sgb*JrbBrGL&8@}hr=uGOucj9SVVj?(}LTD7pzywd*>DR^d#8qJUg2` zB06c`tv$Ern1ypDe4fkNvw|tM!d~7&T!Kep-?uo9Eo@TE+ult-a82XB+dZKTKjm3- z{uL!KZQ$Qv%FZ;o;p~C91;PaqH-rz?oL-o4LV99}XPLBS`sw3>z1Ee#ZY>Vjb?WC6 z*(Js{Vwu`+pTwM;{8{DxtlC#E=I>oR>7%}y=^maXAL1@wzdk9%^Re#T=|(ESoBl-q zc;R+U_JvaIl5Kyy{HE;+^7oq;;h|Ntdmb@cLJ4zTNz#_|o(x^)n_;zi6BsacoD=Ny+}yn&~qq-Bj3YQSA53 zdFE=P_;Yt=?Nt9fd(D+K!JDH}=gv1(d0q6yO4|3Vzt?du1@Trrp9}+=l@<>+gncwr z+H(4$^P3e1-XtG&IX3s)4!(n*dz_kt9{+h!yUX=*gX*SWwbSQ*lvhQ_PcL%Yuea!g z_TnXrG&EA*iC)RD2)}geM&!b|ovNPpe_Q_fb$tma@cJMX)GlGQTJXE_O|iW*-zk}& z;x!8KdRh{@KK_;VuUYFZr0#P~nZWafE7-s4rQP4XdKaBP&6)DC`drluquRLdi=1R@ zUY6~Rf6tireX;e4%3agT?86ln-*h(Hy`nR0!}sKj$}bKDTXNW@OaJvTe|@%UpEc*6 znxwl=e=)2Nmy(PqZ{T}me!%?Ow3kMXYD|~c#%w%2&#!HBobN7q_srGhrx!j7e)9K3 z_{3oGpor^+m9Ynkez?C=k*`|jbl$k{VJ`O^hbsX*aaZbJT%S(PTWl8>!)3f z{QSPM++%5+u5I&Wr36#C=!b;0o;KemuAel~X1n$r^|g~zH@O|kwO_0srubds?$4vyeMg9x#oXmYQ_>H@U!(Io*y$yb;iFv6)$<1Yn>+~H@t=+Qkh>!8g_2+#| zg@Uq8&Gx@eKHQ@z`sQjd_iOPh3zwBG%J-P|A@k6my?&3r@8!L6)kf`9>5Ln%pKxjK z4oti7xPQlKP18<&9`*j_4pv@KSF=-`J^usm>0MIhiFTeZ`KkBivM)<((l5+ksI6@C zFsGsQdoXL9mmmA>kd===ZoQePbJB=kO{P#%IpIi3{|jNOBll7a-zk?!G(Fn4_V6Lr z7oQi{oqX^3TIBxIWf6Y&%`E1aJ+ZSq>A1?zdDW~+-K|Rx?Vn$_`1tOs_IF2mO{WW9 z;uJT&pmsU@;-=6CTd(-rx~m1&_nNS-_P==H?5{cMoejDA$EKW0uzyv$*FSvm`PPj5 zb$M6I|GZGTlWZN6v@7Mnp~6eiZa*13zWDx{@_0kk&x^BX{*`t4IpJUI|7HCzH}47* ze`%IoT%pcsE}ZABLfCe>8l-gTU3l%g%k%D& zu$hm<5*&AL`Zm)sx5Q?-l)aOqfsKvbLJyboE3V~UlYQ~WUg2<7$6lxTAByXh!Xx=2 zx4kf{_1u4H`;D8aK|126r|xSHIHx3JaOs=*%x7=yB7P=axpnV2v!x5yqW7-9cL-!v z9#pD3*?;Dp`!B^_B z|E8Fk*%DG#_rhOt|8i5Ax@^f$9o1z|Tbyz$y8I3@-&wQp-Ik3EC%wzvd;I(**;;(+ znJ`3+=d+4QQqPrk&;Pv#>%`X-u-ko2?u|J# z+v-vrf5lHbmG6d0eEvep_m13^y18}>%QjuMX%U<`(N2%dzou$Sgyq_V?F?02J!xETGVbMaSEI~B3J&ORR&b_%U*oTGAf=GCCwBUas4Cr#{lcVi-Ji;3V} zCd~`Z?@kz=Ty@7n-!4)vEb7^`7lBWf^H^40a%VWga3Wl;=-PyvN1yavGfjJ;`%>!3 zDlPHq8A}e_ys%66gCJX5`>ygYv0@qR+8Hhzm0wNio_&_LpLv%^l^&Zx-ih! z-<~)>_S%yI&Ij9tvg8k~Jb!E!{}KDL&s+6{6W3n8yG1@>e)rmQr*G?NwCve=w;*M2 zT|(c43(I$hSDV~@{N8l$yk3XPzpG9QZ)Fj^(ct3E`P=k$!J`>=zcicYM&=~#{G0Zi zTR5h>?A_)G6Ps(MT|L9@hsDp zN3Fl0_Gato&-oktNsYz1;kDt7=)Lysn*OYq?-M^|ZeVgX#^@BI@UW?2<-thF( zcduzrah`msf^AcJ(2gy$MC@iya8ge`_*0`~eehMa@OP8u_L|l@==)8R^Z3I0qbhpg z8GCa<^*w8|56|+dzRi`NUn_UbweZ%Rp8|K?Bcs;cetgfaB``>~?TXV(VHy6Pd4*>C zLInNXr8llR(k=7j=ZE&rJ3Lv{LAR&wdOmUX-+ie}pG<>3-)&2ss~nR10LVjqTUINVG`tefrdK#_)P`!^wMzDW}$TctmV`{&jMNWwH74FFo_uuCl+k?tP&7 zsqb^!ee1g8;vc+rlD|Id#iQak;>XQZntzzg|8XVn#wO=pPEDbUM}wDeG5+U&6nt55 z^3nM{{*Ql0+Pr-JDEM>m&wKu^5%TSyKSunoKW_J|SnF2hntHWwg&oZ-&l6Pq?9y&4 zb-$@)czYx9=&DoV4!k_aZA!d$=tYU&Eq=iAnEC7{)tcS+9L`5Kv=m4A`4q4%y&x6! zWFlYr?9i($Zij>PKTVysG3##KUhd5E$v+?d*mrKCNuE1@*n{Nxrj<&*u7~m-ugcLb z%0IsKY~qx2D;KkR%|5-Nc&&7?ZQG{#-6iv#T|}c!$)tS0&Jkm@{IN*W{JtOO>{?8& z)k_LKTRHLXold*jGdF*;`yF?m@KATnHnk}g>C1O27~4E8GyHPcx6;e4U#-IUbLQNc zWx{dqJnPkjO~0B7n!G;p^4zdg7qw;%y6>x+Z_Pc zq`T7}qbS1XjzrCf-P%%ThL9ABDbcV}>gIzgaO~X%kxJTC* zOZ9cDZ#{Z9uB}A&sqAj?b=ih#+Sx}hPcP_Lk@K-IbJ0@%<&n;7xl6Jb)?KxICHR(e zc9)|zn}~P)sfEnhY3AHT0STg~t#-dY?sUXrTFA!}f~{*ymFHFSuwU{!6Vkxbuh4e$ zi0UaJvw9JKhNZDa;`UAj|4fYeA8yc?C9?fMmDsmlX_L+eu#mt=x4*z3nxh4XR-4uw%_1pth?Zg)@z`tEH=AHRo&IPk8_9g{9jdzk-!_?U$ zr~Spx{ytBh!TRTZy-Uhptu0uve*N~x*SPAk4+(8$E)D*2@1#<#_lbh9-jC`D5x%H%_fp&1+RV=*t;BihP= z(+Xxv|6O{^oaHj_gs#AVsvHrix68K9S^fHT&2`0^{U=m8&L2%EQ8U|cadwBT)I%Zn zUqL(nF;;3nKM~Mo#k=sFXST&uo;1tQwecM?YdLLJ?`gZy{N{m&>(SL8Ztu9${HrUa z`1KWjN%`!FtP*Rko=u5;shJ##`s6?l3lFN z#Ko1o{vvm5o2m8dN9jKW{@icT^WIr$)pfI)tNFK9wf6R~rcRr(uX!RRUmT3Gm=-R1 ztf{ggxO4({d@!eu--YWpJH92E)tNa?|55#@eP!emBZvDsJ)D^ve>Yk2NT*v~l-$(& z?|cCN%qr*eyUv`I5?o%p)l{`3@?>?#kK8}Je`odHQeROfklfS1l~r_~e0$h2-VK6U zvv(|0&Uurbz2T8p#}B*Of6ntKx8?Q4<{Ud~FkkX#%i0}>d1LO|FOiY)xaxU{|KSSG zA2+`k|LtC~YxbJill3coT;@$y+U1jC_<7#;S6{y^IUY9mS>D0tYE>3HBi}!3E0)u! zan0v_&ar93{Wc+4$ky z!{U(G-#V=;ZaiPPYs&KtpQ9IsaaT&MD!tm9*0yzKN#c3w5{`108JB0=H4=I{>)SQ= z_ZDv@?d$YT{s-OWdA^%x7@N zc=a>MN|{_z*RD?3cz5|0UQ;GPHfzo6*>}wke&6-yNyI(}5aS9oFTY{SZ0p zs9*)__Sf8R{~fSB;Cd=n?E2&Q=z^Y|4!38HFwTCJ&SI< z`El8_ozGq=@l>+AJ>UGuy{a+pwLiCOP1Bs-!Wq7ND?8?|TbjFY?Z$r7z71}t4A0#Z z*S_A67olA_|Ie)@(G_`*Za?R@dwy7MaaxFc>UO4&%ojP_*zU`l&U|+yP~&EiO7Vi~ zKiyebtv0!mqqi`x#`Wu`S>6^-N&t^n_>oUz_n3o8PUzE^canX6DZVgM(Aq%1%64z~p*E{rZcVE8OAftN+any)L&u>r(B-RSP&$ zJ*;Hq6P5e?#U7{?8gJxzyZL|A27ia=3BPYY_pH#I)Cf=gt)sL5tmre88msNC*^|9Xmw4|3IR{w>!nw^ut9E1m7 zn*-C+5(x2>0msgu;}iD48B4S-T)204)j4= zCZG{%K0i%i$wyV={onuI`~G)d{=V<`a&m3-lsaTrc$`}+ zcI_e0+w?Pgau}IYs>5J*!E34w{~U3jPhI=;r8hsJGM!v z#KlM5y;YW*J3nIgCbQ>jv)i}Su5QiMx97`v-Osh!RjK`aXMFtaJD+kQ{g3~0yZBjL z?X!L9^>ce!pL5;%aY9jdfnU(68OGClxNLa8+sw(7_|4Av)&J!GTiYW_4S&0T{qdyf zTg>c*vL8xhRDDDKvt_Ld>0f>PR+Ih-xwVm<3+ zl=N+9=1UTeGFEY)X1J*sw)kyXbTV;+`$C%_mHc_Fni8(^Rxe7VmOWyOJFZ)_{F0Pd zf&AnbM??L0vE?T+F+VSz z9)lxctgq$#Dt`2~_X^2Z*Byzh+ka!tfpFyVRYRbL#ruvNox&SI}7YKv@3J@(d0wQM>j%&Iu0g!} z+Ou}6^@-M`ldrDkJ~^AZ@BQqyxm%RdFE2{%4RW7s#j~*ba+i>KDBr-+`8Ey(`1IW1oNdUov8J(=pt zW@~~xv!0z@k@$X!*F>THhc})x!le}0oV}+~2 z6_Z2vOpCtHJE`k4yXLD~*-Lq;?K|Arx9nUc$a=B=b`ImrHo7;whfxrxI7nxVdOquWV6i@!5L%)vNvrgLx-67?dpE zQ1Do9z5m}p*6STjG4b`wC3czW#fdhXFUl1c{eQO5)bPTp7X8=|sg{K;s}HyTEuS>G zDt^n&`D?rRQiVJ36nGaO@A$YlqWXh(xuKv;?PAaVy?2VR6( z|Lv3WD}VjZ*HAfpuIa)2lW({A|68o~^u&>6@9vykE3*A_tNZN#j7u(SCSs`puup3d zvq8`uxdzaMoJ$Cq1Va?ZT;Sb!L{|jhDJIy7i$5L01m`P36JH=~ zWNC~tD`;i}+OcM4V5DFMI%~@ev^mYp477XD*a8$jpc2|Z!OQ}5Kof{<20r#1#4^A- z=V=Pwvu9#qp#Wl;8X78q4wfZU}Ori5yY}E0qq?$RWLO*-~#PF1Yu({ z69p4FHj>XBKQ#A3PsY%R4tD%t@w4ni+X*B^QR+Oq9Bmna)q;dxx^l4#%*dl0V zW@LnrABX4eO)!_srNLU$VvI9x7GOBv_IdZK2v-0&Ph9s z+&w%tNt!jbBq~Jq-O^d25VDbb;etmStXthTOuZ7O<(+GI@<851hoxO2EN0S993cxD zde{E_SLc7cNBw3}_S>pozyH49`)>dL-T&WhUVdISC9G`TNuBBkKmG;#{CPP)rDuP^ zgLRwh3Qwo-Cw#lG^6>GkzoS3=IrA|2yG+pg-v0+9er#1{|9*ejz0KblF1t4bysy+x zcyZ$6=JM6wcdc#+@1JY4z}8&u;NQ2$zu#Zmdp_>y-v3AbJ!Zf9efQ>u*yVonELY!i z|Ihj1(aOv0TfhHQdQlly8}{+^#doRJ2HSb`b|tUrGVJs;{8P|4QF8a=%)fWyeqVS$ zGqSEZuF|sZN59sc52u@!CS0^#c)R`k*&SExzbtv2z5m$z+pMQ=iQX0d@vi!ovFMj| z2G>r0l2|y)bFR(#93S`I^ou7pXaq+HZ+;va{CsnR`DRPA1GgH34NY^nXEQuae0Irz z&+O>0k8|f+vbNcFuiL&!#(Sg3OI6OfMcCM(|LwDQf-H*MUwGiGRg zD}Ph>VA+SYzoxQI`Ejwk`G|ts_Dz>_#P4}DWQhj%Zq$CsD4soYqNMe~p#M+)x=R;V z+TyABoUPG9Kx>7MOH(PO*+{5!dLXX-wF^B{2nS;j3-^!{JjBr`86B4pYh z@jv2e`MV#?|0I92{`Mw49R)d=JsU(m>u+A$?f!9huHl9`u|?Bou}`1IcA>xT*Fp7) zzlVgXcErAB3|Nq~y2A7R)`R zN!1AC>hfgMI_q{J=f#2I$+u2lJNk4@^-SH^9S*g5u^~*SpXKP@>}%Vol=f- z>)caJSu7gu4s@Ort*bM(Vh&)+bJAc`Ww4rFBys!B*2LG3R5W;XTqWySxxR_z)XY-- zDZR%10MqM-Cl9Iqi+i{|sH=4c=c_$Y6n8!b8=U1om0CmB*!-%}ae8 z)YSXw`c0Pl-5++9Z2G{RDSp~RJd)+U%aZdOdFm(3T$;b2R(+l8w8K{$wL7$XPWP|o zzb>-wcj3~)xsUmleK6=|y2rM@G~$&`jMgR3$DYv@Teq~v9{ig5V*0D)3(_wbtPpwj z-KgO8|6L{_)(iOaSrg`PeK9=~m3S)m5Xb5GiRqaw$1~YV9xIhE__sA<0?((v|AY>S zpDM_zN^2;cwcv8fC9!}=UiHNGPRoStemmN$9!TF?ugrTt_M=VM#eIRsb;?T)eBJYY z^8eq>=St_hT~D-=n0Q4_{lSxY&wKx52ZjAw^oM^J+ug{!`(OTBQ-3JIRK{>ms!i&d z*;T&%GyWyKGrOPuuP)U6YHX_*S+QKOU`#0 zPHHV*>bA0NYeL+71@*Zpdy{&iYVHO~EuMC4Me13THi<2r0s(u37Ig`PYKgu+v1--M zo(l`=&HHCoM6NYEkeXrqFs31t>G+3v(mN{r6>iLWCHu6iSNn?8#7Ug%pLnHBD!L@$ zx5QYvX3Fy2s;U_qik)j?nfHtEoT$3Fe`9@Bdwxp(wX338W-nwu?@n8N{T|P^U9)PJ zRqZ_~%-^SXQX<9P{hur|w|=IK`!o4A znR-#5U97cpzZ=@0Z>}^0KdPKJh)$AH8R$-~5XkzMe>^_1&CgTUh<=&bleeH&*AwPtef| zPE(TV<2&}lUrOokL9v_f@=CAo&hAn@S`F+t(c8$(!YJx^0^CmaL1b+_|SEJ)UbbxkPKG%A48=(xSSUHeqVO=*Kcel=ArUm<=5ElP&S=2xoD>_ga4BmF+Xw_dVlgNKCxf@Mw#3h z<+HaBmT@UQRe1YtwZ|id<6c4eDvzYJpDk8znYZFE-%q_6d--l=E3cR>Uh?YVsYO%W z!z|BlTJ*YZQoT%vj^0a?ygwNNOhIbPzBzCE%cMEEY){MV`K$a>b?*O?yl)$JR?hjc zXUypx^A4AaUeDgab4Ahg-a*#4hgPxk)=Bl&UfJ>4=yl>%g%eCS^f|KXLoZz5le%@) z-*4f;@_07;juQ3+>w7)lU%bxwux#bMFBW}Ax%Z*t$N z+xemDwi6whHF~WPBkYiIVD=P$l#nOoa$GBRa6`!ur3SOX^_x6itb*tKLj)y^lZXCO! zGdA%}kU7kyd|pPxf?J`rLG&5ZI=_taOEXPYy?U#aRT+44;=ZNYA$K~ZubN9dy)f}- z)!yoD_O>YoCi!pVrH!3lr|(g;%;P9Oa%&b-z^^rl%XZ#=*!a(Tmosy%^UKD4JLkmz zd_QOT(Ukwa+gC1Lyf>5WrjGo_Dlw@nTjRJyE-n7V*QTr1{$9WN>;Jj!uOpr*@Fgm` z{1hzoIGa-1z;}?ByHowXt$(Hn$*(c-&TcKV=6txuA%k=3jBO__YfCO>mcL?I>`)Y}eTHj}(vOB$ ztd}|MTJkp>3%Zg~cUS23;p>|Z8veiWr_YFa%hAv`QhGVjZ=YW3{ZweGX0P#b!@4_e zGdWK2D6Ei}eEsIjT`ik0`DspcxyZ!i_Oj2=(D171$tmVazG8mM9pj&J9{*cctuZAt z`%=HhuEXaFyx%VS6|koAE!WR->6~myE2-r2Cy8-|*Mc1{?@EaDWJ+zbI~c9C{?`Y| zDZ&<9ZZ6Y$B^wv}NpGFT{=S`c<+_AymB+3Ds@>fm^Hjb}sZMOX(fd_@ZGP$&A?Rf1)4{xKG_g&|Y{1%T2>T7)WZ_0Y@N8W9(q9z4jo0p+;<(64_^Jb`|m_Xy7IH0tAh9SYS|*c%Zb>oKmGao+O{`KTEB7W zu1R6i?Z5IO+kLfIaQMszE~`cUOgKMz=D~kGT+=@HEAXAW7b5%7;_JE0^B-S5{><*` z@x;BD_nmG3vukofl}zc2BkrHNAl{mi+*YmrO!TX(;-)EFn^tiK#x|}vlhd-b;sr1N z&#y`sr@Xk)x@VRFuj`3poo^g<&QJWhqOxy=$CPa0mpz~FZ{D<|WXUZXM;5&$Ho=Vz zewTJXzx3GS#imJlZ{sJdFD=`;-Dmp(hRJ6&=V_&1O>o;$Y3EdB&UifG$elAhQwy~Y zM`}IWc24Zt(Z61jFV;0(F1mDl@&m*FUzYK%{rc;!xY)Hi&6iyF|K=r%-nQEF!Rpvz zt8!CokJqdszqO7{?l25ueSNL+L6M`w=L4xs9@kY9o0j-UxD^Bzx=mVC^EgDQ>*D8U z@wvCx{=fAoyFbTz&401&e_pnVbLG6df!#ij1uQ~tam~P`i#r!n8x??Z5D`)J^X12Ze;2i5C-HfzLo*%Yx zrR{4}d7sqVq&+RWVzprGyrZT}?3Z61)zPTW5ZGMM#oEZbJ9%aj$J-~L?BguII()wr zpI`g>ZS41}*QLwO*wr|lvj6m9+WGp7vS&};y6@eWYaL#%QsGsS%MvU0ZNjU=o{wDT zW&Mg@wrtXJ854(o(|NNlE;=GJO=VeXSMN!U%`-Amb(7cjvgyuYZIkL3lka2;yHI5~ zcZqR=&Odj(Px?2m?~{F;yKU?A>K}Tur_8U+e#URC8f(EH`yyreXAko$JC}tyL{BPe|1Cs)77h| zFZpvzH-4(w8ox%7tJ|hI%x1RyYBZH~Z+3hn$EQz(rW{P_T zgYH|)DZl=SKI<^;d%5x8%LM<&LZU~eU-+@IO8Ky+Wk{=jK=YSBjY?^gGXie;&kE!9 z=$6n_;km} zUdwb@U&t9FP$FEhD?_{oTx}m4A=(-<`kxtjFGX&)VXz z!Nv=eIjo!>WH-EBGD+BsL%Sx`wsJ~U*s{fIVz=lm+Ng3t;j!%g4->vVSj$_%m1^b~ zzGwN|^g}1gI@TujAC*|x)xS!%Ozwew)b5qjypt!Zd8X&(eC9i2a#llqx>fPVH2ZrdlTrDeb5Mid?2v~b7I!~?$I?HOe%jq572E~_xfV2)UoNynAXT1y<*a}GE*e@@}u6> z4eK9Pu}`1qwY)^xPJ5r`t8c#>Y+JpZJQ9+&sJ#mB5o2KueDFXqLFJax&nU4o~=Q&?(!<3&APP*7tg+R?D4y0=NRq%d)SZXy?lRWsZ;3VXKqW? zEo>uoPaZy8T=viWW#MjBsod_bN8DrIG9SD)amV=;=D8AnIr5y>G-G=&RxLegHqZ3x z%*B5%D+up9(JyaavX#ro)sOUq7ooLgf5 z>8hyP%O=JECYATHCs>T;n3akoONds_`?|(9|GB(X`RjYHYUgeJ|Ld;U-Q(sT=dZOa zmfwHqznIk>_MiNX`^wscWx0G-Z+7~ZtMYCem+ZPV+qO0SUS%8DdsR1OF~eiA5UnMg zrY{03_8wo+ctD3a$YJTCbrYf;)}CA?6)QGbOLbL{>l{YSUEi|K-I#N>#Xb4#!p>Uf zxjUCE;(V?g=Q&;Soy_+q-##9`^m1!_`Bw9T&fo4^T@DmFk*=c`on-K6>xcHxnLdf< z*v{PKeQW8*eK1c<*rom8kxlkj!eY!Pc^itfEc}_(Y2x#_mbbR^&oVcY6F+b9PS2R9{Kgd7pZYYPCmympyf-Cj8r%7oA51cb~JD&!6A1`>^nKmE+q( zyo1UDSg%cPe{T2rf}!fBzt3tpHDz<(&3yIh_T=s}IcH|gdA87y*Fo#MGk^ZEIlejE zn!;gbqD67y>$OcMY+~{B*uG<)!-LC5r9$T#2OT>wQ8$Ijt#01^-QVWF+gVn(GVQJK zrJ4P)H@Ez|0c^oymB)8QyD71W%d!@O|Rt<>>*Ebel{k>-Ty3L1TJAI3Tlag;e zekJvKN>c2>hq5P+GM~HVxDq0AR0)|(S_ z@62p3*SggtEA(-S$|6}~4eupJ&3R2OhnlSAZkUQPf6%;nIA0@pQO$jIsV%EMY*4dV zes%AL`cp+y1TBRZer8?z_s7@jh@e+(*CyO6e^Gv2f~7uvu5HSW5i_({ z$LKT9c&CZaE6h4tKNQXN_!hJ3qUr=hn1s%QhBlQFBo7%x`X!nrtlAfAv>;^D?nJS2UB( zwg0UBqkd`qgPD7tuwTgtkqH;pI(9T-qL0esQ!2fZ(=Vp>)GYpf=Xedj$Lq%x~9)KVe+xy~SU*G|B&1H_K z7OnWX_|v~$v5r$6r<^vgP&5r*krn2B@yW(hyKjmG{#kTL{{>5SB1R-X4QU+C`_MYUwpT0 z+6}SgyMnz#MeVo!T6RO{|MS=7+dcA+R4UwTnOw5s;ek~`Zy64BZx-GpT5)PU&zj@Q zA6=bwN9#jL%asF@IBYHy&Z(XKbo$Yos&6Jg?9siPZRPjPvpub~_L8RI#Rxq!Ibq(Y z>eQGTi#iqcvu3rjv$v<1hhKQ^c9Z3NpWV@ord$0Z-v;Y_TWLD&W8aHEh8G*M9G9+p z(zf`L^uP7j7w`A?mj3yDX=p%iO`J?a@bAlk_5Fd9{Oq1AO*$NxbEKzBOy=kla!%dZvh&qV%TJcIv7^bgy0`j0u@_5Q1BoD$jR zBsTkCU;eJ8H$*Wfc8x&Om$0cN#5@`?6T2ST`0mg%0nJ)Ch`hANPyuoE z5@=g3@&-$=xtI>dGx3M+PVkJMF?7ZaHsd#tcj%dbCTvmW`#=IPKf>qxz*C73o`RvF zsWIW{zT6ORAL(!r+x)Z*iiQXM3O$m&(sN`Em>q0v5O(6>Gn?YCB(x}N*(#}wBn3eg z77thPi8o4;LqkJLFRq*A66T7GW^z7?#7ryD9U03~cqjU6r z^W7mTn|^NlnHjrp|E^~h zx@@BQ&2L6N|01N`mRNBFe>8KOs93JBHj&SKg0uK6+m})?M-_JQzx?q*Pp#miz+-oQ zA%lWRM|Y`SOOjy@>0ER%`PGKL?}e?Pi}afGKX%;VNWQyb@fw%qULJb8KCfn6^FX$$ zWOLT^mFe#ee=Ruc^x^RQCrqze-OK%+X~*;!9EoB*Eyq{&MK{{TY`oskHQUt951cnF|3y zDne}TSzhuRul_huYMk~`b+1X;?j`*%xHoUl)qSU+-le+Qd%I!oy@%i1GH*DCJ$bqz zBl7Q+i%a;NU&L)%QE)w2!7AkX{*qOmzAv^_Rh`lWVeD9Py z&*??e-={8J6Y;Jodh>kK-$HZNmxeC$t=337tTlDXvn`UwZ+e3?gC5malu1Uf7hqa1 zH@a#MFC>c!6M2>dOB2++|DG-4V$;~b&&Aow8p7YVd_WpFNj{YEIPEimGQ@u zybl8M1`qiDdAU6-Y|;2^8eDnom-dB#?p+r?a>wjeD9?}1OFZ~wx%Q_i{}!$}YI|$p z*~ngvj(>B%+?+Q-uuEFeSv)>uzhKqZol-Y$%Ldq`_c$cghyPjp=Y;j&y*AB%cbwp1 zKjpYm#s##>=h38&-7A|8E?={{Zu_C^r|x$&buLd0-stLNbK+`%{oxlpQ>Ml++dX|? zxcjW0?Y5iqH~&BSEb=kZjLy^GRHwiN8suUCqef4^^zN9^8& zmgw_l=HJWq$eo?Fcdl}+?7@S-%>9>t{dn@^$JdWG$MoAzewpRpZvExhvU8_9Gvcc^ z$A5O6H2s#9dR4U4;?89y7FC<-ETU)2%2`)bf8YP??4SK=_kReVYk9C*bIwHnee*4E z-t+2<-Dk8lB4+-)z1x4upLynSCtvi=XG8v{5p^WN*5MN3RMQTtks&*RCjE$w{%zrBwy zTM+!_jLqfPG|9^mi?@81IH*3w`t&35$T)?XFG`1!*y=vY{po7kaOu&1#rFalmXR4s zAtw999|f=0?6b>L`u#=Ezt8IXxt(e*LD!2{M@FBy956}c7|*#YOXh9Adhw5R+MP?% zRmo`^7e4rHtd)rZt?Rz*} z+P(fdtH*CzaQoHFMU{uQly5S$p1d`wZQ=7be-~xGPfu=3y?FY5sMpa=-0Pk(nEpP# zL#|};6d!Bh&55Q`MrkK|q`&zs7R>%&YqPua?{SXCUYA_l{M4Dr49$0C{@#_Db!MTWTJazCl~XR)Us#kB=a{~E z(k)m0Uve8g*nPhg-SrRYSlIlL``8jgO*JLqixpFLJ$lr9t~@DachJi_!d>s*t@*K5 z`0V|^fi>FM4|*1_uRQcW|3vA}pA){yeA0R~{r*RUb zo>&TX?2GM*Db&627wVuzmBbh7#>j=bF}^MY$Xr-~hp2_{6zb^i9DId3=qwhLLLDRk z^CP@a2i-1)#kzg^XNMc&}-sS4)P>sGzH<)O0+biuzxOfy1@-(wWNd zdw!qWTl~Iy^WL8t{R(9Zl}z_fyWL>CMV=%4nSB21b!*u=4|hv@XV0_c>{z?>>Upu) z=-)PDoE&7f*cW<1j{&y(l&+~V;c5Z(VbFkE|$b);uq$x%(K!y7G*Vgi9 zuJQcqZTPkON&UMxt=$$Mqkn?-2RO}M3fUhpD3w_VnRgSsjU9#1;nGU3qdGrKvr@-^3T`6~Mw)ot@V z$gu08*YeA`TKA5}ewl1N_1cCG$vbZ1ao?9{f8cYwQ0#ZSz2Bg5`#Hlpm5Xf5y*}4` zHwrzLSmGs8Dkpq^&+eeeVoAB+*8C4GcQn55+O20GJXb3*vgCPi^Nl0zUtT0$(+fU( zrvxhz$zJHGC)l7Bm-j_n%f&3d|54E)`%h`Q3Q299Vx%-^Q-@DfeISK8|zk67! zGe-X7g@>8-uW$IQXq-DUd57J!LV?vjYlYALXnNVV`A6h5agKR+TmpIys@t{tUla)O zs)_r=*Qlwk*2R%>_I>M*OIlr%&v$#o-+g>CFx~#0hLcK(?dD0_j>_<=IxafV7ad{-Z4ik4e`%$X;lkUmwyvqXzoq=Lp!L*kN^J|%-!!kulwYC@D%8uTX&O(9 zEhzqGoE|TIT|0Ja=4C(EoQT$@D|5_}+xA9lxN!a9JFoZXfvD4iP^G7WYgkMpI(-7) zq-nZ!ND6u$>6vlRX01swyO8kZw6>X2VeFv3!({frdtR0EZz}#sF|Ua9libkke^SGy zPr&sb=qm0;A(Id#fpvS2-fF$EcYX@Dv08lWMB88O?eJp#7ys^jmBVg3j&exv`myWJ z+zY4ouR8d6vEx(icY-slEQ7KtwW20YPXAzaOX6XOrQX!X9UiIbAs#}C<{>s)j{m*t z?%HC}T@dzYs&I#errU0>GuB-KYi;Y2zXpEiOq|ab|Ea(9-)ZH)vXjm4Uud^`;eY34Z@b&7^~bEfRzH6Heb?{!-PMsc zVP>cPAGtN_*XEN?s+}+H%7}I@uidh-$|!j1%pTLQ&e%x%^f@+<-~QOIcwKrf>p}bJ zw|VFPX}>!yc~9+|w=3Ud)umf~FL-Sq^2(?Kvw|=|sUR{-a#9sE{{4?JFfi}|5vd@e z7(^(5h$0XH5;F!dKsX&lfmmQA2r;k{uozg0A4o|ih{)CC z(hn%gPbp1KEmF|PO-%L=RtQTiD$dN$Q!q5uGte_sh|zE=&CE$rFfws8HnE7&R0u3h zEGnr|2yk(8&d)1Jttin{(042?$;dC_(g+CCRM2-WN=+=uFH+FRbX0(xJqHua%+GU4 zEJ;<+aIrEnFfuVTFfuYUH8wRejxsP%H!x7wRM7X$PXQ_6!mY&44ivbcQoW)mHH`~& z!w{DN94MHXni`ubq$xnfjEu~T6~M9zc~CJ!Q_#6#sA2{N21Z6`>I{sG&CSupOpQTz zlY=xPnP&mo6M-sbZe(eJrq{^G$P(Q=BTGZjjY=qb4U9}p(DfP^nPQk{U}Odw2Sn9t zZfR;MPm}+TYXlP_&o|s~sW^7<)U~Xy0 fMOcXfc=WxvB(bOjT 0 :\n", + " mouvements.append((i, j+1)) # On ajoute le mouvement à la liste\n", + " return mouvements\n", + "\n", + "# B.\n", + "print(generer_mouvement(test1))\n", + "print(generer_mouvement(test2))\n", + "print(generer_mouvement(test3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 3 : " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# A et B\n", + "def appliquer_mouvement(etat_jeu, tas_index, nombre_objets) :\n", + " if nombre_objets > etat_jeu[tas_index] :\n", + " print(\"Erreur : nombre d'objets à retirer supérieur au nombre d'objets dans le tas.\")\n", + " return etat_jeu\n", + " else : \n", + " etat_jeu[tas_index] -= nombre_objets\n", + " return etat_jeu\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 4 :" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\" étant donné que heuristique est égale à la somme des objets dans les tas, \\nc'est donc un calcul simple qui ne dépend pas de l'ordre des tas. \"" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# A.\n", + "'''\n", + "def heuristique(etat_jeu) :\n", + " return sum(etat_jeu)\n", + "\n", + "print(heuristique(test1))\n", + "print(heuristique(test2))\n", + "print(heuristique(test3))'''\n", + "\n", + "# B.\n", + "''' étant donné que heuristique est égale à la somme des objets dans les tas, \n", + "c'est donc un calcul simple qui ne dépend pas de l'ordre des tas. '''\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 5 :" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n" + ] + } + ], + "source": [ + "# A.\n", + "def est_etat_final(etat_jeu) :\n", + " return sum(etat_jeu) == 0\n", + "\n", + "# B.\n", + "def cout_transition(etat_courant, etat_suivant):\n", + " return 1\n", + "\n", + "# Exemple d'utilisation\n", + "etat_courant = [3, 4, 5]\n", + "etat_suivant = appliquer_mouvement(etat_courant, 0, 1) # Devrait retourner [2, 4, 5]\n", + "print(cout_transition(etat_courant, etat_suivant)) # Devrait retourner 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 6 : " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[4, 8, 5], [4, 0, 5], [0, 0, 5], [0, 0, 0]]\n" + ] + } + ], + "source": [ + "import heapq\n", + "\n", + "class Noeud:\n", + " def __init__(self, etat, parent, cout, heuristique):\n", + " self.etat = etat\n", + " self.parent = parent\n", + " self.cout = cout\n", + " self.heuristique = heuristique\n", + "\n", + " def __lt__(self, other):\n", + " return self.cout + self.heuristique < other.cout + other.heuristique\n", + "\n", + " def __eq__(self, other):\n", + " return self.etat == other.etat\n", + "\n", + " def __hash__(self):\n", + " return hash(tuple(self.etat))\n", + "\n", + " def __str__(self):\n", + " return str(self.etat)\n", + " \n", + "def xor_etat(etat_jeu):\n", + " xor_total = 0\n", + " for nb_objets in etat_jeu:\n", + " xor_total ^= nb_objets\n", + " return xor_total\n", + "\n", + "def heuristique(etat_jeu):\n", + " xor_valeur = xor_etat(etat_jeu)\n", + " if xor_valeur == 0:\n", + " # Position désavantageuse (perdante)\n", + " return 100 + sum(etat_jeu) # Pénalité\n", + " else:\n", + " # Position avantageuse (gagnante)\n", + " return sum(etat_jeu) # Heuristique standard\n", + "\n", + "def est_etat_final(etat):\n", + " return all(pile == 0 for pile in etat)\n", + "\n", + "def generer_successeurs(etat):\n", + " successeurs = []\n", + " for i in range(len(etat)):\n", + " if etat[i] > 0:\n", + " for j in range(1, etat[i] + 1):\n", + " nouvel_etat = etat[:]\n", + " nouvel_etat[i] -= j\n", + " successeurs.append(nouvel_etat)\n", + " return successeurs\n", + "\n", + "def algorithme_a_star(etat_initial):\n", + " noeud_initial = Noeud(etat_initial, None, 0, heuristique(etat_initial))\n", + " frontiere = []\n", + " heapq.heappush(frontiere, noeud_initial)\n", + " visites = set()\n", + "\n", + " while frontiere:\n", + " noeud_courant = heapq.heappop(frontiere)\n", + "\n", + " if est_etat_final(noeud_courant.etat):\n", + " chemin = []\n", + " while noeud_courant:\n", + " chemin.append(noeud_courant.etat)\n", + " noeud_courant = noeud_courant.parent\n", + " return chemin[::-1]\n", + "\n", + " visites.add(tuple(noeud_courant.etat))\n", + "\n", + " for successeur in generer_successeurs(noeud_courant.etat):\n", + " if tuple(successeur) not in visites:\n", + " cout = noeud_courant.cout + cout_transition(noeud_courant.etat, successeur)\n", + " heur = heuristique(successeur)\n", + " noeud_successeur = Noeud(successeur, noeud_courant, cout, heur)\n", + " heapq.heappush(frontiere, noeud_successeur)\n", + "\n", + " return None\n", + "\n", + "# Exemple d'utilisation\n", + "etat_initial = [4, 8, 5]\n", + "chemin_optimal = algorithme_a_star(etat_initial)\n", + "print(chemin_optimal)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 7 :" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(voir cellule précédante)\n", + "\n", + "A. \n", + "- Initialisation:\n", + " - Crée un nœud initial avec l'état initial du jeu.\n", + " - Utilise une file de priorité (heap) pour gérer les nœuds à explorer.\n", + " - Utilise un ensemble (set) pour stocker les états déjà visités.\n", + "- Boucle principale:\n", + " - Tant que la file de priorité n'est pas vide, extraire le nœud avec le coût total (coût + heuristique) le plus bas.\n", + " - Si l'état du nœud courant est un état final, reconstruire et retourner le chemin depuis l'état initial jusqu'à l'état final.\n", + " - Ajouter l'état courant à l'ensemble des états visités.\n", + " - Générer les états successeurs et les ajouter à la file de priorité s'ils n'ont pas été visités.\n", + "- Retour: Si aucun chemin n'est trouvé, retourner None.\n", + "\n", + "B.\n", + "- Vérification des états visités, avant d'ajouter un successeur à la file de priorité, on vérifie si ils ont été visité.\n", + "- Une fois qu'un successeur est ajouté, il est ajouté à la file de priorité et marqué comme visité.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 8 : " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A. \n", + "Une représentation de son parent est crée dans la classe noeud. Lorsque qu'un successeur est crée, le noeud courant est défini comme parent\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[3, 4, 5], [3, 4, 4], [3, 4, 0]]\n" + ] + } + ], + "source": [ + "# B.\n", + "\n", + "def reconstruire_chemin(noeud_final):\n", + " \"\"\"\n", + " Reconstruit la séquence de mouvements depuis l’état initial jusqu’à l’état final.\n", + " \n", + " :param noeud_final: Le nœud final de l'algorithme A*.\n", + " :return: Une liste des états représentant le chemin de l'état initial à l'état final.\n", + " \"\"\"\n", + " chemin = []\n", + " noeud_courant = noeud_final\n", + " while noeud_courant:\n", + " chemin.append(noeud_courant.etat)\n", + " noeud_courant = noeud_courant.parent\n", + " return chemin[::-1]\n", + "\n", + "# Création d'un chemin d'exemple pour tester la fonction\n", + "etat_initial = [3, 4, 5]\n", + "etat_intermediaire = [3, 4, 4]\n", + "etat_final = [3, 4, 0]\n", + "\n", + "noeud_final = Noeud(etat_final, Noeud(etat_intermediaire, Noeud(etat_initial, None, 0, 0), 1, 0), 2, 0)\n", + "chemin = reconstruire_chemin(noeud_final)\n", + "print(chemin) # Devrait retourner [[3, 4, 5], [3, 4, 4], [3, 4, 0]]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 9 : " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3, 4, 5]\n", + "[3, 4, 5]\n", + "\n", + "L'IA joue...\n", + "[3, 4, 0]\n", + "[0, 4, 0]\n", + "\n", + "L'IA joue...\n", + "\n", + " L'IA a gagné !\n" + ] + } + ], + "source": [ + "def jeu_nim(etat_initial):\n", + " etat = etat_initial[:]\n", + " while not est_etat_final(etat):\n", + " afficher_etat(etat)\n", + " try:\n", + " pile = int(input(\"Entrez le numéro de la pile (1, 2, 3, ...): \")) - 1\n", + " nb_objets = int(input(\"Entrez le nombre d'objets à retirer: \"))\n", + " appliquer_mouvement(etat, pile, nb_objets)\n", + " afficher_etat(etat)\n", + " except ValueError:\n", + " print(\"Entrée invalide. Veuillez entrer des nombres entiers.\")\n", + " continue\n", + "\n", + " if est_etat_final(etat):\n", + " print(\"\\nFélicitations ! Vous avez gagné !\")\n", + " break\n", + "\n", + " # Tour de l'IA\n", + " chemin_optimal = algorithme_a_star(etat)\n", + " if chemin_optimal and len(chemin_optimal) > 1:\n", + " etat_ia = chemin_optimal[1]\n", + " print(\"\\nL'IA joue...\")\n", + " etat = etat_ia\n", + "\n", + " if est_etat_final(etat):\n", + " print(\"\\n L'IA a gagné !\")\n", + " break\n", + "\n", + "# Exemple d'utilisation\n", + "etat_initial = [3, 4, 5]\n", + "jeu_nim(etat_initial)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercice 10 :" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "def xor_etat(etat_jeu):\n", + " xor_total = 0\n", + " for nb_objets in etat_jeu:\n", + " xor_total ^= nb_objets\n", + " return xor_total\n", + "\n", + "def heuristique_amelioree(etat_jeu):\n", + " xor_valeur = xor_etat(etat_jeu)\n", + " if xor_valeur == 0:\n", + " # Position désavantageuse (perdante)\n", + " return 100 + sum(etat_jeu) # Pénalité\n", + " else:\n", + " # Position avantageuse (gagnante)\n", + " return sum(etat_jeu) # Heuristique standard" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/TP01/code.py b/TP01/code.py new file mode 100644 index 0000000..556bc06 --- /dev/null +++ b/TP01/code.py @@ -0,0 +1,197 @@ +import heapq +import random + +class Noeud: + def __init__(self, etat, parent, cout, heuristique): + self.etat = etat + self.parent = parent + self.cout = cout + self.heuristique = heuristique + + def __lt__(self, other): + return self.cout + self.heuristique < other.cout + other.heuristique + + def __eq__(self, other): + return self.etat == other.etat + + def __hash__(self): + return hash(tuple(self.etat)) + + def __str__(self): + return str(self.etat) + +def afficher_etat(etat_jeu) : + print(etat_jeu) + +def xor_etat(etat_jeu): + xor_total = 0 + for nb_objets in etat_jeu: + xor_total ^= nb_objets + return xor_total + +def heuristique(etat_jeu): + xor_valeur = xor_etat(etat_jeu) + if xor_valeur == 0: + # Position désavantageuse (perdante) + return 100 + sum(etat_jeu) # Pénalité + else: + # Position avantageuse (gagnante) + return sum(etat_jeu) # Heuristique standard + +def appliquer_mouvement(etat_jeu, tas_index, nombre_objets) : + if nombre_objets > etat_jeu[tas_index] : + print("Erreur : nombre d'objets à retirer supérieur au nombre d'objets dans le tas.") + return etat_jeu + else : + etat_jeu[tas_index] -= nombre_objets + return etat_jeu + +def cout_transition(etat_courant, etat_suivant): + return 1 + + +def est_etat_final(etat): + return all(pile == 0 for pile in etat) + +def generer_successeurs(etat): + successeurs = [] + for i in range(len(etat)): + if etat[i] > 0: + for j in range(1, etat[i] + 1): + nouvel_etat = etat[:] + nouvel_etat[i] -= j + successeurs.append(nouvel_etat) + return successeurs + +def algorithme_a_star(etat_initial): + noeud_initial = Noeud(etat_initial, None, 0, heuristique(etat_initial)) + frontiere = [] + heapq.heappush(frontiere, noeud_initial) + visites = set() + + while frontiere: + noeud_courant = heapq.heappop(frontiere) + + if est_etat_final(noeud_courant.etat): + chemin = [] + while noeud_courant: + chemin.append(noeud_courant.etat) + noeud_courant = noeud_courant.parent + return chemin[::-1] + + visites.add(tuple(noeud_courant.etat)) + + for successeur in generer_successeurs(noeud_courant.etat): + if tuple(successeur) not in visites: + cout = noeud_courant.cout + cout_transition(noeud_courant.etat, successeur) + heur = heuristique(successeur) + noeud_successeur = Noeud(successeur, noeud_courant, cout, heur) + heapq.heappush(frontiere, noeud_successeur) + + return None + + +def reconstruire_chemin(noeud_final): + """ + Reconstruit la séquence de mouvements depuis l’état initial jusqu’à l’état final. + + :param noeud_final: Le nœud final de l'algorithme A*. + :return: Une liste des états représentant le chemin de l'état initial à l'état final. + """ + chemin = [] + noeud_courant = noeud_final + while noeud_courant: + chemin.append(noeud_courant.etat) + noeud_courant = noeud_courant.parent + return chemin[::-1] + +def sauvegarder_partie(historique, fichier="historique_parties.txt"): + """ + Sauvegarde l'historique de la partie dans un fichier. + + :param historique: Liste des coups effectués pendant la partie. + :param fichier: Nom du fichier où sauvegarder l'historique. + """ + with open(fichier, "a") as f: + f.write("Nouvelle partie\n") + for coup in historique: + f.write(f"{coup}\n") + f.write("\n") + + +def jeu_nim(etat_initial): + etat = etat_initial[:] + historique = [] + while not est_etat_final(etat): + afficher_etat(etat) + try: + pile = int(input("Entrez le numéro de la pile (1, 2, 3, ...): ")) - 1 + nb_objets = int(input("Entrez le nombre d'objets à retirer: ")) + historique.append(f"Joueur: Pile {pile + 1}, Objets retirés: {nb_objets}") + appliquer_mouvement(etat, pile, nb_objets) + afficher_etat(etat) + except ValueError: + print("Entrée invalide. Veuillez entrer des nombres entiers.") + continue + + if est_etat_final(etat): + print("\nFélicitations ! Vous avez gagné !") + break + + # Tour de l'IA + chemin_optimal = algorithme_a_star(etat) + if chemin_optimal and len(chemin_optimal) > 1: + etat_ia = chemin_optimal[1] + historique.append(f"IA: Pile {pile + 1}, Objets retirés: {nb_objets}") + print("\nL'IA joue...") + etat = etat_ia + + if est_etat_final(etat): + print("\n L'IA a gagné !") + break + sauvegarder_partie(historique) + +def pile_random(etat) : + piles_non_vides = [i for i, pile in enumerate(etat) if pile > 0] + return random.choice(piles_non_vides) + + +def nb_objets_random(etat, pile): + return random.randint(1, etat[pile]) + + +def jeu_nim_random(etat_initial): + etat = etat_initial[:] + historique = [] + while not est_etat_final(etat): + afficher_etat(etat) + try: + pile = pile_random(etat) + nb_objets = nb_objets_random(etat, pile) + historique.append(f"Joueur: Pile {pile + 1}, Objets retirés: {nb_objets}") + appliquer_mouvement(etat, pile, nb_objets) + afficher_etat(etat) + except ValueError: + print("Entrée invalide. Veuillez entrer des nombres entiers.") + continue + + if est_etat_final(etat): + print("\nFélicitations ! Vous avez gagné !") + break + + # Tour de l'IA + chemin_optimal = algorithme_a_star(etat) + if chemin_optimal and len(chemin_optimal) > 1: + etat_ia = chemin_optimal[1] + historique.append(f"IA: Pile {pile + 1}, Objets retirés: {nb_objets}") + print("\nL'IA joue...") + etat = etat_ia + + if est_etat_final(etat): + print("\n L'IA a gagné !") + break + sauvegarder_partie(historique) + + +etat_initial = [3, 4, 5] +jeu_nim_random(etat_initial) \ No newline at end of file