From 7f713363780adb80f158f911f2fe6d041aa5e3b7 Mon Sep 17 00:00:00 2001 From: saaalik Date: Wed, 17 Mar 2021 18:05:14 +0530 Subject: [PATCH] Path finding script --- A-Star-PathFindingAlgorithm-Script/README.md | 28 ++ .../images/1.png | Bin 0 -> 25159 bytes .../images/2.png | Bin 0 -> 25692 bytes .../pathfinding.py | 239 ++++++++++++++++++ 4 files changed, 267 insertions(+) create mode 100644 A-Star-PathFindingAlgorithm-Script/README.md create mode 100644 A-Star-PathFindingAlgorithm-Script/images/1.png create mode 100644 A-Star-PathFindingAlgorithm-Script/images/2.png create mode 100644 A-Star-PathFindingAlgorithm-Script/pathfinding.py diff --git a/A-Star-PathFindingAlgorithm-Script/README.md b/A-Star-PathFindingAlgorithm-Script/README.md new file mode 100644 index 0000000000..ddc41bdfe2 --- /dev/null +++ b/A-Star-PathFindingAlgorithm-Script/README.md @@ -0,0 +1,28 @@ +

A Star Path Finding Algorithm (Python Implementaion)

+A python visualization of the A* path finding algorithm. Allows the user to input the starting node, ending node and barrier nodes to visualize the whole process of finding the path. + +--------------------------------------------------------------------- +## How it works + +- Pygame module draws out the grids and sets up the application window, such that the colour of each node can be varied. + +- Methods are created to change the colour and functionalities of nodes, + - For left click:- *The first click and seconod click being the start point and end point respectively*, followed by setting up barriers between the two nodes for every click. + - For right click:- Deleting the setup barrier. + +- A-star algorithm is implemented - + - `heuristics` function returns approimate distance between *start* and *end* points. + - `update_neighbours` method is used to find out the neighbour nodes of the current node. + - `open_set` queue keeps a list of tuples containing neighbour nodes information as #(fscore, count, node) + - `g_score` storing G score of all neighbour nodes of the current node + - `f_score` storing G score of all neighbour nodes of the current node + +- Algorithm is called upon pressing `ENTER`/`RETURN` key +- All inputs reset upon pressing `SPACE BAR` key + +--------------------------------------------------------------------- +## Requirements (Py modules used) +- pygame +- queue + +[](images/1.png) \ No newline at end of file diff --git a/A-Star-PathFindingAlgorithm-Script/images/1.png b/A-Star-PathFindingAlgorithm-Script/images/1.png new file mode 100644 index 0000000000000000000000000000000000000000..d731f4f1349ea5abc87e1cf1c57cdf300b19853f GIT binary patch literal 25159 zcmd_Sd0f+Xwm!~W@5uDJ(AKtyY;9>pYa}WnJJhA1vMC4{L{h~NSp->R2_%^gt%@uu zib2*?*%X9G*hCicUQ) z_{)Eycf0J?(5NJ=lAri9`1>1Y_ah=TG~SMae*I}Qz%W)rn~1bkI%&RUB2U_9e-)$Sz(fIgk{05RM!K+(u{AX zolQGG;@&)Cp%dkrcgxz!6F$i38XAB7+a_@38h<|A4SxTx8-;(;(0J#$rt&R0O(mo0(q4oq>toL> zNc_*08!4aT1>{!R99dDb#JX5sULLy?WkysA-Q~|o%3GLsz=sJqnkIp?7xQ>4C5!gL zB44bG7dFu5*{!PY+!}RMQoQKaqPcP!|89(G6#v#Sn#_DmKG3;1_`nBzhKyXGx_~cK z8iVh!7>fJmvRI{*;kR79quQ3XMwPmlZm3w`_siK08_@W<;J0#+1j(o>;I@IH?qtKb zTl067$AobCVno6nX>$0qDQQF@_zw+@J9SvR+u-~pv!F&v`b_?Ww3PTaFRt7lA6WN| zXRnpYTbO09Ak%3UOZ8JW!c~>Rc=p8(c0;`k+#wD22-Rs2F2A~^D`vsf=D3WH|C3}d zX~~df_*ufV2kDYEUiC0mGNLQ`3-sa+>cK(#B}Xm)1!Sx-?k>&9566}A*`qmN)5dNE|7tQx|vQ&Yd&EO*7M4CtGowl-;W5qLE4grwX}*Il|uP zeH^KBZ-(P0WUwHlLOQiLOfC!(GbhI9z5B>GWy|6uzUH2abu(<}L%Kl9^LvLyN+Tx> z(R#dbWB0WhUG1Nc>RkpjG@dk8R#pmTmL^BoDjD8hIZIMhv8!%+l08*<)3lr(aBH=+ zs>kRnt;Z!^B>DyGA)%IvKRHe(se*;8RPFe;@k%*?PLkeoYavP7sEfg>WMg3@UYZk* z$C=p4KmWwaK4HCM!^$zZQVUvK6}%#=XZP4ON$$ z2#Su!{LJqZ3zdbr>6nB!ICav6{kduEG%|LwnSDaS*k-?E+ansQlT9(_S&PyUp*C`Ck%ylM z8^I3=gjn=x60^fAbpfJ|Ht!W+E@Dct@I5^L5c~#oAKe;a*WL zty7M`@5|b?OUa%oWN$Kl!R%67CVmNRgyVs$x(b&^%g30t0tTPjCpdof3WXs3BM&kV+Se;MiS?e74_hyNXY|Nz#@c;Z*{TNycx+-N2Pcs4~Nv-DWFf zF{-!eY-J0xnb}HiTAY-muhG!Rn6OUv>G^Xxg?!md@!i*MswDe$DiU5kIaXG648GFZ zt?)m3vv4KU1=8`i9A)F2Om~EnO2;wnGc?)}wiRbf#Y9@;q|=X+@e{HI7D?qS9}B~O zU{cJSu~)PpQ{l?{eN$K~>SAAyu~MR%5|l5^X5x5S%6g`%J9Dgxrl_%BF!wR^em5;l zQQj?4{z-?ekSK$O7w6F9PBd{Pe2ZL8F7Eck%WbP=68VBQKDaLSGlf9JL-ERlh9#FJ zUy&1T{}sEGENmf2Zjz)$gmPJo@GEk2nBqQuGipAV%T#cXO7!A&xP}Hw);pQZX1CZQ z?fjl*o1DH1!t@qgK^GRm6{K=M(;t7G~oBXSDts#aH(s7bnC7yJ64FS zP|oM5ER=4ly0BIet>#^lia`^eloMVEFE5ORrBXfLr}CVpOX1gLc1Q55Bs@MnQE=FR zs?fZUATaz|cpNVXv)ON$mnKM%n%WB;RiwDdMccA5(J>ayEhwsCM%I<7hZ8v@So&pr zCz#Mu#VPMFmCfjBLQn%T;0=uzZK86fHjTDQ?2r7IhsI5y$4E+k{B~Im-rOtyb_;&# zmaG^Dm!`r}{SuH*(KrQ~Dk{RUnMf!73=nC`DR{_mNwhqlq+*TGJm>3tH8fs~VC7DF z_R1oHiL&I8X3E2aEd+(oFpa&Ks@g#n*WlL&ml1jvZ>?9&uM-Lk z4KFg~ZKM=KS(jmwP&F~KI3i&a?8OgPhy)9XOGmR7TglB#zG#K1@}j^z_;CqsJzimr z-{0nqx1%!2Plks|RGh^uCVyUX8~5QvjC^NHn7kd1p8+>)DH1o~&yLSjW+A11?2C1o zaMgmLoP-l7%h5}Fv0^9M0uT9#&%s^b79UTjGkm){>hMrsru8UIFSCk zrHc36vleScNZ7-8dmqt?H)-<>eGmk~A|}ofcMqemzSOpRQBLl)=e#HoTyF^9PE{5O z#$|MBnHwD(I}!~ostdUFsp7swSTxh(79sDI40_sQglnA_@*ma*eJad{iZmm;STRZkZwdgCqN?Qt}3sihx zIRmXso|0ep7mCC9%?0>j9d<~QUWtQhQkWx-=Yk0SsAiMdPSKz=Kq8{`? zNl7Mjq_iGnIt6L=BHWjsRKQZ14QeTb7kkZPRJ1M}N7bbptZQ#@j2S=9UFupC8sa}* ziL^6N_0pu?e)5&oOz^a=a8^`aSZj7M=mtNH=glzmw1(!ja{;8cz8Q}=}uDRD+*L?>-ZQFDadcmPLKL$_doA-a->vFGU zX9uwi!7I;xYZW?jkF{aLhSIQkA0MAf4Kae&=H`71VsURlTnCd$zhdk*He4Sm+K;OX zW2cSN3G}I{)3%rUT3a0+KYrYtWs2TIQ)%6 zI@`U&Q_(RpJso6wnLRrj5{$vzqXs*eAUUxUqp3+rNmD#tx#N5`i9|4V%WtlaoSaUVhq9^qbb=wF ztE&t15jizA^;%X|k}10LOW2STbepsg6CW@VUfw%{3m-ES(|0kVpt7o}Dr!eC8g0DG z+`NEHhFe)#O?Nfcf}`YG1R%i=0S|}(Js<B!x1qm`PPT8?${smE+37fx3X~Zd( z_)EKrFrgK`^&c{JRl%VjLV4_{j)KHT5$yNgd(ZugGY)2bPoEwMK6kFhpe-yqy7ubd z$b#&{9o`*789}yX=dPk;Z951-F7V^`o*r~O_)^i$K*rH=DHzP>3XZlqRjPsvQWoX@5i zu2`{RyN!)6;dxC{lYV4miS^`+5E)Cnsk+h)%-uIuM<(86 zg;QMx>-F?jBWnASVTMI8`h({ zw-WU+ILiK~Pu~RL9~ih9gTah7C#?fV>c9JBj{44y9%mOHVRpQDaR)mP(AmG7gI^1h zx=~CS>&RbNiQ@0>C$87kO|Gb@!0aTqw6w%7Ed=J;Vec8V36u)i_HEnl$lf@yuC}hu zKQz?D!NFm}&>_uCj&FMeRsD*t_1EGzJQUE7AYSu&BTUM<`+bJi1*YcQxtyP+$sN#f zVjl9w5VP+rwr>&cV&7xMXM_B+<6jo z@F!`(%+~fe+pHj)oL#q>h4GrfSWp@>>@Kxd1W^Zs!i5v}!oKs-Uw_)g#kKZ52M2M2 zE#0%jvjfr5)Hh>U5#&+=FM>&8xAu8(Pd7l|OS*}PlltZm+(S&>h_3_>=hQyL>U?H}}K zcJ@bK`B8eOSylKo4NlL_-VU1|92iLI=;)Z5nMqDdO9PPxab!w)9Mnx1Nza6YG^ZOm z-e_oOFlZ}d1+{=fvaqnwY;4a!Z)T)|%#oTpYC%z+hzbkqGm5L}_Ngc_;~fYd%IdxQ zhBY^9z?tca#GJS4u6p`qc|}DmZsGJoaZ`6jYShZx_{9?;<{79Oc&Q?Mw!d=k9e7?P zZ{tsk-Y-?{R)bopR2nfebz9?L;uV3ysSGud`@nh#)%gBw{9T6K* zmRBeVUW5rVd;1M;0e+Vv1&tnr=P@$5)Izx!o>Dw{^9^0@x}~gY`_4vL=;|V~&x+wveagzpKm!IcNjaCxU8>MwC9oP@ZuM6A^i5RdI!9_1HjJp=`bcJG zZ9SSzjoOU8#@D@9Dh;61B?(*UHCEf6WM}7wY)wg-m15G$vdglovg656_RTifM;s3v zjhZ!!SW_s5m!+eXWAiJuKCNp(&+No_f916Uvhl|ag4RPm;~QZ`=m~x>xn&>bJceYJ zfg03x^9!(7-^`f4U1ov~iPz6J^&)~uT<-BKF2W>bLZwotrlxK>&JPX_UYcZ*%r|^0x}$Fy@zK4825_)_%Drxr$&PN!s;SxGTi{g# z+>{QqZCB<5Z~wgciL$aS`G&R|ngX#ol=S=@BSYN!k)a__S<0*7y*UgpNx zLIrKWh!HK@1Rb~O+2B3rh~AthIzxVJEC2ZDzPoQ|if}))jz^fcVM7dc1ExoWzV&ER ze7Q%7E2}QfHeqpF=xC!(CLEcjR4Tzaw~paA&&@^nHpW(h6V#fjyWPTKJ(`&hPLR*B zW62Bg9poNKz)TL+R(r0KPMQWe)S z=z-6mc28L2TiV@rmLk8s2x>N^@qP8TpV`ciY-pcjWpJ);@y@M0BQ7@;@3Hc?9}r~r zk&$e5O>_}Ge$_Y8Pqh8U9`yLp^#@`aREhhnY_^Z)YirOMZ-LYFaz;kBXMiYm;?{Eq1~08M+zHOTHlh2v#WisfY-r{i zimx-G0we=`I|bumtA`G8^ADS_4n*2u7B;Qyu@mA3{5*-QLEMuk)Z4w3K_k}33^7HG zmjEbxg_h0C%ve6hkAtI=lb3hK#m%iRrsL*BPM*G-;b%sD)6<{&^tJUqc(nhXi~kzX zKYLucQqKC~3tJ>Jyd#ZJR}4QsIA7!I4e+(VkIcFI5@OTVe!@tvrh?(x^U?_`8}w`l zHWOKs&$@@9h0ubi!fLn#lOO53A`t27g$4(|bNS$dI>d>8Z7}vP&-bq*uH{)>;rL)p za5>1JAf1XtA_%ww%EAGSMuSw--hMD7G_>`}lS6=f=ZP4<*ThA%B7fUmBQ6>Q%o*?FFgr-2W*F6a3A^rTnU8h39n zKk>1xsg{Go$&gT!d$n~lU5)P{<37$`ySkYxU0J2)g0Q=aYS1r+O}Z0V1ASjk!^oX| z6U_b+Zi?-3(7LFUiuL=MZla{lpx%mDcjKPz@x{$|Od*ezInLjU z6ovFSm&Yzy9|E-S9CaLx2N{vkjcM%0Pa zrzeQ?=p{=+-+ihcsb3d560~N`8qlk3-MY19q``Fi_U%^;YSAE(&(9YKPfZkANII<{ zPLoL@j1vs$Q*v<3`W!G-Sy|UEnhL18dm(U}k)PE-ZhCK>>1GCc4azc`l5k53W9P@_ zPK0h``0LWUvt64T(4#KF!_LILPJ4xeBYoYbJJ&J6Q3r*Iy70UxcG5Qzkx#?g85r9C z6~=Z&?5c*BRmnwtNH_HCKL4<(d2Vj}&#{LKde6F2x1#~wh?t4TSt9^PBuf|#7d~Xv zv2pP+{EbIAw|#o1FQeiIG9j+@CoJ13z_PtR!h3IWwr_S;-MK)xd8%|GN8gY=U!&JI z{q3jf{$|?_$|MAvD}p+M_)UJyaL-`On~1a$^rj6Km><9ERE40Ln>yJzL^-6QQw`2_+fcwUfs!H6M@suhTAChxB7 zj_*As!fpQ1Ild1j%|F&*{6WeM_wKnFuV6sk07@26H~i5&!1iWM@vy%R1v>$M7k5U_ z`aRQi>%u2SV*EFihp!`cn?_1%`c9tQh?3sE4s-M%!p%sWp>>3w;f_;rA>&7VdXi!# zj~hVfwMCo`+~n6F^TC`C7(?upMeO7;GV>eX5#$D&Fy`x+^zm`cuQ@}T8Rx~Qb3~eQ zX@;AUw;vr622NOl)nvX++}nV~Edz-KD~r~%$Jsda09XR?&j-*WfU}3%efTI`U~mb> z#>sdf1Du65A-#fqj(^`v0dCKm&MNah2C<4~AeySOUJ6@U>MbZJ@B|%F4eMPdNk4UT zL1QP%=qv2=hgt>k@oHq>_0|j)+f`MslLsB5EBRR+`T0}F+z_=J+9_L5aYu-}=xY>T zd+~{o81pMA$1=M?Shxrj0nSkt2)~HcS zXX~8k{@vJd2T)^ElePWN##wfb)&opm)5|tgqmR(h6c0g@H(^5bg5^Cv@zttuX-5Xf zXD=e(1+liBG6ITM9~o9spVLOcm)nnC!x@G8(R2i68Jx1sj4j?3g{ESVg=L^F^9!3Q zbH$HZs;MsZ0H)nvkmtHE4+Bz$dM!UcZB-y?rwkW2f9TX}8JU~%lk0hn6xevItZW50 zw9W!e3qaG4^<wE=jWxl(g$h|ze-PsnnTY>&q%LGfd~))J|2i# zm6bC%==1MG2feetEowBiP~`Fp2iXe~SuS{ur$3`q%$+@Dnctb%ls~E0_o>z7#xj6# z&!E4r8vjnn=5b4Zzi-sJGkpbdTTQ5MyG^bfTYxG7ThZ0EK6dFWumq9+qUCv|H#b@-g!#G$0$nxOhNtaOtnpwTmX>}+_0sbd(`Gy{GE8Q*>x)h zy?fr{_;D^G=)u_7NgJ2==L_5(2m}e(gfAB4tF^SCWKn|Mo++m9A2jZuBJC{RS?<5k zAvHup-dkYSf`#U5%lyGl8{U*F#@Yo{kuMqhe&5-&>qSL?PAj^8eM*f}5)Ofg?itV_ zbUSSD^-H7HK+!K!DvuiIrCi~@m>Le;!~he35lTqi!wgQrv+~97_L(B0`BAMe3Z5PH z^G&NcPnmT?tko)k<=FX~dl2`o38>Eyqud5F*P!YFCze6c({q+l$k(y;`C`u8vqy7X z1=Vm}D}U=AonzQBOB>LjfR4@LF6@Ht7H4a2Bms2CMKDbdqD%B;P6nrKB=Y+HRjXE& z7axgqadD~j^49D=zB8huGYtYX2Mvp5=a&g!0Kvn{*RHNE-e`Pmm61_A6$0O-6SpTu zXGD75HN}(=)wydFJ-5l-I~RiA&x^dmZPa}Q$}3h_`j>bBz)qYgohX|anW+Kq01(Io zR*0>qtLq>bTE<#wiPcbuo11gH^C+TL0T7xmAj3nJ?&<&@F7S9s_tLJB1I5vkCRYW& zW!m~r3>JS5Z+=$^{Q75OqV2BvzA2rZdEoh9y_)GCS!sQqNCZ?D@%;H4=-@4`2`?Zt z?21O)Y%oZ>&*4lRgW63Wfq=ldf8V118s&dARIGD5`=6aa)aGEb==V{UxfC1FT-IE% zlf*7e9d3`J~ znA4uLFq=|Xljp>AH$_k{+evg{KT)TKv?37s?Ge@}%S?)%j!y9H_0*}4wA_t#obn3G z47NW0euxIZJnM@n?Nr~Ys_}BJQ)c%CF7^{X{(qEDp1fOH zUus!aFTsE*Nck<;5FP+MdQaS&YZM#yPY$255;$}(6&KW|mt`}k(7_OMinvaO@t5Y+ ztsA!fYcXmsZTU0o?egcB&ky-w21+E2v|7KRzSQrKC~?BN?MQZfjlpKZA2!NwRNO9<<)&qHMWd+uer1g^)_*DWZk!^Z@g>^o zUycgVmPEk8GUmoolhsiX_W_ULv4+REKrTj4?rF@jlOTepA_2P@NxF|h)DE3!pF7w- z7qS;oQ3L~t2@KVf0<7CQo*pnMaqUJDh($kTiWA<$VrPJq08Eqz2d4p3oaP{Cg?bl< zurNL8i-%LAqZN*GLFb~HF-YV>NT>rEFx9h#=zyvcjKW*nLrv(7*;yVIi4cb_v|eyr`#Dlvh#eSsLLKIU zIgA_Td~Z+HQ)l9Fa4`i;FfX{UnE_aD{&`AB5vEz@TF5x>nJ3rnRCa41WNGk1$-7)W;8$X!`&h5}7lP;ta{G)JS z0vQaE?|&bd9Z(`vs)El~vmW>nYDmMwYB<^tzj@TM&zCqE zMk3I|O0WZmh;(=2y3LF?&>=$rP3b+Q=33-aLZ%cEMoq}hLJ7kZy%D;S7dNg9kJxHq z;^Sw!9>A7`Er6;UfacjTw=B%h{?8UG6B$L(cVaLzvlxz@-Q1}HDZr+qp>IBSe8c`3 zOThm}fG=B-2soulCRgjpBTv!aN)30i4-|I~gHci3ztO~|v$?t1c|mLk>P$AtFxA); z-clbkdJBRs$^<>U+`?gU5)46hrRgVUB_&zR^BVvOd-n||ZdSc)Fc{!^N&;Zu3N|w` zPpPA@&e#BI$LIQ6E31pw3Hd_;e!iMo=;JYJt(|2N6QazqyvPnzoKh@}l}AH8OdJel znNG<)+gh6kO3!W{BWWB!t5LXlw~XVAq1i+RoRna1zX7*u8yT7Zrmn8eV5`$_!A7a- zspdQ4bgl2n5l6?{647VOiGZkL0P9^b0lVTcH^OXD13{Y@6&akv>bwx4=)X`oGU80s zFHfs3##Ty0B9{x0VHJFczm3O0V;y^zc4eXj4q*v*^FbO%L>Izj?nFA6hk#Z*{E%#} zKRpArSCCo0fUD0Rg~wykcvOPfv(JnNhHbSvQ|wVvhxWNkrnNkvds!QV^wV)h>;hLo9EF$k$T(lE^1dA0oEdyG5$X>LA=4346`)rJ*7zw|;TfS^juxt8Jn zqbWAAZ~lmZHbK>o0Q#{Irn!6)>nlry%Ci7SoQWwi(@)ln)QVoNFxRjH(H8=dovCY@ z<=hF1UXy+HXh9D(M12B|wnseH8HxrJxn>QVzS5nzrU@BZB4N}o;4F9SsFm6EeyN@J z{60VKP~NJKr|(Ade9FjVGN5L#SX*MI_W1L*mgO<24A+i%=H~RKWeVT$ zsZks+D!R4c*|YUO14GH18F>KGS)vBEs*AqehS5t}t~;-wCSB31?Kh-xS~y38H!+kM z93Z)YuE8XK)^%pc7oz_vMVojGP+`@Astb9q4r0VzW7NPC8OIevOUM|7YieF77;vTJ zTDAS3fS%u3M-trru2Je=7`)5gttj7y=yFzHpEnTQQK<$DMsoPv^OI50eD(aXQ7qphsRyI!1KZ31^>5BdPk41>o*e0p0;2FDf5nsX_$ zMD^Ija7|c?rg3%~C9=fyyx|)9+*rhI^?)y;f4QO1c8e~7^4ImE>-`u2i9sSRhF$O= zKJ4s=W)v1Tv6jPE)a`_E6VmRWATu%XVOI!1F?r9Q^Xm`YNQ34-=YSLpjIXX3CLR#y$Jtf=aN*PGPL&uMAH{bQ1k(NPoQgy4# z(F4rKiRtOB6o3t< z{L}eRA5h_%7trwK29VOLsxkq)&1Cd00KqZiV=Yj&s*2%*^i?jB&=+*Wn!f_F-Jgz# zOw|KPv7eXD~n74j{d#hrvhhUVE8^ zL3+~#?B(|%9ESqX8>BEF3@z7Hkog)=5#&QT_$P{G(q~9ECMv2LV6WQRdt=h7g06;2 zXiU^Kr0ZxW-*&IA4pOz~>sOBUY1`)HbiERI&2p2dq6}2oby$Nt(Qz46i2My(qhml3 zskZ9Q7Pm}Pbu0%k?(y;gB#HE0pak5c+a!F3fttC2bjqv~!r+Gh_IFelky_BqVKB5= zuI0-jaw<|{bF=fSx6l1l&i%jLl4iw#$=DUnlkP)}(UO{l)g8@MfWPjFYW>N`C==wM zqr|Wh7+}%}MW)do=2fl(4`m*g<#?6zc&0AbHh?>V0z z_he}37~#Eu6DO{-GJ+~@-D>Lv!hw5EE%jdnM@KiBVY%*0+eXZzJm-OCKp^!=3qJSx zH)dv*13v3@2Ic{iX69{%Hk0^46oVO%W&=(DBF1i9N3H<0nDgYwqX&=Z4)e-o?oGKE z+lgdl`(;xXD%0h(Qt7DyB~p`!veN1XVKpA3_FQYc24-{v+$cZ)$9Q&DZ>c~x~cf6mA`Sfj`g#YGuDF4xFd+p z#!)#ncRzae^j`F=gOxuTNE0R=@7pLMC@aA(L z_5`IdcKoC-Kq>iWHZf{4I8p6$53ZiBy)x{a_k0c%`NFTh`pU}#QgSX2ZA{*sTv;(N zAnaWza)PuHPXMB@wxdo4TUG!iPw&&`r-DzM`k6c)jLm4LvL=@{{UGE4sxu&bV*ePB zWT1#(02Zkp)4DIE)Yc<`TJ+zIBxn@%9xGpG?E170$jELtCu&A+-?dBo`0*itHj|Ud z%{}#BSlHSFIeH8}YUj#)yVPeAHoz%^{OL>em6hw`UcB#G2;lWWOn^a3N^?IDvNv3Z zArBzdK6)9Nokg&+pgkfqn4m2GPmu_aTpOYQ`|kS^d%)Br0BBa-6A^2RV0G?9NQ;JUkFY>l&VmFW z+d&w?#_ixSuCJ7Ex(}_E6vEtgg4VWu4$$alEwXtZF>YPS1vL7l>hDGP%c=n&G5e=A z1D`O&NXp|#px4{)!;X5oE5b9f?InBFJ;)b@aDW!MwWl$@iKr&8;`URj;ee~|r{=oK zDEEIgJpZ4@9>5Gm_(4t>ag?Z@I{;tKt^2SG?!;r88CqbPZVC-a^rDwrbw1T5OUyZx zD2oW(bUxmlXuP34!WbppgtD~I>i}c6rw3g5P`eg8Q(os|?3#NMIQ|fbBu%Y}lOZ7{ z_wLm~;xTPxQc2{Ba12Dd3Y1f)SKDA;89zo???(FjZ=d^ackX^5!o0fh*k-*>Qe{0j z5dbn>rs#eBN@*ql3EaCq0+4FUhwCPExH`?RaZa~Kgn)k?K12l41@OjP>_8|0`kq9A zR^!`Uz8Qi34vjm+?R?cYU0?F5iIIUWj@^U1h7K6aQr)}-eIHLBJ$m%CXL9$KLECZT z=2SgX`frAE&_y4 z81NF9Dj*TzcMySlwrVp&2$%w(N+wd|o-)b^Ac0C@Y-y#i`diVb>r6h&RXvba!+RRn z#Af%-fsw6HTQ!Cp-Wuc*+jRhEbnY@~2um|b|9^a@;)WOnv*(w1UlzUUPFbo&-GVkpknqSYTb$8g3w}AgZlqN4SBAse6@C7H@`7+)O#>9 zaCBw$_fD4(z|LYx6{BRQr{Ocb<-I_-3e03cxH{YvZ@zKk#%QgHjgQr)T+?v=uv)+d z<{0B)z@q^CJ!*=)x)?o*H9rq2LpR%+#vtRjZVU*xAsJAQSh~7m=ei+#!^$cf(8@rv z!JCjO%?s$wz=*P}Ds<1w)&_FAl-!3gOMrW8NA^VM9?wtF-P!q;^U7Bzbs-Sk6{{!#En%Y*rMWI+G;j4#x?K2nT0U> z`n*%WVhc611wzv5V^4MK)&7+pF#i1F?}3v%Y6fL^91=VOzbIb+$m@2NA3CAUGqEQ6G6ETCi~7^IE@W!3&yAuN;g={J03WS~+OGg5YSk$1bpnVPl{0dsZ2SuX^oc5~=xVTy{a@|_a0VZDG z{lPPlBr!%<&jb@4XJXvnv8KI~ptk%1V6)K0S6O_mfJUP;RuHFfpf2$C7vGy|?m(hb z;O2zz4xqdvL4gzhBQCVt!5AX{IgP{Q^^zzY?9I&70FxCK^RB^np zo&XziS^jPu%?m(9`p$n7>Hp|3{d{l2?>gUwfnIy_LZQ29irCzD)7?GDP9J!?yF)2P|&3AQn&)5afhk9wiPq}sm;M&`!fb-LFzH|@dW4nI+IwU(QDw^VQ17~*+0XrzH^g{i3HvtyQ}MOcqg_))r&C>z3UW_a~}=x5f+jQdv58 zu2SUR09UbT1tw9~?mrQOnLKX@9No6tUDmm{u`w4MN|F{`#`zpWTc~%lZc|%>eyde| z=D~yg_mY8!s{+#50Hw6rX9HXfkQzsv09lK@!5|)Bb!ctD@%0CQlL2TdvuEB1M&;gJ z`nw?$1n^Wg`7zYH%FLR(Lwr0+^<_$Cfeg=ko}YVptjQ`%bU! z2Mzd>LqwL2IY2+JMF12c=!A8CprH{kfpa8cTN4t*ah`g=#QHDv3{{=_9&yOAPa5anpaQhd5QsE?eQ6T}u_76syUvbC-o#&&3L_``8 zYqh!)9|8$wp8Auqb5#IO0Bl?aF${=29!rP)r8g+AvMLEfJXi0gwyu8#VIZ?2;7|-I zt+{v4hw$9o+IlEEKfmHfI$b+P+fK=+P$d7;Ow)q9&(QK722bXpr4>6PJmU)njV^rP z1T-n2TRN3(ioKB$D!~;GVN<;kz(HnBl0Apkm>^cNul(J`Gruc={;r(lW~M(Lflu6=j)6X;ii`BP>yYNGM&4GB`QFrkfJBN0fh#)Bdg?^UOpfNxeCN@g!U{ z&GG^kH_%9QcDe$Kn*&%o5fv2$rk-ccoN0l!JwhUtwlL6rrRiC|Ju)%^W`^ZnTfnlA zf|3&B?2b7E#KjK0rX&jk7ZOr9Iq~R%p@T#m4Ye}7WKp#}rrVC|4Df#5!sC!)bP3#c zuRf$?hI~BMn5Y=?&LXQ7Y5Gn-u(k=}Hs)Mhdp9+N{E6CX96|T4})I&N?>ikptGr|X*e*&EIvo8F^bx;KOZjV(YFJb z@}RZSfBTi*gi}w|M`FA|L>Y$!5&SrSlEU;Ca~`4-%e4Y(`o3BoN))iIW>1 z&qcS-Esnb>sks2!V9w`*p>K^j*vNJ6wdVkBu=p(={fFtCBB&*r>VBkVdh?;V=--oa za*H70XIH;xN6a?a4ggH5t^%2})kRoI58%@v-<)9EEI8kjp8_90GzaxVaTOF^0{;ro zh^M1;{*BaM|Mcc0XkA2B2Ise8-)_^V%NQnMP}daR^p2ph2Z;ZeBsSJBhn=}B0Cd{S z$O1bVE>mp!J}1_B5b1{aISI!ZXzNTDfKR8aNw_paj;Do~zDjfF)5^TbwN}>FGeeEh z(a|R(BTd0Bo*Tdz1KP3R;4S&~_|elEtcTIhAEi(6`H&{F#-|eK6TmK>4;W%hItK#? zX=n+?^nQf62xjggE?O&H`1mSRDPhqod`~qy6fq z4K(WskncFYK`jkQ_?qGiwov#WfMind00Ll$mkrSYRsM?Y_Rv(u+{)^ntPuxJk?%Od z4r>L3=8=d|ntisI)6**93e@Q+|Z4ZOl(Ke&!+KuZIt zmjE>SSWnN7UFeh$do@&3PqmBP-uL02sRFJFCn67sZNL94B-Qv=7B2ql`relc(VvTb zJAl|XVnHGS*0+)RNMj<9_l~tBLk5Y^;fwcy*(Y8c0v;wfB5J?*D(%k|HNNS%6fbVy)8*?F~Sc2E8yVAp0L| zV#FRhdUXGvYjytdYCE@I-sJcPHbVa5aN!0789IV-IJ;l44?8+S8vI?mP6h;Q?98=X zUNx!SDyeQc0Wt;K`j!_3{ddoxe!XV>@Lg#Z06cyozgag zQTXByz8^V$q@z=ov_$#YAK~l&KC=fMqNDRhsP@nAI6g)ZIyzpWy}Ld-9N{^s(mg|# zq@C$dtlVnCEJ6kxOIL7W?>caPb}DG{GlVwOC7H44>&>EeSgW3^sg#sJ~uhO z-V^ce>u;<7i&?;397C$Ryb*m&L(`?Lz#zxaLvp*n(0chQ8!lhAO6~8K_6PXTO|u~= z35Ai!q4joGnN*v5!S_;c6lvTx!o};n+poNSe+HGeOh@OdJraIjO#b}evQYR&-+uV_ zeLOSm%bJQ%?NY|vem0dRSu7IfY=2$Dr;Ck;h02l!5k_;5&NhfV84zH?iR9}J(N+AO ztQGK6gijs)6!-Hcu^M}gt5Tt9vmCA=E7_t4&Z;`o=?9uWt1C2f4O=P7=9^ot5KcRW(YpFrNC*rctE+TGutGe{* z*jUswtI{@N>g^&PakZ!nCBAvPt5(y9=|lKe4tY0?Q z8lT00cbWa&R66S=llOdvb?#bnLW!Od}p>#8CrpiaQcq)#s`A&$k zk>*8wj+4d34C|rvJdEc4x?N;Pe4Y4|JHFSc1$S!P>ouKE#~mFVZQG@k^0}~S-D%+g zO~xFndi26R_QM%UBYB0>Uk;@SrQjE5u~88c`Xvf} z@-cI+si|qUkpBJ~Wb4_o+0B|*Jxd0S%p&l{KOts$G~iX6SNPhA7p?I!ckpLK$e3$Swu_&DKEsClO@s=x0Hy(b+2DEN-rfd`FVZ>a?G`Vx0=XIB6X* z^_^~|s#riJDyYLqV=XG>G^su30f)r;y^UJ+a zT2j(%NsqJ?aPYDR``E$(b@Cl~Lc$eIY{F~f83 zn~ibm)Bc(f?nNU_J2zocccfF4#30Xwa_^xOpTHv=4lz={LD$8P_=p{(gt_7s^so(f zhl~`7NKN!?Uw#}>m`kkjwq@`QRXiDeW?DfP3TMk3XGC^NQxl`7jS6Ky4*!6Mo1Hmh zaGraSD;Hd#Ge^<`Xd1gt>C|9@MigU0tF%&2IsBO}_ELYUvF0#zufk1F9gcpBTD^pg zi@x3=MQLR8)tapK^BO)ju<;ss?9^_3Ke~Q z%Ez2F{*6eKQu}@GMKct;2HB|~2m%U7Ru7H_MA7YW}~g#vD(EM>Ki(4}r>d zZkD8vqMXj9%j9IuJ_suUUl-pzesApe(|3KdX&T*uS&mTQ7xcK8oB*$jqb(JQ>8bmU zh^4ajQJH)csTuKE5kJBmw`Q_?hEUFV!g#v$+79U`l97%YC?<^XQK1}q98!H$Ig*P? zEtm6Vf`}45^=j0v*L1$}H>&qk-nCG7O+Oy0?mAZ@-IW(Gvsn`v!`rMWm~~cnYPP8{ zmc;FXL1CYA>CwabD~uGo=4{`pS-e?Sb4I10YCcvPX(-%8H=?(R9dX*tC{eS*?pUTF z!F4othiDzuAt%c-$QOw6#n`4stTN@uow_$QU08Lr2&3vxYDCpedj$yxsei84Txez0H%K&- z2^hNaZNg)Xv}SgeF0Bv=V(D+FRCSrMX%*i7)Lg3!RXj7LD6$jJv0|q3&Z6!YlvKC$ z5RKJOk^d93BRhgj*5tLaYUPO4Iyx~}BZwkhV&M~4`B?{d)$kl~W@X**;5pndN@1<3 zo8@biWJZoJ0ika7(kPzJ&0>-;a}1O|ahyKuugo%DH8hj%Hms*cS|5MxUN@AD<0kN> z_)Tgfcubn0$yU|}cvHgUCl`w20=Ht{dTNGRLB?y$P8dx~xN@&YrA`ejco>(3B0KUU zEMDfk9Uc|ONPX*VIH-a;dfa3koe{8E`E}l;k;;;8D5h(W$9um1P+9nx)o4tZ85TV- zQY6oIVN}>59D(nHFrj5N%NXtS2pjeA;3825N|gdNS$Wbx<%?}Ls#k?8FBq*k$?3G0 zTniQ@U@npI1G?YMuBTy2%*pCt<)l!3%^0INsQfFYT^>PJQ-^)+6#pZvP+!R6N;=ol zMe+2hyXm`Vnjpf+PHtVgx(!L7W1mD{rKo3eHUA|a@%^}SvG!0XafDN+HumZ0d@Y-5 zAUwVAsz)`Ro4&7a$+;*HOp1)ut(y1MBP@;m3a)y$G6N+p7;e(jW%#0GJ1$+aQF8Jf zP?DNnnZR095NEf7+b_-)DP(TPz4PRr)TBSB#bY>1^x9TgMHlK*Q61f8T8uKn$S2%} z3&w}JE{ChX;S&qx8!rlpx}0+>MG}fqhf9>&;XQ`@%=`;3XHsJ_5vn?m`F~f5E!}}_Wp?paFWKBZSohgTZXz_ zZ13WBLv?5>)2NeY{WRnB72LVl!da@Ws;6C5mMt2mm#x65KgPw>MOjFbl+MGJTQn)N z?ScSN$zm5oX(_{b-RyvgBkrTtVs)sOF zoLiC0LIdK{B$Mq84HpL&=?xj6mBq3#&o10sxM{Q`~+O=y>FXx+ETI#t`JQIc)N%j~F z#w@dEW+rr?A=)z0z^dcY6CAH4t+yc>cj?llt?MI8Zry5}osBTq9{S#iK6LrRoutV7 zALyb-)-!ERWW*uF5l72o4h{|ujt)nQJ~#KlMv!By$!WDO+J6~-(lM1kPzg< zI2^8CIn4~3e)8by8_3l;-XGK>I}DO;2PbJ^M|=ryfl2?J{DwW?7=%3+SO>C{iJp zYtS|>on!}zhMKnF=Rzm?tF&((9Q?rupFiAqVP)$cg5H*6=kMOVyDet+jM?R$j*f$u z5)zuqycj!3+3!A!m@mEUo<07gf_It5F6j?K_-(eE0!+=!QvMWZJyx^Z-o6+By3b$e z7cN}b*p@M7#@-R8t~)|u_~KEA%goQCM2 z@4h|@SFdjw*!cC=A5O5Tlr<0h@Oaz&{QTn)5!-(L9NOC2isr^Cj0Y*kxm2oUt!E@J zt%y#iTV3s$o(_JujoaJc`tk5B$-2iu;fPfu3exzl^;iKVIOCkY7&=FyWk`NjMI2fW?5 zcoVZNWg&DSZx}s`GDhcRo_)~B!;I6x!R7N0Eczc$a=*b-_&aIz)!%SyJk8Cs5Drw< zU_BffF9N|%Dj3v>))@O!yDf;gHJ> zwtWjJdbl}Z_3G8<@d~Lqq-Y9-@#xXvrMkM*@YwmI{5&~7KWhFTlbnkR3XDC8Dv5ob ziI0y@QT3w`ZLx@tkB1Mva^=dd-rge>J&94YC{FbweuW*Se8T40(}FCY{Ol3hn4k%7 z`nFvy++b{6?AKH3LMwo#>#H9Wp;zzTFTUNs#SeHqPg)ZrVG8Nwoe0tKt9JP9;gkJc zka?}F)`-R8prOVKaL|_MZP7j=1G|_zaL@qRH8(d8!F_*+*>?FSV>e}NZ0sUrt)}M( zt&NPrgyC?OaboQw@9OG$Dim^+ANJp_u3n{UXmg%MqrvY+2^0R?4mNYrinq`z)?U263MH^j@>*1shjdc|VDQ899TWF)Bqj#cZfd*E=H`Y85 zwxn$?i4BdQys_UarkP08&t=}z{{FZ6{OoNpwpjNuF`Dd# z4$t|?I)u7t=G%5SB_*Y+%CBb=>O7El|DF+%zQv7G$NhGTGjnnh>u|#6 z(ikpi%dtDJ$HoHAoq7xxl$V#cT3H00w%jam&w$g$}akxnEp>E2QgmG@2v-)ZUcs)=Utl1Tjl*&BMMPqs^yL;QF>%R{L3I(|ZLo+aT&KY>P{vWI)^>JuJN9@O& z*+WAgZm0Nm%GVJlL6rhG!_O71*V;N&tY@91}B z`6f)-u%2PZWN)jst5$~`ot#{?krU(mQuFg~89&o4n_Y-RVnx;~0L<^R&)#u$bMrcR z^5&Wc*ucOoQPI&}tQ=dw{*W|+;JmFiFj$HX@4kl+-av5Y(Zo|Hw7>z~R)9zcut-YB zb|bR}3QbMTwNzdv!unQQaCo(^*z=S_!)pK|S!>y!<)lCF z-#(a;NSb)e^x-EDQnDgLwW03fe(jMSr^KB)^xfT9K<$a}zI}atcW^>agKcNNf+EwL zpl|yA`?uxSuP+-PA2&5Of9u}8dnJRPx~KCFw*=SDzan|{m0CRohfoK_)Ha)080r+) zSu>c@7Nozb!#rfOhxOu4^UC!e4gpv2f|@(&g5*V=CO%e|%lG@8MOYWN1#j}U8az%~ zzmXXWSEo4I5^U>jl~!&5*M4dv^IR&gB$anJm6u2=zv?LCHH2cS8=9BjFYi2&!RSom zeMIr19&vVdu2;{EC+%~8`0(N3fI|M-b?Zugz9A(iBAoN6*Q-i$utQJVXMFmxpSc^X zzPX!~Q{wYQoKdt5!%DO_jLb^jxf{4Tty8`#}=9co|EQHwK*^T7MAbs~R z!>kLEb=YKoRg3H&>GJ;-fqrXzPBPx5R%ronAeXjI59xWSv%r~A>QM)w2xw3XiJh)) zYX@-p_?vSOx|i<7=~}LjG%+!00%&Pq9gZN(R>YWlM_z*<`R3e8)7h~Y1E&z`XB)Gb zWyqL!67xdpG$mAcw?N|9p&(Na>jF%)NqC-L;j)xb&J}0b{R^R#O5Tp6i(czI`Zlwz zNc(1JN_0SBk2u|PAKEZ*BQr0Rccf+dNJ}u$0nKqjd+tZ)K-8Sx$b1lrX)92aPnw4x zAZ2fW?zt3!ncf~A9~KtYR1?A z{9;|hU0S;2GPk8=pFg|WBq}N@Gr7K~=pv8DYyFToTTxFgKL+R29X%Q!z!ZMWnu{{K z?3UKX3*KJPFgg%k5Hj#ZLTKx)e7^#e$4-yYqo?onC$1BHs*pZ)knMAK?O1zz(iRi!{11e_dG! zYe!O~jR#sV1K0JUbAJwb?!C-DWa$oC?00r%4A$X>?KyWKPb^*R(+`qpEKCp! z*>~2rcTmoT+OhJ*+ilF0*V^mpV>M$|<25Lo9I+eT$vGi=?%O?T%zXKxv?4n3mvfLM z@RKX;lkBA0jIey^;ap#qtJ%GKNwzs&#rz`vEk0oYsvzEpdOQIjlO=kjFQ*96*`E`B zv~R5Evc#{&Na{2_&ue5}y?P6dnydUHEkpQsxUhdoH#S}yI(pE2>()mTBfpkk>~9UW z@rHP-=gw1OZ{Qf@3+vO7mOza~K0Y@q85TCr+z$m>sVyx#C`K7kANjQPihd@b_qCb& z7x@%Bqv4HAg^4$ml9&;JS&)2BG@5pXcP;`)MOX)zF+(w)fg)PWJA>&AF5a?r(22C! z8kZjuWwX3N?z5dSdBQ5ad%Bo~B9~sPZ02B3B{;Hf)v+q+%>t4)1)G>N{k}Ky z_`H2lo{0r~-nE?!cfvY$pmC&@0Tn?r^@4fPHiTWV0lhD}!KBjCQmCd?RaKx0e^h+- z(YvPs|F?H`c3yho;^KlpBC)Ua2a;rmNX(7QqIu5F-sTS7cCJGnz}#0GSluA=oVi7T zjOsE$JRR6c3K7A+gVw7QM6RT!K}&qm;G zD1sHSlcUP&bZ_oHOg(k7;fU~*F|)L2^PrJx)DG>)zmtuqv#jl`TF-P!(eiU%#pMGv z^?zhBvqvNQ4wCdYGP}C6OTsT3yAb^?u^i=Bl^%3LLqDBJ4B19uQ?ZPuc)j77(atg; z1>iCtJa}*gl+KmLPFiB~&Y5?BQW~Cmd=J2lgM)*qg~cjH;=1^7Z3>q|fiKk3h|^~t z(zmZR)?V+q(7~noA=@K>cB^C8%&QC$7(N{cVUTfhs2Crnj2m|P*u5^_P+F7DEZhW zs+5|-D+nZR@~|$S*gDT?S8rmbdk%ii=Q+$@H}w!n4@rA;8lG@ih7C?IklV4!%*@Qi z{l_fjTbVzgxY?{}|IFyOCj$uONQH%IP~}?duuTmaQuqEb`G!P8{6v`nd+6&A&7-9L z=4Lj^UcePmrBQ8B0>(Ok3;e@cTv5}OuLyp7FdY(4?kLU1JbY~DdO5KRx-3Ejf=|)r ztgr~5*`2wO#IBGB3d%7-Yc=yt!OB-o; z1(e|Ko*u8$r#F2O7neJTC^$$uw2>*9N3Q%K&Z7?vu4sF%I@1r{STs78;iw;Hau$-;4}f6(4L)!XxVPy_sufh zJhr^tCj^S0RJ(iy6#r0LwzcWDZL6V1X8{yO2X4)cG(p(t7gyMtrnX_-M>@hf>#A2p zb0Q0%K(8Ov!yW81+ArIy={N|D-*l;mDY-Pe0lEim+IZZT>V5PQFw5|X{aeaCW&H;! ze8q{rAc3~?VjQY!7C8D%9EkUuI0l8-|09y(AW3E7U30bkDz`^_Jn(pYkbIi=kFtxC zzL6HKwqHuGrv)4zItj6TILd62TG=IbG_alP^|GpNI(zo?%tYU5pNQEqMu?QV zN!Cy~S%nB|dVmY5prgj|IkP|r!Ho2s$ncHMEVnTyb@#4y6*;v{O&&!HhlnBvV?;4PfH z*49~;l?eCAFLjs=*XN~={!MyeXKTa8T@7p^ z-VdMXZHHQ)6?hA{ji$4U76VlkIB;jhqD70!kRE>xID)|>6&4n*HZ%+@dC%^lwlf4I zti__)_$>m*WsPS?N8ujmuU~KaWhohtr4L?uQk5f!FAOCvEl`|r-p&X(vZv=^N$8}( z{+@3WwSg|JN%gL^UkG$<$J&IjKS)~a{ZgPC?)RHGyQ-&G|5QSD|K|wZe1xnrmA9j1 zy8EuH^@Ef#AZmIrMAi3VXKrq8*U->$Xbc(~cbQvQbWc>}=1_8|CKCBAmY)Kh;~1iQ zqv53Yk1*vtGCYzP5cKI+Yi*;eGuIftLW+QRf`tQF7#i3q&V%+;+iwn}M_Oo+Vm`t- zAGvGE5vT*RT~2_ zWqI?3Py##n9S_Uc(K)NDrMVV}JjL;eC7APGqjr6oZg=3os3=L{ohzl;os>L8XVs%G z9)w~a7HIQ*l?$4dS$?ahq59Fd+@XA8n@mgp4;LQw!tC>#xBx-14bKLPwMAqJ#<$!*`5w@;Mx&ZG1(xy?u&0&^PqU2tSPt_71fFF z$OdA?qQkr*vou>Bx-3lFF#A~_B(c5wPC@K^-%0}O0I_o)aO~-XNoPNQ3?%b?N4?Ui zZ!@zuG6kgafj#I_fqxaWPIF#$k>ZiXd6OM^4qe}VdjP6ZO-;?6D9LF96rsNAjlU&a zOXBmMDG!xdyoeTn^pSKZ-%(M25hS8k+Hb*Vi}Ca~OUe|3IIq8W*asZxt1)ZtR0Tb4 zwe)%~d)VS(p5Mrrn8gr1Dg!bX7i~8 zmBi%!H2l(=z;_-bxnUNrW~C{T4o0@0hHgKWIeMfOHd!Nvd!n<*6HJ=peuI)`r|f;$ zd=;rWigqE_-Y6QusNVMefrK1e_tvGlC@HWyImI~@If@`{ow9;XjtXr0;qBA~`qCKA zFci^w!sigFpt)l$dx#Q6GkFla!8>CF3!UJ95=8qyb~9WIuK+#)o}|z+H`38Lsc}%` zJ9MAN)RGXM5$}Z46@iy-jNe=atyyzKElS&(EzJXnRukHK46l}N%PGA^gB~wKkWj}0 z(hu-DFbup^6*2F4M;;@s@uw1OJBHRqzgtp9r~MIa=!{+tgvqg%>9Kfi zAJa8BxDKKs_^M6h2f)1Mjw|J27u()1fJN69S0LWOX|1h@3(QaD+C3iEs{`1pKw<~{ z=;G2eJw5I7)uc}(N(+K+0d3XY9o`tLVCN#C%HFy$?!%6LK>-Qkd7;Fae8mlGh;RQJ zem>?N)~eC9WBUMXc8A|UP?_^rqIgkbQ(vmFY;t!m4Z=IEvUv;kBa-zY(jWk@GkSY7}R z#$lAUTJeqE&=J7SbcriK$w_DYrY-q?{29LmEcwBpzIfCy+1nRj10^3Z9!4>dM5!+$ ztlRMOj-jIN-t>;O(bt>Ir8^+A4t|cn>_ZFSq_a0N*n|R*zP)XTRsBh68(Ai2CI3@-+5`Cm`$n)9h@mGY0ANIv~tTHSyT35 z>0&6c^vXvd-PZfLJuL9^75cY)0OAE;YVV9y>p`G#)#B`DpaE3QtMe+S=x|9{bmv;@ zM?-6^E#LHO@DsJ=gqKfno+jdP(k9y7RBzy@w-g}wviX1qV)+;?M*eRED(yS{N_CTX zO7ky09daBg8-0Bal1|YRpw>J2YVx_1>SOsza}5IMj$5Ur%>Z)d70_cK z-ZyIn-{ksV)nZF03YN@DeB+ z%hw-ueDr4L^A40*Oon)R`V1JdGa zKOC$L+q~S+X0>(r1oVBGj+Wg(BMg0gb`g|U%fNy2XV0GPO<$E_aqD}_kn5X9KG0QN z-G?rPirm^}rzgvQZRqP6AX>Qz$;qqt^ss1DE`YY9&a$S%wWu#T@#V%)#t=9BMqF#d zm*@MPw67)gzppsf^1?iSQe`DK%p~o&gbCywUW0|LBAU+>~d1 z0|gk$Tf#ju#@%h(u9gpU9waRprPZg6?C&|?u5BV`W*WySboI|vgP-H^JuAz9Q}6~@ zx^JuRrcX}EMB|4FsJWw81Dn=HZ*3Ua7hR%UyNB{FE59ez3>b&X|JR58@AP31LkoOy zIbpKvi@B;3s!Xk-r_PgyuB%GnmF9Vf&Xpk>9T*2ma9F0pL0np(ZvT^-GiV(ME#-t( z7rONHy~I?W)Z~a4mo4|aC4+R})|DnmQup=&D+6k0LMZ09=+_c#7JSD4i^yCa2$Uk1 zecQ|%jiPe)qr3eu`eRi}Ii$gAE&#u|49O*gwG%1Q--U#vUFq&6VHB6Rj%dSErp(P7 znS&dd$Wq)wBfbPt8^{#n~f_F;DL%1tlSh%gNipOPF z>92LjZL-?NAMTIx%vV`}6i{vb;D`R$e`7=QGmZc(E&~I{jx|J?CmNv)fer?21?pCi zOfa}D_zB3$+_cSZ$Kfl}4?ch?gDT)YhKGlPo_>1`+79U9A|UXgnV6Z`Gq8@hA@LXu zdJ`P)oZfL+ov?Y2RtYK(@x4@_82&a3+k60+y(8klouKL-vc8xpo-n#{0Rk@b#7z{%+Y|&`{=S8TR!=xF+N-ebSX8}TUB2~ zc9+EOVlmsIqH@y9Cn^g@t5~YVrxGUpf)YGNHL)uX-6=)jl%*a!l8 z%nKjLd4#p!d?k2h{)qCR^vEn8v5Jv55SXaZJW|gQ7SoAc%g;ktPo9dJ6pzIm^>VJf z)9krz1+t+QG|hClMxq0Y$sUc26y>=Je>jA2s46eVFEq6B=&@t|;IF%KfqcG$pSvx$eXDRdk=Luu0`9(`I|ezk#0N>)(ya|rs~2j<199*M zTV$s)0JM+*Zn{xZhM8{>=&WP?ReotkyI_RqrzV2_xw6HpLrS+xEjban{T05>kRJeR z5Bw0IW@jh7%KT%wV3wwUc5o##^Wx*jk0C!4rfThF4O$scT64$J{Po581zSMpP{_ze8nuRghvkYC!$$9S<{VM^(uC9y_f&faL81Lhv~&acCoRbX5hI zQo6_I*d|bvC}VurhDguw?oM%is&|2{BL$x?$TOFI2pnlb@{BIXU@a^A5; zVr`H0uxpXz!_SOnF9vYjJR|eQghK3cepP+F0XWRdV7}+6KoGcFT!g*-%l2dl`M$29zAP$MUbM-%L9#* z=TUdu&ciyob0^LE=bF+;)i+ad!~{vbR^uM7ayFFsk^8zTo0nJJX>NmyY+Gf6l;!cE zA!RXnGxZ?ojp60bTa16yL-$p`1^y#Du;Q`Z(Vp(Ol`OnqDw1x%o|0a3_zo1@!Ua&A01FnQOa`C!5tSVRyR={R(|Im%OO+z|B}C(Tu{ip3xyw1b53PDvRh z@UD0|4=Mn+Lp&W0tw&5@mtuPFZ|EOow?g9w3=eu9E>50bETh_Ew$lU9dwW`|Wt{jN zi3D=Nra?XCsQRg+Y%dNVa4(44r)$IKI?W%Yfn0xUat}H%eO|5yADN`KhZJSY1$*m{ zFYE>O+v_(m4apyu&-cbb@=utl2T?&A`+sNjXw~JvHF~7i@(TsPy~tgRUnl_1Sxw)g z|L}3m4g!CC3i#v8-MttttRltKkwY|2l}<6 zNYE^R<3c-AjZt-B63B`gay(Gp5RBZ}1nzmRqJbL^gGJ`+Gz-~#{w>)5DL2xsEc%wrMfw{W8~kM z5BfhJa0l<&|CZBB67u9lD+E*0V+d}}K30j8)LVIfw+&7>DJ7>b?i7RY$YP#@FaxtD ztXcRCyF4ScR(A{mIVL1zXM42o3nSk4bX>x? zBKqKSESTO_VqRTg^K6uuKR+Y7!1+x(MR_h4D6X|l|G=~*)hG`U=P{} zhCK%Fm|iZgm+d6;9zB{Gi8?@85)dJ%;al|l&d=X>K4caquX``T(Nq!7(|*CEAFQ6y zt+2`DTy(8&YC0S03FAE0uek3+{U;uICGo(jpYsI*?C9=!aRF)F3fJmf`*B1`S@uYz z*2Xfw62WV8x$^%WyCp1fk-V?92&K%=aljxkW{-Brjs}D6uw$X%APJmoy*H|!Pp48+=X{fH*QhCjj?-@1vuAhJ0kDn=QE4pfp+wucW9d?$$l=}-> zT{E({^-QP|e7uh+8C^W(D%YfP&D4Cv#DT#4yXWaAUIQH4zw!RI6bRrlgi|xor+U#|N^}~77)bnVIIT&^pFXyEj zrBz?a$k_Ww>N?4>zv(|NMp!#*R~95il~%y`891vY1${^R5)ExPF_+H!L0?==($LGJ zsJefKg;PJjYU-ccXuM1;AL+?+NH5a5-z{HqrP_cc0+`eMf`Vb-nu4C(hs_Q2&2FWQ z@Riqz6R;q|&)fUmW(H&U+iN?YFZRf7E6=Im2)J~ZICCMh^e{1>JllI9pWm}o_7>W% z5Nx~=aK~Txj{1uv**NnqPrNy;LlWj`zI8cw1i4Zqs?b3+?$z zJ%;OvUras!r|;P64tt*J0zIi%ZeqM1vU#+#zzbGYK=-^UTUthoG=FbO)x;KzhFaPLN-LolZFr|J^h+!v( zvi`7ZoCDzbY1Nk(-+Wk4O7;3>U zeE1Ce6PEe*?MF?vY_V7`cig}K@aT?{FE2N6A!Qr?*b|P3&^vm z=yb@dt2__5x%G^^3>Lp+y|hsUmannrH#r`Z@1I{BG{&k7;L>cXwX559%DX}&u}Fn$L_{PeCscy zDFP7)gnu9eS6P{8vbAKhVWTv_L*#{$dYLKNVkRwXcuGU*m)?TiPf{BHGx|6vJ71 zAy_P?KPp$@B}tf>@`?%_`ygW0)NVikP-JLmXr#Kba^{S?=S4}CWX2TNRQ=|Vbf*1= z<$8~nR+1fUySOqyU`Z4_rnJUpX#~2OR!br~X8fZ};YTW0TU>=^iiO9Hde~+bb1W9y z&7>RBG;?^ntGUuoLvChZL!w_72BS?dz99}u>=3TYZs!qasdxMi#Gvy0@3T%*=XD`zo%WJ)$$k!8fcN0&?; z#m_26vRVm~kI4~F+iME3x93>hvV#>){-tY@)Eot!_+7h!gga<3D?nZL*|*5(q3jG% z>>sGUJ90lxeNZ)WuYHbu3aOHQ_fc&eCt71boHDiupvmDyF$J0~89P>HXy?o^V%w;v zsJb?pmL*9NtdJaEikdMtiqyp5r_znGMY<|+EM22EpHd4o&B^pixwTGAFH1GR%Ii6A e6t6+O97peE_;{n%+&>5fl7|Nj7z!lBLp literal 0 HcmV?d00001 diff --git a/A-Star-PathFindingAlgorithm-Script/pathfinding.py b/A-Star-PathFindingAlgorithm-Script/pathfinding.py new file mode 100644 index 0000000000..693bdff2b3 --- /dev/null +++ b/A-Star-PathFindingAlgorithm-Script/pathfinding.py @@ -0,0 +1,239 @@ +import pygame +from queue import PriorityQueue + +WIDTH = 700 +WIN = pygame.display.set_mode((WIDTH,WIDTH)) +pygame.display.set_caption("Path Finding Script") + + +RED = (255, 0, 0) +GREEN = (0, 255, 0) +YELLOW = (255, 255, 0) +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +PURPLE = (128, 0, 128) +ORANGE = (255, 165 ,0) +GREY = (128, 128, 128) + +class Node: + def __init__(self, row, col, width, total_rows): + self.row = row + self.col = col + self.x = row * width + self.y = col * width + self.color = WHITE + self.neighbours = [] + self.width = width + self.total_rows = total_rows + + def get_pos(self): + return self.row, self.col + + def is_closed(self): + return self.color == RED + + def is_open(self): + return self.color == GREEN + + def is_barrier(self): + return self.color == BLACK + + def is_start(self): + return self.color == ORANGE + + def is_end(self): + return self.color == PURPLE + + def reset(self): + self.color = WHITE + + def make_start(self): + self.color = ORANGE + + def make_closed(self): + self.color = RED + + def make_open(self): + self.color = YELLOW + + def make_barrier(self): + self.color = BLACK + + def make_end(self): + self.color = PURPLE + + def make_path(self): + self.color = GREEN + + def draw(self, win): + pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.width)) + + def update_neighbours(self, grid): + self.neighbours = [] + if self.row < self.total_rows - 1 and not grid[self.row + 1][self.col].is_barrier(): # DOWN + self.neighbours.append(grid[self.row + 1][self.col]) + + if self.row > 0 and not grid[self.row - 1][self.col].is_barrier(): # UP + self.neighbours.append(grid[self.row - 1][self.col]) + + if self.col < self.total_rows - 1 and not grid[self.row][self.col + 1].is_barrier(): # RIGHT + self.neighbours.append(grid[self.row][self.col + 1]) + + if self.col > 0 and not grid[self.row][self.col - 1].is_barrier(): # LEFT + self.neighbours.append(grid[self.row][self.col - 1]) + + + def __lt__(self, other): + return False + +def heuristics(p1, p2): + #MANHATTAN DISTANCE + x1, y1 = p1 + x2, y2 = p2 + return abs(x1-x2)+abs(y1-y2) + +def reconstruct_path(came_from, current, draw): + while current in came_from: + current = came_from[current] + current.make_path() + draw() + +def algorithm(draw, grid, start, end): + count = 0 + open_set = PriorityQueue() + open_set.put((0, count, start)) #(fscore, count, node) + came_from = {} #Keep track of previous node + g_score = {node: float("inf") for row in grid for node in row} #SETTING Gscore of all NODES infinity + g_score[start] = 0 + f_score = {node: float("inf") for row in grid for node in row} #SETTING Fscore of all NODES infinity + f_score[start] = heuristics(start.get_pos(), end.get_pos()) #ESTIMATED DISTANCE BETWEEN START POINT AND ENDPOINT + + open_set_hash = {start} #A copy of `open_set` that Keep track of items in PriorityQueue + + while not open_set.empty(): #Until every single possible node is checked/ No item in open set left + for event in pygame.event.get(): + #QUIT BUTTON + if event.type == pygame.QUIT: + pygame.quit() + + current = open_set.get()[2] #THE 'start' node + open_set_hash.remove(current) #Remove the element that was popped from original `open_set` + + if current == end: + reconstruct_path(came_from, end, draw) + end.make_end() + return True + + for neighbour in current.neighbours: #Check for all neighbours of the `current` node selected + temp_g_score = g_score[current] + 1 + + if temp_g_score < g_score[neighbour]: #If the current neighbour has a smaller fscore then the f_score, g_scrore and open_set values are updated + came_from[neighbour] = current + g_score[neighbour] = temp_g_score + f_score[neighbour] = temp_g_score + heuristics(neighbour.get_pos(), end.get_pos()) + if neighbour not in open_set_hash: + count += 1 + open_set.put((f_score[neighbour], count, neighbour)) + open_set_hash.add(neighbour) + neighbour.make_open() + + draw() + + if current != start: + current.make_closed() + + return False + +def make_grid(rows, width): + global node + grid = [] + gap = width//rows + for i in range(rows): + grid.append([]) + for j in range(rows): + node = Node(i, j, gap, rows) + grid[i].append(node) + return grid + +def draw_grid_lines(win, rows, width): + gap = width//rows + for i in range(rows): + pygame.draw.line(win, GREY, (0, i*gap), (width, i*gap)) + for j in range(rows): + pygame.draw.line(win, GREY, (j*gap, 0), (j*gap, width)) + +def draw(win, grid, rows, width): + win.fill(WHITE) + for row in grid: + for node in row: + node.draw(win) + + draw_grid_lines(win, rows, width) + pygame.display.update() + +def get_clicked_pos(pos, rows, width): + gap = width // rows + y, x = pos + + row = y//gap + col = x//gap + return row, col + +def main(win, width): + global node + ROWS = 30 + grid = make_grid(ROWS, width) + + start = None + end = None + + run = True + while run: + draw(win, grid, ROWS, width) + for event in pygame.event.get(): + if event.type == pygame.QUIT: + run = False + if pygame.mouse.get_pressed()[0]: #LEFT CLICK + pos = pygame.mouse.get_pos() + row, col = get_clicked_pos(pos, ROWS, width) + node = grid[row][col] + if not start and node != end: + start = node + start.make_start() + + elif not end and node != start: + end = node + end.make_end() + + elif node!=end and node!=start: + node.make_barrier() + + elif pygame.mouse.get_pressed()[2]: #RIGHT CLICK + pos = pygame.mouse.get_pos() + row, col = get_clicked_pos(pos, ROWS, width) + node = grid[row][col] + node.reset() + if node == start: + start = None + if node == end: + end = None + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_RETURN and start and end: + for row in grid: + for node in row: + node.update_neighbours(grid) + + algorithm(lambda: draw(win, grid, ROWS, width), grid, start, end) + + if event.key == pygame.K_SPACE: + start = None + end = None + grid = make_grid(ROWS, width) + pygame.quit() + + +main(WIN, WIDTH) + + +