From 81b7a9acf3adcb5209ec2a5d5c7e1ca7fde70a88 Mon Sep 17 00:00:00 2001 From: Kristian HARGE Date: Fri, 15 Jan 2021 17:41:58 +0100 Subject: [PATCH] Add energy consumption compared to size and reproduction --- README.md | 10 +- __pycache__/analyse.cpython-36.pyc | Bin 0 -> 814 bytes __pycache__/analyse.cpython-38.pyc | Bin 0 -> 796 bytes __pycache__/configuration.cpython-36.pyc | Bin 0 -> 311 bytes __pycache__/configuration.cpython-38.pyc | Bin 0 -> 295 bytes __pycache__/graphics.cpython-36.pyc | Bin 0 -> 30022 bytes __pycache__/graphics.cpython-38.pyc | Bin 0 -> 29837 bytes __pycache__/organism.cpython-36.pyc | Bin 0 -> 9089 bytes __pycache__/organism.cpython-38.pyc | Bin 0 -> 9105 bytes __pycache__/organisms.cpython-36.pyc | Bin 0 -> 4512 bytes __pycache__/organisms.cpython-38.pyc | Bin 0 -> 4246 bytes analyse.py | 37 ++ configuration.py | 8 + configuration.pyc | Bin 0 -> 362 bytes graphics.py | 14 - graphics.pyc | Bin 0 -> 41649 bytes natural_selection.py | 675 ++++++----------------- organism.py | 280 ++++++++++ organism.pyc | Bin 0 -> 11057 bytes organisms.py | 130 +++++ organisms.pyc | Bin 0 -> 5998 bytes requirements.txt | 66 +++ 22 files changed, 691 insertions(+), 529 deletions(-) create mode 100644 __pycache__/analyse.cpython-36.pyc create mode 100644 __pycache__/analyse.cpython-38.pyc create mode 100644 __pycache__/configuration.cpython-36.pyc create mode 100644 __pycache__/configuration.cpython-38.pyc create mode 100644 __pycache__/graphics.cpython-36.pyc create mode 100644 __pycache__/graphics.cpython-38.pyc create mode 100644 __pycache__/organism.cpython-36.pyc create mode 100644 __pycache__/organism.cpython-38.pyc create mode 100644 __pycache__/organisms.cpython-36.pyc create mode 100644 __pycache__/organisms.cpython-38.pyc create mode 100644 analyse.py create mode 100644 configuration.py create mode 100644 configuration.pyc create mode 100644 graphics.pyc create mode 100644 organism.py create mode 100644 organism.pyc create mode 100644 organisms.py create mode 100644 organisms.pyc create mode 100644 requirements.txt diff --git a/README.md b/README.md index 704bf43..85b244c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ # Natural Selection Simulator Python A graphical natural selection simulation. -##To Run +## To Run Execute the file natural_selection.py. -##Credit +## Credit graphics.py is an open source library written by John Zelle and licensed under the terms of the GPL (http://www.gnu.org/licenses/gpl.html). + +## Condtibutions + +- Release of 15/01/2021 by Kristian Harge +Reorganization on sub folders, added reproduction on omnivores and carnivores, +added energy consumption relative to size diff --git a/__pycache__/analyse.cpython-36.pyc b/__pycache__/analyse.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a318a6db9e39d698af7cbc9ead9881bb93f1b218 GIT binary patch literal 814 zcma)4&5qMB5VjL1O|vb63kN_VLI|lyr3bDEt$-V=f>Z>Ofn7Okw{_O}!FEOGK7RP)__L4DZ**gMfDggU6L1`HtPsV0 z^fI3kj#&T}a*zAp5gl;6KofEawP=2dU4TWd?KMR63)~7_U@*@D-2j8W_L*mwBb-A~ApENJ@-ps>a6eNos!7VQv55YY}X^dDR)aG`7nnqlw! zjI_7~{X72)W(0U*P8>I&10GzX5f2^e`x|TzKdhxmmUVGzWmzPZDy>QES|qZtLJMPM zu}aRFs)b3)WuGbaiWSo2CQe|@FWqpqUix%<|45#@@_z*hvsTNrw!+Y0Q3=5*S;(!J zjJt3tSG5*h$f`;dybFv=cf>%tBTfb#8evZw&Mdov8wWeTQkMFll^!t8PfVS<;x4e# zDnY}IVyRFxZ2CAM-SFLBE)DxLK#DuWbkRQZ6X_B3@aOGpUFKpY_4Kr42HKyRa%pF; zKqsqbb7pJJ)N~<~=!Z33$h=m}mU{ZWvFoy!&RD@zW5lzn>0&4AV?VfoyDg8vp@3lG zMP7_Y__p&wg!fPPa12}Df~rYGgQCu>hI&Os@8rxnE+tdo?I#mnMIAx0hI@{*JEH%# b@8pIXL!ygbled!Vyxs_TP ztMX-h!P82bxLEX&LN9r)OlG1OnzYF1fkm_IG06pT*Q zN>0XIuu#iN%P!z$DRa^J#)Ug-Aly+$gAI+eC$->~-@r=;JFiSF^MEVc;zFF5YUYwV z-zu9*7F?!$CQ}yFy`Ru-_`QZQi!wQw7p68=W(m)ES{wPith>my|I}a5!2O0NV31ESB_Rp%2yc@JkNgmC zW)E=$LvKUYBxHVGWo6AsUb6ccx2{&IW>B}kf#AmL5Rx_gXrx_>es9nCju}Is3twf0 Rs8adbJ&AFS5ZhiNf1UvzycAnP;^*FL@dJE z6}Y*F&<=1tiMQOmpkNP^;H2 zxvdTGI+=4<8=lh?a>$(0B~4XP=Nz5sqH!A(l1!ItCGqUAKd%}eUlm%^Ib4VM#g34o H;6J|s{=-?k literal 0 HcmV?d00001 diff --git a/__pycache__/configuration.cpython-38.pyc b/__pycache__/configuration.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9650f2aa8636c94c12f6ef8753a8dee4c873678f GIT binary patch literal 295 zcmYjJy-EW?7`(e&k~2S*omkkW&{9yuC^3nkSeT?)7U8(>b6JwxJ$5&S^D)F1Na>sS z3|om-hi_oz7cF!?W`_9~X4dVt0>bvw`tF(hV-x-(q;N*Gdn6FB074c*#3HD%8pJFn zuS11LbxYNJsHGOL(73kGOKB7;Y%;r;>qu&x~ zj#En3C-{KMU2Eanwm^hYnmKKJywJMv9aLyU`TKhbOq=F^_xXIkA$u{5cZS{)RnPfl_T%LSfBv}QXbark%N%WqLb literal 0 HcmV?d00001 diff --git a/__pycache__/graphics.cpython-36.pyc b/__pycache__/graphics.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95cca2f48424e9e3089b829487e36ac3e7c27fda GIT binary patch literal 30022 zcmd6QX^^)WpsuEF3~Y%Q?MommbB2f5@51VI3UV?kmE5HPz~HkWMnbk+3q zpr^Yxs|J|q9hm0M^03GyX-d>VDioqAk)|!$A}Pz1FNJ8EX3%%oVTH>ITRy@v>ed9DgO1`j4rO&nT`> z}iX-mG^5`bM>6**tW~w~qyu%rA3a=T( zZTR+}GlXw5?{<8D2c8T&BX}~hX%=@nqt2MK&DoCg4(FZD?qALocOl1wvj;i$AjdfF z_B#7;x6d8N_jludzw-$0ACdbB+#hfr#r>o11m5q#z3n`P`^V&dFYXUIhj4$$-HZ48 zaR0dT1n!@Z_xo}GHs?v)KPlxsg8NBl3infTe*pJSId8}P+vWaI+)q1)aer9uZD+;6+m~+%QhVwypn_%LQbNr_H1w(z>J;-|}eLXexbopEPRO)(drB!$B=EAaD@$IIn zxeecS?5ZlamTDExuGbb+S*_c4VSdSt?`odyxL&Q=KvutLuas}PcFnhMxyb33y>)xB zsq9AcR;}XNE!9M6D=V(@khkEjwOmzOK{fX6n!jXMnk%hU-&IMKwT4}8+yl{K*;}eL z8#DGL->!Lu+p6aKZo^(!x8L7fYS=}$j%KjhRnOHW`v7>M*}Q2Vyt?i$H5>NT5RzJ> zdcr=_C|qjzs_Cp&e3Z*(%toMGuK*1d_n$S$Teb#jy)bKX@jOR5gwX*Me zQ!|CjmuAn;T|a-qo?ik^@ZW5?jl*7ZRiWixbJ4$DR<5nwIP%BrkJN#`hUa=ms;&CWlD|?%jaM(9nZI!5+H==g zC$L+t+$>jtea|l2x6y0Bu3c75)MU@!tf4b;i)(MGxmtH@wF=BO3gyPS-Kv*;;A_Rc zz2pMMC^HMXRj$>`3w3vmwof<$n zcGO0fqEk>a>D)ec^ynH6P%ImCqHy>v_!JgZbESiyR$5Kv+fNl7cM+^wYfMg^DA@R* zPW!!aJ0}l5w{Fi0zz3%Zmn2h?vx0p3)#TMC@H6@J(dnm;PBBNAVTLW9M2Y$y7c*7Y ze-7w(C#UQ~_SG`^5}3JFb8mwoyw$oN0WnjlHzgZjI%LoCCd3CjxFH={(15=+_=&nU z6f&Oet+oV5m1a{pwFa2m_QClc`J=4G!xDI^x+LuCx&ACOdiIJ7!Qu$9t+1(bb<k)jqy9D!sv&*%HD;K&?7GRm#b*8I;AdOXU_vf_G9Bg~MT?XE?MkJ#aYe8f>Qvt<{Bk&07L4@Z!EB z<&15gVV?k&LO9N?RJ_&)F9;?~-vi*1SRsRaC&O5aSW z9DtGJjmt-tFjgL^DeyqqLq|YESoDvaT~%&*^~hY=UsdJ$;p@;6L|7b#QbsCls>6Cr zJ$xjBY^JrYOqBZOH@mW`fGoehE`v~`ZHLdDrt3AHB#UZU2Ter@ ziL`fK0^+OWKxr(-&HAcaAyWBChsP|=-m^$HQtG6iT25`I?ih}-k=mEqFnnVoHIcew zZa}BMX{l%M9@m?Ofp;6`?o`=mSQ|#!@YBoICNQA7u6GsdUi-_---XXx=Ukwm7_8b{kcHDZ#sfew$JwNWO!^ zBXOim%g7sJI0{C=v`l&1MN35LX&l}kBk7{0_c|FT3p2uUa!ww~bwkV#>7sX2c2EcIL<@PZf64LVP}uC7v~Y@lo%04anyOAm=8vAOq&hG zZQ5KYZr5f)afdb!V5*2&P~4@>f#SF}1B$yt17IRF0QNY?op+#)y)b8<#(AIfF6Z4i z?{}VYehTMDoD-MYK`_YXJXAjE0=x~TFxyBgnGb60L?rm%vH43j~2$*onF{NnZ{oa(%U9$vZGa6PYRE;vDEp$XRV+^X0gL8j)r zD;~Z=)#%0W{K2BN0J1=l&BiPY900-lQn_9avUmodgETZJwG$Aj9Y}(K@~Yoltgm`Y z!3g9o3Y$gl1=I{MsHO#30oN&7_1dBzjk zhsP8eov(R1caTMwKwHv{B^H7_w2&KAzk&f=Ju9R&WvHj{t_K_JdF8fLsq}|<=@pQq zfCkGXBDxx@b9FVA1C=zE><%tZZK9!5#@v(u<8FB z^2&glV#9ZKfD>n_2&~A*bKLeJ+-w-j0IQ^dLHo^O7Dj@%zM`h^7LXA0Ma#VfvhShB zLwNJwaYTsF!WDvbM)OKnrDslrmOrN19=w zLPA>)of4s#M_-u>)j23pJ4;ccJJ15oYc>{Z)vmWOyM`@;G-1I#O$&yh{+^91|DS9m z$A*+iHcKdbrYl=KjBq$1uB5$>E}p;ZnNpV{`==ETkulP07M zSf})lh+;pvc5Hh6*i`745c3HZlno0F+FRXSWEl!tBu(1Mwd2$4$D_P9^eg016w+ZP zXpfm-U_P=aMXG5j^dtZevhW7LdY;M%9R%juvA|r%v34BidHO_S*f zqrE-q9wJO<=+7i?!`FmK3R>_0NrF0hOJ)3n2m*-^UFr6i2oW(oG?wP(r!37m6rNCe zT<~LaT|JGv{(PkN;MI?DXz`KGrY!JK!Dx@f5DQCoK}%sNT}zT6w19?^L#p1Qp0^`w z9$$=jC6UFEEbLze#S^O-dWcGbY|W!Q80x4e;Yt0je=VJ|Nuye16B?CPG8l0P)c$)V63ZmF}Jzqfd{-^9D;l@ zh%wZO7j+t7vGa)*b(V?nkR?b^Bz|>{2@%nYfB`m8dNfA%UK6Xypei&{03W0 zRbO;1A$j8tzMqus=SdKo93QRr2X2%xt3g9Yd-p2TSH*LqT-fZGQJ^z4nyR2m<9Z+p zpe*is@`QYCuDvI6h;mTTN=QgM)i3`NKfm+7sR0oH%0|o8V@xR1L`PB7y%e>HAm=x4 zG*um1ztj&B63s247!tdt7_x_`d(Vj{mVGdRM=8(>71?pHH{ zBPc^7T#ZGl7VhH_1YUr&dI3++3E>qbiyn+AX^3_cXa~n3wft;^cB&?!dh+}=jb*Cy zT|IyfnWK}x27k7=U6LWsQu=M=ngn2eD^;AX71_ld?P2)U;x=B9ET zD5vY7qc7gi+YcalAjS(x74Ig_Df@|Y{_PBLT`=1_k^zuyl#(9qFR{PyCVZ)db9fqV!S1I(;P67w{ zm-$$msWXZVY3~MYz`VK#c?lV3MX}Yi+=qfAy)cd1dL>&{7k)lQo0%2MOUM-0(7u!L zR_E=HvPpnSQ~@!4Nfgd2AwWS%x_zdT*oXze2*{^{*czC*>Uh&jSbL<``(Z}#h7mBq zg^*T<_OIpuZZ9tKQGq{AY>@Xk)bUU7kmxs2z8Dk84;`+L3e|ozY$pYib}IBL{Gyrm zm*r{(WflnxsWWAEj5g>BZAd-@3*&bHan%KEj4XPYBjTb2j=(Y1 zqj(c!IYZxYV${(^)&oG0D?835JYVlXS<+SE%QsiMaxtOihPA63L`ILY0E4d1$~XE} z9=?ouoXw6ojEd^oBpdJG?-S;p)Vb7$$M1m4!eL7KPKKp18J4u68SPFSkhNJAsR;OwyoJ9k{s!bKQ^*x^`AmK^ zKaw8`pXKs7ZX>&4;hcv@hmH#Rbc~Ih zFGkx0T#A@}qL(L+C(z{MCzddtIj6)5%>&Tw)km%y(6PFaY%a~I`iY8*vqFrvveH!>JF6@(mHNZ? z!K3tHT&RySp~|kxOddxPI-5Go%=3J8fr(IALTW#aXJ2B2$P+1Z47PTAENO}!BjZtx z4Pm2ZaR?3RhU}Dv?2a3P=A?IW$`H-iumo^;LM#oc03E{{ftmowvb9X_0reVQe5D7} z(F9Z(Fsb4bz`o4Rwknp=frJDT?3Yincy=_IExl*$w>gOrj!X%0x4n7Y3Ul6OUxebbBA& zNbnaR^Z+)6_O-*aqJ2WA@kLII3}CuNyVRpWx}W>pglZM%`@vQ~#aDFr&ks7l+tY)>B-c*_;RGRM{E&THrmg6k5)(q$ zhYsRS_-ID-^m33#&0;3}r~|s*4vzBlhwUX4%MMn1nNqnK!nJSuu(@9i)g4&l7>@M4 z3|vrEMHFT>NyG4W&=Eyt2v>RaqK~<2ZOc=Jw}1Z}U5zx-bciI4?J6U$;Dnn-SX>Qp zR$)x1%p*q{b?gSwUt{1+6k-*|KO&}R9WkJY4`Hk%Y6&AAA+q8xYfs;deXU$W_$eF$ zVW&@g2`~oxEO{<*5TxJ))DsS)fiFQ-iIk=M4`ynNd1iV zbE3(nLDgc9#b$D_?aJBrm(E((LJ)Ba@ zM=0wd0>vKuC+vTEK~uTy@PX06kOi}IN*5kV?VCy1iIv7`FTR<~@X>N79e6UI5>bSA zO0Lk?n9^l0lTr{l5MO81DL=cM({5K%i1>Ffrc3{S^m$Q(J1JnYHsj7P3XZY0Q|KJ= zjv;sv!MGCdgWdtb#MqAr#}k)WPgoG9r1A-}p~WHi2$D$aoJ#*g3-^qUsW+ll^O8YTcS@`?C($a(=cT2Z^1 zQ`>#S-iYJ^&7uo9nQELQ1*g?Drkqekcj#;Sb+d?)(Os5a&Z%pDetAIXIvl49np-&n z1>2vWyZ-#ut5>egpFdZ6?)?0-SI#9UD;8)E>+w(1Vh^T5PmGU}iW~&#YgZobdKsLf zfPo5i)R$EdddveYjQt875D9a~gKmr+VuoBU13FO^63k1K0}yL1gvzuOmjNIGw2DAJ zh*VoEBM@c?^b8e_C=At!X(nRZ`I~kP-o-^Qv%8`N@tm|G@-B-g?AJEVi;S{uL})4< zMk92zMr0LRz|U4KdAFXvA+?7#n}?85v|};i2Z(234>*CHwP^@(;f`(~@1O?tXPER* z=qq@(D+bcM7f2R8H#M@gE`E!p-e$7Kgd$r6jw12PFt3OS#hN;57dS+pYvRRkkV(dI z0d?KVkBLoe<+s5e-T{j^tC**PBmNMlr*U}akR*z=V?r5DI|w(!83AXA1f&hDBLTBv zBw#L#1k8t#fCJ7bg!!2Go4P0~7J5ff31TH->p5^oS0lkES}yE5=nohfGPu&QXIU|7 z({qZ-n3xZ+BG?4&st{xe+Dd#z+7&Y?qNw;m2fAX-cON^8cPZf!&dnAP+e+O`pM9*wuaxN0`8wNZpR7hZ(XM~IsP_!v!Rhq5!$eWo#ggauYyCs3d z5;ojv0wo>-Q=8gU9<6{lU4ZLa*?m??*cf6Uns6XRk5&1d{|giJ;<~;$BuUf(xilbj{I?m&qGi zcHnXRVYi*e;hjR#DWIHmHN9vs8Wusy>CioAIeD@BGojs|4ekD%GXlJhLTNdBwz;O| ziC9Z4x*`OO3!Yh@^vC14(6TBV?dftSp+Z9lue8%mh$WFqL_lD+5YW^*9?e#K3eVK1 zne-drh{k7#4^1ya5-cQuCc=nd@xwE+Y7o!if+WM49rDmJeTBS->nyw%g*<+rmiN#v z!}sZu89D4NB|x(2+Sf#IBT0H+{(CP$k0hzM%LYT>yLga<9us>ZhI}(5cvII;>}^4s z84&o@W3#LcnNsbr7J1sA?)%juz3`w~j-T&W%kj7t_5z88*z!ak1M4D3Fwsw6EhI5w zTX$oa<8lEQLguoi?A3bNR zdjPo6?`i%J=ngNSFs~>Re~vGHhRJ7`B$dQ9sZZj?J6Q)&nzy!Rz_e!Gl;;&Zia*Gc zI*r5Q_}9s<_tz)DoP}T@Udz>Ad!W@7awLtWbmwdn0Tiv^K}eHKSJ)JSnu41;t~KGd zXx!jA?q}K_9Qu9o7!(va!`Kabw7o4ZC{_b3Q3HZB;t7&o?oZw#N3U%KSC2kGCqH{z z=m$${aI8L&KYPMMugd?@KnpT6TEs4laox|%OoKtQmkmO&$E%FBL?$jB|xM-8slz8 z{2ei;v6D!+($a?=xj&09bTosWQT1^okst3>KInmL6VF~EWW;Mq58542$-v#mmo8jH zHBKw%ETyC5gna$;_x1pfIim+fHvnJhJbDoo(=*k2!^!M zMx1AX$438 zVYi;f@n#q$tJe|7tU~K5mh#l8U>#r%U#1@^H!%$fDb5+93-{u?9YYsqQN`#<2CtEDy?bQ9>XA!xqG$yK?mnFOF+#>pfm}#nx*spv$g9mT zS^NWEz*dIX=aEyZCW4`d7U!=LCe4jwTw^g5;_4?b!nSU;C|}p46F=3__OY-IXkPl| zgIVFvvw2BpC#=AB-)7k%E6`5LC_e4a3PjAqt6bP4hV!F?81{z(i)-v-hM=e-7_&HJ zU09-Z(QiY`Yts^!HRgaEYft3mC-G~WC^M&S;>+qZ6EU=waRqAsBp=A2DUKV(Tl#Sx zN^N^R=};m5VM6@?(tnWFHpDXC^Z@k5j;@cOxgXI#>;Uvd;^k9JL=-$U$$u%q5a%V@ z1;Nn&2Lq5q{J#YQ&zIT2-hoGxfq0$pT0T5et_um5_CrIQ(J z+MqeiwJp|^=LZ&prvqyN?j7agt3t{!<$spfKgZ-tO!x|9%bJ41*)!)#SFUp3n64RF zpBWS0CL_y?>=}kVe3fm{@`)2jZB0OM^UK?h%IQG z8A=c6oP1uv5r5c#(>Oe8?LWEvaInJ^;wy%M!jT{sZotu{zq21MvVyBfIErq{Y6dll zK?vf6;=?zpNU^SAQa`zaDH$Kjp<$t*hr}(M^<^0}ebP<_0tgc@GR|go%#*Aj?s4o) z4FqXS7AiW#(W^D|Y8pFR=uw#{46-dQY48%Ka%3X>GT!!doQSP&5~J+Klxd^S5au)% zHo3nXifNFZPY27sx!jwPWwasBq0Ri;P5QIu)Gs1W7v|VCG_qvEaU=EN0;3CGfE(rI z$ZsPsPMLu@b2KnoJrKV!aI%WMAJ$sx)VB#Yi^HPbLkYxMR?VEOHxU@-otlaBgRrTE zW5w|**1;>H<36MRZ$_nK^zXn&A4y0MgeR$z=;8l!+H<1U0vjcGPk;?rqL$!8s(yG4 z{JVri^Awjb(=RVO!f?}_9?xs6@@*GTI12~^8MD?TI1NHZeHri6SD1)zM)+=PWQbBA z-dOK@9Vpor0YP7t5L`Ue5{MWO8#ikbWTC@>V8Nrm_5AS5SlSTjm8M3@2C_#U#>7MS zD|p&N2Qp{$Hwh4{N_F8yW^rS1C_Z9vuHk0Gs2X?DYg~K5@YZQ@FK{wi+zGLJfl6>j z=K6V+<<-k0H#i9`b2-?>0Lzj#(w_^ReL3BLGpHbOcc~Y6JBp+@5>89Bbmw8#=PABx zF(E$$R#{a&B~2wYX^&;MoE7o-yKM9ba?sZ>1YZN^>oM08lSOE*4D|JmC8GALtmG9Y zB6O3QydA2M&{G zIpb%YOsxB1Uc8ix1o8?>(z+j8s2WT}0n8_oHsFLdfl-@yjY#oEWeKaM`>Tc0(^6J~ zdcitX$sZBxS|?x!vy0oqEV;i(W}BtG;Im0O5re7rM{3sVwHeCEoPX-Aq1~$+|ykb z8@UB>ejTs=(>>LM1l?5)tLmzTVSk$XOpVLUEvu1H@QkqYA9YkFOvP>T^s6}5FoS}4 zNOjNPLR9svnwHi~t; zyO6*jB@DuSkzmc;B{uIqjwEXA{hEcXY+Usl%=|4Te}zf6kd?+=N4EcwG;X4&aeUps zaSzd>5^>eHF)+$tht(Zb16bIMz%OH!>l=f7gg_$RL{0oH!p&UjuQB;;B(FfP-*QIJUT41ll{7u&OT>9w4*WS5eTgVLFPR6 znpy8sd(wbPM9w@ewAuq3laf{hZjK+$amdehhR*chcQe;6`1gK_A<0 zA#fiXZb@)IHrztBaDq|AK)8k~ughu)O{}Ad5+u5hmZv+ART0C%z;)Rr3;R*(5MK@$ zm_u}Ztx^fWDCVXp3o@7hR_l@fOcW(4D(Ok-L@G)dv{}clVoWQ@N@Kml6QiF5Ll4lH zILdWtOrgFsEMJbjXdUX3IRCa7ji_F4BS;}}#~}3RN^A++AiYIokfr+TO4?(9jnj-f zSzL296?zN@wk*SDX{qHw9N2;Cb*`%##`W;>2tzmJO19BP?~jSLmBr>5)VI=%1tLa^ zLq0Ss?y}2e9_lzA1?FN^_o)$Nbrkv3Hr<^)whcSBn8B`**cf_0uGQaQA|1sRb@VJd zRs9_%2aps87O}sjS3>U>heN9QV8E=|$DM)>5pOokTg|p-r?Cl)yk*{YR<* zEewXVAgUiV0e*PCuU4SR6yy6A-A%!BsH3|z(NH0vQ0vc|xqJ7`stBzVmH5L?5o|2R z7%AE);m~^7pr$DSQwU22zmKDQ5i9C%@k)s8Z}aN+n4Cru4MeZt=Dp>w;(=bPj)J0z_DKVBE727>BBNvSJp8fiEPMa9r#fZIMe? zNPb~dx8C1LR;zHL4$eky1|}lej=T-2|!$# z6jQH-qGEtpmhM}~BkF7tSk6UWGMdN~oH`ErmN`W3@zM<_MFE75_@G2A{3;%FfULvA ziy2uT6J#*8yNczg%+uYC!8Xc|3s_XgJ>TI6Yxt+w9Bnf*Se&as+Pg!x@6FqV?O0Pk zhv2zt5*>_4n8m5`b33!-dg*nGd=fD5}hb zq=&F9+U)G1PR*O;#XUq)*h2Gun=}eNMxCIiQSjCNCZYH?6He%F3G8>6qX*dU;@RZ{ z*okgnyEJJ6`zA2{TdXx!hP(9TyDSnI@6Murz^7Yb{I9dPo<@8R&#onn5R8WdIOs=o z<}SL4QU0)8`nwt;;YS$`AH=29Utdfhk~p~SnxsRq5h~2v9-uIbhAdk1H`wq^CZamu z;*}8P!>Z04<pAt=nFq1v2B$ZHmB*tvQ=E3&(SO!0^PbQ*`}BT3ZfV!FnN ze7!n7BjK-Hm9AH(BR*fkU-M!3>p&R(S_qfD4u;EKhr(sA!{M^m5og@l4Rv``|M&;g z=DiqG_5~T)(p#oh;?5*F^0-LY=+x`4JBucUg?~JA;kIufus=sPqHN}KnTuw)ee#}^ z4;}h->e7Ray&H^ILo7Sr`UM*Lj`g}|*pWs}ZqvKPnzGfJR;NI^qE*Sbw-Z^WhWaYm zKg6pbS950ZixF6GEZd7;a?~%eP*KqeSC_CStZw!&GpB1S)zAeX3RW?Ttq!|pD@l@texU&Pr5Ae z6oVSoXpX$aOpW`wBNkP_JcAND-2eXww?RR2%$BjmkNSsrP#g-CUj5BC;nsYa4W;>@ z)m`|82gBz6X?Qkocc3|{_a3!#5Wq>lb2wTbA(n9%?@jS{fh_C*eY2nr>fZ;_zYC;; zjyjd9jQYp;uAnT)V^1d8^jNdNhwx$xLg1@5A=H|H3C}s#)wPE-hQjrW9HaT+nTLSN zZxGO*z%M9XhmUt4WK>tvUqg!uzV8|EHu3DW1Xpwm^Dm;Nd*>IoL{)n-S`^0x z&s{r036*m}rtH7y0UiOBvSy1eJd9VLiE(O1ybPS`&7mHu^V(CL5Owd9wFO8bWc#mb zqU8B}2S`abhg)XhoqX8Ev3z*}H=3aIl&9Ve0iglt@-Q@j%bO5;bR8T)6&i1lB52^W zkLR4TWyk9Iizg&S{!WOqxck=kt@6x{`V&fyk#(ge{_$0v;ru5|R@##1d(dxg# ztH+T98T_0E);Zs^_txKKj&4$v9S&tT%%3Hehma$c8G%EVn>XY;NkB4nEpLgrO4Kmn zU+BMFslXK@m}_2?MS1d*Syub$>n_#@cc3BK8?$5I(-<@H#T&*eZy0y5@3Sw4P-JxxIV)tGv$h@hiaU3y5|8VXM8AvE_k4d@WiA~=sm(%~c}rmeM=1+O`^ z4VZ%#WJ9*SalL#CQv)OcG?PDjqUjxrL9vgk%b&TJi5oVLTzYqLArF4Z!`H*FVEMnp zMdd39C<}itg*i|ROTn*e;0L@s>_?xJ7Z@|zdN5>uaqjMq@xk87X4B(V^9Vosr|f+a z4tB=JPk_16WJEp!PW?V#TCAa%MisrJViCY^5S?PXX2v)5>Lj^{)??lRg ze66Ia3*ROhMEy#uf6K<=kPo|w$1D!-4>(h zFf54r7c~MugEtum`))`M{DuV1Fbp6MF^|TDNMXLLydOXbjJ+khgm1tqIdO`b%P=Iw z)nvlyJs4i$7YIf37`kI&`!jPHzdV7+ko}mbwwz)90tE)*41b$&(Hu`<3nc61uOkw~ zSRO$QaIs1$*qi{rK?rE^3_J3KS7U%v%c_)LBW!(n|-#q}N7y1p+Mvh^)%#P4Z{ zb2n;_{5~M+)MsOPyEE36gHN{I^JM!yPj>V?!B3v_Ji&fK^2EUJYm9fjOD*prcEzCC zJtsrNU20R}QfLqB1zV6H^oojjxJw35{{YEd^3q+BM==e`#@rY^KHG8M9+`aN=*+Rj zX-TK-Vn&F*ow?pBuRPXc?YBE8(C(6>#65FY#`JLs!O`2jeT}aq@aZL9{UQ^Zw0e^_ zF^3tvt5>Xll~=DZ`2>?+WAb$-8%#uQ&}pD&oWy|MgWIWWkcLBBeV?y>g~{_wzJ;V{ zw(gZ@_*pLhw}B9E9yzGebH!o7I3RG0}z@TvME zl*=E2;7_oXN{mEH>)GNZyb!O-)Z?;Y9=9mR4j7c__}K{Q!hgl@roDBqnDh0|5o)tC z7yjO0FmOKlktOZeT4$LbWAgJzist;y@V800s{#!aMdLtkExVUjqfDM*qL?(9NDqCI zSD$6_IVPWH@;sDjL5gou(ukBStPDXUE!nb6%Ot^vXj33VfTFdQ4KH>EivPTcSN@4R-g5NSuJ?E-Um9(U&c_rL%9{&V-r;9xO@&zIk~{(%E8rBdJKLGn|; z!3k{cj~JN^PJ8=I!I5TJu;mpv@ba|(}%^tS5+dJ@mkG<30^;7xsF4WjT zY}upsqc5k*57=Y&WB5MgY`;lN9JY@vq(5V*SDZsUwlkBd(y_|VV{j(xi%Sj1YR$|$ zRnKavy3_O=+p4L`(p#Tgqy-uGOoKwWL~j+Tx<4T+}T(D@%^5FQOUidfl6|s;$MPWzSJ@ll7)mX>NjO zw&Kp!Tg@@+yl2(j;&oN`Jf~^RtXl7G%{8sE(?B=a?6T|VCwl;Rrqx=o4qaOH=2}hb zQUFQ4S$oPl*({!Kda7kFS3NwJ-53u+nXCd0Rp*d3a#mHE3ypen)H>xjHd=U-b<%ZP z)q2Hq+|pR_!ujzt6O(72vZm&M6a2T9oaUo$YgwV^Zfn-NUQv#voCdH0TrD?k^pt?1 z$BU>v%Y)*%OBbw>InP^q>aoYJU%x(9Yc7wqRPC__@Yi%5_p#biV{Fb_Y@o$U7fw!{ zy?FWANwx{>R;mk?8nEwL73(@i4cN6Rs)d%Usf9WQ6NlJ$=UU4R+fvKGY_nKtu3Aft ziU)ixTG!_sz!+BMgRWKTjmk{J87rQjn4CI!0ZpF2IPsKqY1sq3s4-gyD%{qhqwm#a zfaNL%&vi%-W5tWlow@wn`7>7qRy0Cnc-LDN0JEj{n(lx(3_wg@W74&Aq`|B8X0h6+ zxTr!xCEZ9*@qpI#0CZbbu47CswmjolcB_e&(C2FvRc|f3MR^d2`JxaxZU+>g%4>C- za0mdiv7Hr55lr^2CwRCyta@Bd9RO9*^LO z`WQQ7HOG4v=yyg+)?w>Xg?tIjT&p|R!4U3p!wZ2Jt2SCv4KN+H#(5Cng9F@@0WE64 z-x&OaLmLPg*K(Ja1V`0YOWE}%nA`He`7ZgRqQ%1;c&auh?CLt+I4io=q65KV3$ZP- ztFpJ?tj@G5iUW*+u4wV1Yr10{Vl*H^$VJfpY^%{|0dKW%!M&uRX#DxRn6GZ50kvNf$5V(3Ed0a}2_>YP<^i>+l3Qqy^~+G@1aDCI>%?+b?H z()GIS&5ddDt5*|`t2EqJF&vRauqjYNcAl$aXlf$kE6sW^F3#*M`rCz9J|X0AN(<3T z0RwAc!mcmXSDZ%Jcj@pVp1ZURxd??YYF(^>4SheIwVt(Fvbv}=cE$!y9T*@`r`PN zXU|Mb1%ml3szzeSZdI2lCxdQK7LU(WmZ%9Hrzi^4VX;dcTIcVm4m*_XXmM$Ircrn2 zfD2rBT}?S=StmIrfTbAdxy7oxGzRVH%`B_hm}4(L)}{)7Y)R{CcD`c0xLmI;Kw8W~ zU_v3cGf#{ixlQwOqRKM)fqAJ7&0*{~DHxe47?=i)OBg#De=yVnXOwEG_FK+5P1qq- z%i*CFQ$;}D;BA-&kloHo)mb7zxMLF~(=SX3Zoz)11h{{?KWiK1YbhMZ~d)~d{^E-N6$YpjaGX|}E4yxnr#=EG!1E!SX`C?SXT z&htQWjoc=kf{tt~J5?et{A94hZ5*5X42rdsI_{;`QyZxphHb2+4y4u$&)A#Vo4S!+ zgAKo6swZ(B`x}OVYisE}sfy7w*NlqcW!6pF;&zIIFmam=DHf%yZ+b8T{o(25B^v^F z8cN=iGg-IcI7@zZTD4l9pVOC1nX-v4IOR;Ub-mobM0Ik(Y1X{C7{`jvh8jZg3)ox| zLMm+<1!EXn(I}?Pv|QapJ4EgYZ0>habkNQ_?W~=H>tNb>y8weaE3QPUoYRg(Ij`M^ za)GV`uJ_S>z;}@j1it(2UG{E#57>L`z4#uq_u2dLJ!C&Ej)GC%X1_~Z1fx8xU4!y= z?GluCXjhNYuiHZvhW<#y!{Pea;lm|8Gdru;Q$F;{RwtF(8^82gGYGNSV+5jJ@|z;jgJ~$ zdOhQr8^(?7T6R5aXVy~lxs9}u^3wD9`NCRiExVRp%fJtWC-`a(6qlOsTQ9B|LVcc#jBb*Og}5?(a+5}_1c_Q-Z6)-26th9R~MR& z>z30qwx6A8zyW9%kDprhyjJtkqffW9$KT_uK7F=yKNxIv$?=EausDhmOeCM5_7=*8 zsbFB$AO@mbfFa_wpsW3?m|}izywbc@aVhQU&AJB(msD@9L@n~KLd+N?F2;X z9u$6GW!Y=ZHkREve+aS`4;x4A8MF*AXrB2w0oN{@jry$T=P5$)9AWZO&Np4BF{|zk zpQoSv5DyQsh-9;t8wYUi>)71KQKZs)Au)#VmrkX>mrD;of(#hB;E(4aPom=j_RLg! zd&o#*A=)|wE5#m}Kp0>YJ0Lj-RW)E6lL&LHgM8*e`WrkCp@}lPk=lT(9th9&_Tyq3 z+YysK-QFEGIr8v_Zah3{edq?a5;|X~ySlcY!_dH5(w!zY`~s|yt2Dp-KI}asBzDVC zkKkGtR!9NLSyI!}e}Ieb0E!e)VFDpQ#-Dd|S=ZatWvVdgGMOJdpSp?e-ZCaihHvr~ z^%%}~HwzUC4w;_*Pq^mt2`QsJ9QGCHm5W<9wF5T*n@|Q2DiALpg*54Wrt8-3u;UYZy|BRZVic{!*duIZms7h6!MLmAFAN8NeTQlYX z*tCG7j^acqUCzN_a90;qNe*Qc%BFJ-tk6ZFhf(3bVha(Xg)Ri{nC72NO=nP9P;X&J zQyT@{ys-wXyh>#awJm~5Y^3&~Ntp2DFU`m>DPg?_L5e^H+%o+1Ol<-N)z0a#`w0Yr zBU{bcdadJX#KyPM(mO~QKDeuU{vgcZQ&Ho8#*UI*QfabYOzC4C)jCuR)eUhbeSQ!- zBscUHd_}WlEwg6cq%wd?3Ct3ZVkzDB*zef)6E`QI6L_qQnTWAJvT}5E^=K&wR)|Yw z;RCPDQI9s9Sw2I-s-&AcvT|&6^;lTff*poBiUK^S1Zy(u_f3Ufrbs+3p&ka{ehv`= zc+{n=##nmgsGnZNwsH*L$GTD12b^e^^nc-IO`(~+Mtes%L`0gdur<@X3AYN<6tzGC zq6B@KM1V4gCTLTlEYltq;UX@H#?-`A$<&-g;R?gZ0gtv;)sr~t#aC({E_@H0D*@z8 zE@gtJibi`Vf>{`J6TB3oGQcDb!aJD~PJ#dvM(!a_)SFSYfEz>3i6wO?CAV&dVvEfT zgbgXS-m6P~uI^Gw3?y2Lc~oE9)J`NGk}@mc%CN;!Mv2;@vKHmmt91&hh|`7%0?pb@ zf-0(_cHwGO>aZR@L}L`le*lCB*|k_byNZqyk7 z1#v5gQP1E&&~VEXG^q1D@opAGMK=oi*hPsj93&n@nq~^bLM#}fDqB+~EwUsjL}DP_ zK6pi(H*r7d5d_Xj%Rr|aPjJhpnDZ}!RfY1J6_*WCLM=)7TLb6?G+~ z{y6Y#kX<#t)rbciijQs5vldc^K{OvkcA)R6-OcvfB7%m~CH4$SmZ4PGs!75I*;ja4 zyR&189ck|YO~4J?gfR6(xC#MILs!#p52_7q#0*;MMq5rl_)LVdG%bdJG_eoDjP$b_vl5N;2(}NdhAl1S24s1c5a%vz55gO-%b_)O%uvc!Tzf@gd|S zh`LH_bV+Nt$Z3A%(S0P4?q3B9L`9Fd$n0Cv} zY8NK_ZSY4#oIQi7lZK;~qA@etdn2jWRcR9x^!G&ck@iB@8sD04p+3|j;BeE+$~Bz7 zDIw|@(wsJ+EZnZGs0X-5=tXviT`-(3_|+j)abvt`&P$AB806XnGO15MW^_8FG0Nc> zsI zj<9$O3);KtFpGDvIK_gVt`_a5xhEd+v)sGL;u4E1ES_WWJc}|561504ksFGvs-{^S zVqvqGWx@U>21ir{1&rE;;%nI46DSIp{Sc`Sue-RvP$*;yCjN5x>yy1~F<;CVvW0Dh zp~66LE?>x_UJhGEo>s+!IzDL}oxtW&n|92cAjJ!F3=*WrH)c`nJic>w0R~2&qIcOo ziWx^oH8B|#Prn^|^mHN;(=`k4R@u4mL)S4PCt{Y4C?=)yYq>QO-vz{b7{Xx0$5_jI z;=b)g_z@FWi~$vJ1~z?k#v}{gN>3<07{QtB3g^ZB?5h5n#k?=3qgGrPhK`?Gm2Y%K zgq(5RH|EOb3SvQJbCqRwg(3TLc2$3^xJ#8Lj`)=rEEy+~&?iWsqR7oqjqiY)7R86+ zkTQud{E!SI6p*ecisvyihZ5bqK^q#Kl;aGJP0xhy3Lh5pE~fV0ZyMBV2#wbCL;v7i zh&jz;UoEm&V9{jpAc`Oym2f-X!%G)f2;IfR_dcBa96LoWNu`J3eYc0>?r62yq3GBd zc5WP-(39@WPU*~^s59tNW+x{f(Umom!0SM&sR0(yBd9}wV=&L-=~~uz0sMYk_{lDS zx5WU94yDOY5PJ#%_E_;L2~@=RAjN+?ltN_2LVqDAd>}@%NE+Wb>YGh?D+r^)KXeqr ztbKD%?$;HtLary zyWNhbAN4N3>4?EOT`K>df9Uj?vnQ`yn3^8HIC1v;IrTO?7m7i6Jg=wBT{-FJ z^ig80BVPW6h?ny)$1|LP9x~c{#H@+>A2T!uBK&Ya>J-%xJrp=~hD>CVQ8VoW3^O5~ zfb<3U9y&&kxQmV%ktik*Q0v3AjSj`Dx8qb7n0_9n)menxzD7_5fOHUHj{yv-bRhk1 z;M-650fO#A0j}vAb)hb<^?d`km%uUq$ht1mUW{0Yk0A`C zK?}@29g^>q5`F<~iy!gL1bp2?8`jwxIx2Wd>d?>FK)l6Edzf?nXkY`uSBG-a$D+ny z$cjMBZjgcz17U!Q77~oxf_l!w9Ju!MDb3rzbDAMY`f)nNlFoRInOg|WjUuhCjy$a( zCsgL6Lz_Dajp*B$xD%#m1^JW6Nm@k?DRNGjYl&8Zj7f;C=w==N8?!D~>PTNjz#vGo zK@bMXWX|FeVl+siBJ%kJRtUgkI%f13rdKu)0Jc|=Ht5!wk=i~mUSVd7+(xQrwxAuv z$4dR`21)D9EJ&*U_KT<9J$>@Rwqk&MB+ct@InJ0ydw5-k_txZW6l^e>6o8e z!T?Fs3<;1(=#@Moj1Y(>8i9~_TnUwRr5j-is}LjH&%x$L8mvaDSf-sw?dh=B(DC0V zA{hZmWjPDPd3VmY6P@i{U97K7{tml=97@|k?1lz*C^Nw-n6A*Fdze8PHMf>w$kE03 zd(;uL=?rs9XuA8pvs2=h(3EM(h> zT-XDmq|)|^pSD-^u*l6@8a$uG1HVhuOQbi;8GUXt0BIB7J2(K{bW8v`(BGkl8SK<% z+d^LL@Q}+R5)8D8LEr?eah!CXQI}Y964upwjQHl(GQp5#=JV>3S6J^8%8vZLqUKuR z>>XDoCa+w&bn)`knbXtHo|$^);^~+c%SC$2f&S}-tzi1(BLKHdUC3Cx`Y?{V8T}^C zAqOPLCNmjrBzx1G1(WMgMa<-p((S+yEk<&?5Gc_V5Y7vf2@r8hNWWQ9e5C-{q_t%Q zVnRe(j1mYoB#j1!N0`!TN3;{N@6>`-MLhO}S zaJY^ABT`eDAg3YGBavI|LHOCKH*eFEJf!@dS#$yV37p#%0h-kdypa@qr7Gwl;INDR^*MouQYK^tN0S||#|_J!vM zy8_xGi#?s&mZLq4{7gmrOdJcy6Lv+1Hw0;dK8n|b_t#@?L+&`hfg;XQ!Y7>7mno>& z=p{ddAMTSa#<5A(rfoogN0V>VWfSc|dB8}R;FM9LsGR_%S4f&zcp##g1Q0>05=lAy z5Oo}C0fM0y7+47)FbzemVXQ-!VCq|(=wSLgy^)0vTE{K$6wcu*hRPof=C7#+Bq=|1 zNJYYbxTA7{=7iixj1Lle;wFVzp>}_O#GX8fni}|n*a7y?0nAkgIULN%#eOpHD27sf z8h3QJPA(XUTSvq!Y+W=!a{SmbQ7Ndq4?A(%%}vbSg_3^FK+px2iFVhsdUh<+Fhg(u&Erh_q9Bew9%q#*c!0`s6CIrIJNa#U3 zzKIEg_Z~$nf5t}IMU8r%{C*z)Zrt0;?vckoe+-XTf3@@R&rg(!-7<^;A{}ESO=to2 zSGe~%7C*)!MpA?+LGXU!X$Uo7Pce?im|wPFXz_v59Ul(j32g4uD3Wr@&eSrq1`}?P z3!MpKd8S>EfIv0~2;_o*K;9k#%Wi`$bLv!UMT-=fusMsTR)v_c!w>hl$=E!I9WAl~ zGXNpr4H7L3hhR@4bRqe~;)$s6(@V&XS~?au>*^mC>cs(B5c{R0<9LRq(V!(cyNL(x z(2{iO^;UcCwbwg zSp0PsaU(Gc|2Qr@&NeuJ1#?FhOq?#H70*|(b$mDmC$PCxjY;->eKP~hTJ-y(*T%Ls zD(IpG97^vhlbE!E$R@55TZ<&Fxt3om0F^W#BpW!F0QMZ79TTPc3=VJU z>4t|a; z+>+=FwY&OJ7N2F&1sEm63j|EdWBUI|phTPN38=EwH4pk1f9bGz8Pd2Zve{-@Hrv3s0}v16?4>jG#~Iql4A+r z4?rhhWYaMf-bs__6))^Z$rX%VElD3kX&}18BO5om{xYPIPgh?uanp z>(aWAIUkaEa7^pO=M0}7(K-x1#j|fHt>^Ts#~sv8c^%2@(>Q=1V89CE{3DYx@C|<; z6P|^wBxf-jiL7G2DTsHwASETxMo%>xTS>WYZ$Ze0{Etj|d9^-ttX!N^e}hF#RIyAT zQbb9uhA2uIyYYwlnQgj9cfnix@sLm*(K6kvkcNVn@5~urV&CEsk2!;#zRqU{oI!Uet9W*6&UhSG@7|KaDl?oP?T1A*;G29) zzk@$0o!Is`HaCvYFjUPb4V|nFlOgMM%mmryzA(;DUJ%!(l$}s3xLG1JdV1iq8H28TKkBZV_j%;N0g4e78Q)Ln^@{T#i26H?avBTG-)h4G7l{ zdoZwdxPF}p*Lu!b2L?-KIXhcdu7_7GkztK@IT4#t3O5TuBFxOE`o&WxPfuUG#MNRX zpc>AkeuNb}!IqiSlT26GAnaPUaMGu(X#qibxw@4HMgCE-D*T(BEyP?;I`|}8Aa-E; zWy$rh{&>EMt>eQ^oWSNDNAdmhy^Xb{kQXrs{vY!5!O|O>jA?fD92>cWg39owyrF;z zUj!6vq{303)KKDGg%N$`1}0KGyc9i;Oval*$kxlR<8@_5kL@f32j;pYh?~>-OY$CZ zSL~(K=Vvg@rx?EW@ye|0`5CNhp;aqU>F1XCqJkTTe!~I$JGk04fTBik5woPiRNBJW zA!TVe==NR65(X-5ya3J@znLvYt#umx=HDLDojIZY7V2!mAcu*1UM3CKQtvM^aqv0J zvAh@uRs`Bo+E0%i@r|V}*!{laHLU-zvZS8=3VT3yFcB?jAC95dqG;@RqlJVo_vx|d z4iNhnP#^CgFXQcaC8*g-mH%Bno!~;1Cor>xm}5oZN?I7y<@3g;ba+F*7i{2tmMDN~ z3T|}scb0CyNI*1`6{)}xPM3vYxb{wuh-oArw9n6pJpDojsV{U^v+Cyor~2D0B!VLB zxD`G`!%Gy^{gnh(wugW)t|Zjgp)(0c7Mq}j1Ve9I=k;Jh7sIZnd0&(n4DCawHBLCI z6Gj8$S*5SwY!@*|JoVQI5*te~78qeireiw*qGX8xn!v%DQ8UE-Cs?Br0^q!|xcuVo zGXy~6HY?Ni+{;N~>wuh(|+BhKCsqC?Xa>;^;sC)yD+V95cLy2-3N)vFj~^{!6^@ z2^O!gh+B%ABPV}}%?)4&f|!}56vmp4w-&_>RR6(6F&Fnkike=XqZq8t(I2eNF%YcI zF&M1QF=X$9)YMab|JcH+r3O5mC-G(p1+xHRioFK1^X zV-6GD)A>+RxA7!x%&l_oLoCFiE5ssLa-1adHQA6jqE(gq(^u{MqHj1 z4}lCe$LpKKKGh&6lem5Xyq-Zm`7UHNo%g3y@Q6VyeH7lad!0S{%KI_?J=X580$V8(yej9F`)#JFEl- zrdUaEPLe0i*?Euzn?g>%^sX0O{wl8j@upS+O1^U|i7A$FL`6jQXi8M#N#W=3BpMWs z;_`X=Qb!gcxqvh$9eWZxV!Y?nsB{p<;|rM^da4>EMkAgPm02+ln@D)q8HOT$G7|`r zdw7D6tl@g4QO;MfY-Qb1?S3x9l-s&M5{ARQQ=S7L5d=-A2Mw0Ovj^l7MHi~6&VTHO9)>_t7nYBrAgC%pC>EdD8rP9~K8OrqLqu;PGM!KX7E>hHz-%uQlW%9yh0cM1d&jvV$oJSXp9pQR zJ;~d0b)vLwYb)dxKAQqk`-GGfij1uOA&alG_$G^g!{WDC#DK^iNmFFsHweUD93^ZN z+9@(=0IMZ0wW_Gl@gdkJu(@j}{_oi;_d?l~)>s7%_0fik=-5VJM339-bqn{k}Kt4Of6U!Eo;Hr2 zVnwlaD2@Cqre4)*hsh(4ibqrilO|6#gApM}DcZGoMR)*zocCf%l3;0T+b2R76;^Ef z%p;i!U1ds=JRl5qB@G`Po9iL*WwvoUfeOex0-}f2!~U=*>DihdS;NoiWbe{;Z8V(2<%G||;VoyeI3(78KFCYI%|eEY zgPa&&4z2okEEwb~_swD%OLrPHP#z4touDC|>AIzS4BMqJ`S-Ig>_VbT~2ans}(?#dyJ$=)?Vp z_+H0gRKJFbTPAP4DbZNitxcxlow}v|0h{PW$ds$4L=)RI=3=WQi9Hf~)T2{4h%M6Y z3^B?cOkfz(c~GQ;xKJVwILLX&I)BsHLd(8i(^D)?#7_B90!_+O-(n$z_HViOyDZMK z_$-SqfkDYM$}Z7E)p=z_gtQQn4Di?6u;p-#W0TZHu$I{N1UFWInm80;2<%(m*tEPC zb=Knvj0O}ED9Ej~F4+YJPmt-S_5%dYt0Ab!CB8&1!@7T*ZD(}nh06p}Z^zkgG`x&+ zPZEyMw?P(o3=7{H>d-74*9Zk~#ep8%n+%Es8Q**ZOEONGzmZYLSRywEaCX25JApy~ zVn^aiA`pHNC$v-`yg@vtoRt??{4AzemmO{IbdIIJos#1$-h1Ps?uc+Ty{FkFx&n;w za6M3TYfr%L-E}u1J0jjgxIZwtcZ(APL{o*rxDJxt1>s1g{dLroDD16_`aSNG3AEv? z-;7sZw}1!~^ry&drUYo6$WheqAy7#=}d zpja`oV$^OLQB>DldsplO()=CV00t6UI`kv zQradgTe7Gos=Kvpsdh7jiAorj?EviAZGlx=Ku%~5Z-nz*@SF(LDk^n+I1DGSxgLtx zx-Dnw%v{&+dS@j+l<#=!cfFCvF8QH_AV0J($PXOfB$`1f(i&)4m7{9*%M*_GwJ&)e$fa9T82xp-*~YqRRE^Zhg|lDb$6999WZm2+5f zjMF$#Q{C)w0Jl+Oi-HnE81j#X@NQXROP;;88B8rOj!k@`*bLSwxeRkM&PH>1yF4f` zhxIa~LEeL?=ST4jy{17gbK(fDHVGps4esAi2vrZem=JNm1uF6*G|3irF|JV0$lFDD z^9UA&*tj?g&7ypkJ?@aNRcTB9c zyiin!3{0sRDgDbkIzOk=tjVfB#@&Jtzkqd(WPxE#<~3gEHPF1!CX`wgrxAo6qADKH zhzZ{BOB#=VF&p(G35;yhZQO;8N~)5HNeG9Vh?=6zNS<*VH3bc=XT?$_h2?n3o}c>&dZib5AT&p)wkqI;ysnDf)7ZB?edd7m`o!NjtL6I5t5oM^yVKSl4MJ zd{K-q1a~Z{B=pOd6=mH*7g}H76j{=1_{hbdBw)g)>5xx>QoXv;T@D;zDkWj+Tx@C! zpeROr($p9(d^!PCJkG(oQ@9p=Xf8$4<2f8?OzD|Ky;=Y!;4$XG1Uz5(L1xY*c!E|e zu0UmAYW{?W^PCLj#5|T5%Fu7o)1&hHN@lwr_OOCC&ao`r`_yP{bmsl~oj#7l<#VTk z7v#l|#qa9ig?_z&q$~v)z2_%4%CAFUq_AXc%^5lN#9Q@mby)alYRkx1TrgKkMpN9L z-RNp!!uCNN`dR#B1>OVRw3y_-XWdSDCaVL=T9SX6m=+f)JA}w*5nCZi2vTX&dma(W z#oiL)gssX{eZDk-Y1~oKcg<5*yZlMa^@Df-^!Y zSa%*jtmT9O@j?if`Yvi4qSrCvtaD!8 zf*M35m(sbznI(+TKr@^T8r9U9+06iFx_vFli-KjZu74N@>qw1ajRhtbqSVGj0Ri(L=x9jm5S}b!w(%fwi0gAZ>$buDBq~{oTuoM z+on}*<|{;ni0h2{AM7x;=)>XSHjd5x7NobAx|zBGnTXjV{z2MpV5)^PN0{i&Ko^=4 zvEeMM#ALiIu4L`(O-gQj+4Sxd76~$6{34>+L*Pe5 zHRTBzJas78!%8*5-Y{OX6~{f%I?u^3P1wn{?%TSp&loQbOKYY)HSWiD=}%@|e;eyN z?BR|YJhOe%nH`(X+|zXiKPu9725aod83VswvAg41YJC@>5I1GdglL7^w7JCDZx8DC zlOQ}8eiXO=Hi=*TM-;coOSefD7=Gl+ z`zje`3N>i8^Ci2Yai6F;9XDd;gb8D8KV%&D^>0J)%t0J6g^|&vUK`JEiH?mr`ej?n@hqzt?hwq2}=Z;eErq@V9gL;P3;(?-+jH@FdcRj^q%%|35ZzLm>bF literal 0 HcmV?d00001 diff --git a/__pycache__/organism.cpython-36.pyc b/__pycache__/organism.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d460a94fa8823cf8b23e2ebf99420705be057442 GIT binary patch literal 9089 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
    ?$@IvI2|@*&`JZB@>tE)2Lv`m(jO| zM-idiKamq57c-Z62xI6+ZQ@qO{(EQ;ZwP(Mkn_U05AJxPlUui`ZI$JX?2Y;`;u_u! z{%US%@&?f(fID~};zE>hYDGnV+lTPmjtvJ1nkQGemw_2*kI43wlazjjuS_O9M{P5d zDH<`D{Hy#}`H-XZzFJYaD`T5uNiYWXTKCvzBS<_kbaqD6ZN3pH=r!5%#z4*>qV))N zJA;|b!`maXy>{f;w;Ytiy;g6nLE>gW0XdI?{gwOhWtjF~8A>yj)d9wd{wyXuz@uD= zDiohFuP;FDl?|(?`jmPNsckV?^RvUpbZj!K z`DBD4u>)_1{PUdDOvVTFY^Jl};L+3D~zX}M(PM4IyFL%S}Asvuew^Y#P>e~-I z($8|JibpE?-II>fY=_{IZSqA&0A^=!0>JVofOI#9*6J^0=vfA|MAM_eB_t39HYrfn z`|nQ#m>k&5%bx@=Y$l<59AZO~X(Q(|KnMiYG6{C#z0Z$=o&4vcwTF#q1859rif8By zq$S`^LPrcV*4K0Lu67`lA#%tkV($$WyWjfw&3O%b1R zHfSS%_8SoWhW45LD+uZnjt9BcHsNN$u)l-&4H=$??_hk14f};6JKRS^0UJ&XAj4j3 zV?+#9-YGi~Gfa-=BI9Hu(mYtE-O^|!C(+ZHBU@-(m|?EkK5L77#Bj00?2-+d3{QT9 zg7~AEO&TsdWR2C@R8m5Y$=j_@lS6Qanu$f~sy@$H%4SED&*;i$h;!aX@s)~-lr|uG zkMWZ{hrTcHDC<8x3zaah&*~@i(+Ge1r?YjJM?$|5P9m#HK>|AgHi%1{w68rNx)Tqf z-bAf9XNe3H^?-Lsc^G(aP*#xm$%5-xlACCi<0*=i8Y&xTLB&uGq4J10>JK!Mz6Gz) z$QkX2jKxTBZb{=Xpz3@FBuurT)e&SRC#+Qm9X3p68H7{%=}tBuiFgycyO<^{N5^ zp42CW_NT0;kQGmL%_qa=r=00ZW;n5?;?(-|wuj)!kM};2SHLjC_fO>nRVOL;@E1JM zODMFd1^ptT@>zXRufjoH1bZ$P-kDv8fo(AdamZoH^&YvsF$Ig@$r1D8tC} z;AE;7_y`d?jAeNZ=crdQ>>lY1%jYrfA9x~?SIt`1`zLb&ALeNe;frhqOZS&(00Ri| z7y~fyu>py_2zvn;XW7QLt6H#I9JPc|Ga9mgcd4e4j5RfKl}9T4W$SH^tY=`oOT|(7 zdVd^S4nFmsR>sdp>^@&fw4 z#-kkM=`uOUc|viS;)z4F%7x=Q%u}WhiURp3mEB+$Dx+12MMNj@v0#EA61NJJES;gA z-v$9(qRwW4&grZ{@hi{zmS#Qtme@b&;w$fg+T@*TO87v9aLTm7I5rj@`;gVrI;?(PbuOd?{594#9O&k#)}J-!is5KjeXCQXwi_OpS0>&co!O6>~NJ(66kTe_2UU$X^fz$5L?tpp zXEK~FkIos943di6DU^5_=m-)v5G24VYQKJ*g_tHSQ%H1;}@gZKAfY3qRjGpX$Fj)_os7rz6#xGD9-+# zT*U}Ck7f<}i+sI907DM4W&4X+i;sdY6lJV}18;zIk}`ynoG^KT3c8MwluD5AQZc4N z&!f)--Xpqd(WWbOi-JGgrWgzG-qgKHe<|B=jESOEq&4!32o{IhY568rN~(=U2RA)! zB%hMmM&n`6X{%IJGSz5^&_zy)FL&|(CmLUQNV-$toVGdv2iBBc;~c3v0mVoh1F^Ts z4wAH~?*%IO^mL%YA^Es;Hc3{R5-AbkqM}>n%2MT0#jIMDO662#s#3<^d}XF`qVgQx z=J0ol=hUX;b<9XAsf~RUzaZpj(T`z!A19 H`hxLa8#AtR literal 0 HcmV?d00001 diff --git a/__pycache__/organisms.cpython-36.pyc b/__pycache__/organisms.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..165c7b8dbfadd8adafbf5264c408bb72fb97ba5f GIT binary patch literal 4512 zcmd5<&5zqe6rb@|oNTt+ZkK-0(wYw;Qn6jBNFb^Lg;iUSAT4YK$cI{9&m?iyvBTKu zHc@&?rCvF5;DF%7AHjbB|A57fQzR~2xh(I^#7;!FThvyiW6kr-n|W`(-f!l;x0aV{ zx6b}_D?CcbA7mjJP`(T~?Eqnf(TKSC*CKio|9YhLbXTW}XWS&$2s4;@k1&(#6WukT zZm|l~E3$4u-DXv&S7p5d^%`4(`jV{MjBb%eeF~$IW`pMR91#1uX!~)P_5x%V38#iB zeH{oVE@i~kU@(p8_o%DiCoL+cV!OtDVi4B^#g)AJF&Eq6?L_cqU`csG@Lz$v2|4{9 z$XH`^M-yi<(xsWkv^BCs)PJJg)yBGPy|izuJ~m|Q4QypPGeE)^o07*Q&tw+x%uMeZ zV=|^=&^Lx26N{2D>6%^Gt_hu$D`SdfX1D2>cxrR1qqyeG(xx9fZ60&sXWa1};m0iL zIpq@1mmR<0*+9h3mwq(h7o87hJ)>bM&75MBon*VqgKRF_Z2$HvrawQJQrMg+Zq?L8 zQUj73+n_TyZ$y5aHLAI#CXrVLao9>kFR$%}Fst3IaKwd<0=DOcahQ2tzEX^NP5Avz z803|dXIH~0$_*y`-Q4I4K5SUIk@BdOTS`$*@8om{JW!aMX`gfUGZ802^WUFsbdnz5 z2*rAk_-V$)dYZJdjgJO``-6?94}0K8>svg6^@T~iz7_Tck)I`E{l+ls0AnMWSz3C& zKNN>RCoVQU0fd+~Jw{co!@sVrX?0qsqt*F#7YhqC6o7<(%((9K4ImkrfL*9lh11r$ zU`w;p)(So&V5wSDRH1*vfF%z4T!^gil*9!L#(pN3gWpXM!GGa5hJc+}>w^m-pbP4#vysd>fuFU|xfv9~Us6 zf7daq;H;TF(MuQ7p1F|dS64^fM?5*wi+dJ`nGRs{r+5?oC!FNfAc+#;iT1XO)Z+KW2?eQ5lt;6Y4jOIBJA2U)n_uE{2W$t0&;=xPR8s?>jR&X@ z6aLHC;~Z4R5UX@C62QoVGA)DXV*(c+c#8T_vPRwkhtgA1Fq-n|o-z=d;usCXwJ;iJ z58cD+f2Gw5gOJC;(5)-ZRX+fSSH8pGu1P1de0$`y^ZKCAAfC7)6(yjynE$Gp|6+5X zLpvsfbGeS+p)!kgD8xFtECYZr7J{;t73OI$?WBx)j+3!|oMhIHncjr8mi!Yl{u0@t z;ub_+m3PTqJ-#UW=%uVNll^v)53-UkWxoSi8)ZxFFkaak`n4e@8*AMP@BlIpvEj^2 zHX8%D)rl!%F+&3Bml8;yWKPEW0(|Cxr%u-4P7y>nJ~TnS?+YGhPLu>bh8?9Ow)F;? zWIDHf5&GK^cRD=kgPz0*AZmfIE`^XrhG|(Cs9vZfUDPsk(oQmnn6u5DAYq(2VJt@u zIw5ddgILBpbD61h*wFT*FW3zK+S}WcWD12n@g}r1YSQ1!D;Us)afVSCXStDuJ)Z0R zBvrl~dV;y-_xn6%$~!{uZV{jEauMdGpN47X+IPI9)q+URwTDH?iuo?8{FfF6aV(1vy2>7~YVh zwqfh?;-B4Bx!qO)YwFs?VXN47IY{DG*oHV04@tVv$}PZGNcq Op^YIXEbs6s{Qd!j@~@l# literal 0 HcmV?d00001 diff --git a/__pycache__/organisms.cpython-38.pyc b/__pycache__/organisms.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09ea772842290d60ab60fa0127f3646954c8522d GIT binary patch literal 4246 zcmd5!A?ZORv4SGo*H<1dda*2^tCO0VPSrz(K)vrLm#%7>DqxvqR*GQv2g4IZ~L34TnhThyT59wPjxv*3AYlz{#bb(RGY5Ef zW^PzRGNeP$H-s6R4kbgfVsC)iHtD!s8B%OBw?l`drHxcwPio${ECh+y;RzQ(#=XE3 zLBi6mS03|ZIq@pb`XceZ4B|dN?VTIXj0dGO^9o~o>Cy@hvx#i;x1WE)^2bLb3dR{# zkl0AjhjMEPbmsPzI7qUsYVPPw_QaBxy3}V=370%2U|{VNglUzM=Q$dt(*>k2MTjr_Bdx-L>vXpf4#kM zdhrX%g#b@JypA z(2`pg9H-yoLO?_ku^-7C@(uAEwhv;P=G9g!i~}iKEp=#d498FcO(2zD!=_=wdnOx3 zYc{MV6tE`PKMA@V>|blOx+&|&*six)-}Hl6k0_HUrTOf5xsbI3E91+9Czn>;RNzlU|6y_jWHeBwF~<>Sb$uXoFU+&OZKvrdBVKLxJ9 zC>3}$0{vUyBPXgrawml_?Qk)JoHvl*?c~*kKxk`=Ix^>xsM}UV-8M$c%TRZZmi^^X zo_w%iaETX?yoAILt(bu%_I^89%AZn9(L6U(H_U4PW%};PsX1`161wu z`PqQsXVaBCX6eW?kNpIde)QBm*%X{jJXo1`ci;U0EWEq#&P{gz*zcJ$t}IPD~m5<=Aq2&K`SZ)p_g+Zw(3j>2g(>fPAIi|>QZ z|JRGN3htb_cgzw@xnnSeNVB@W@|dSs;hCrHy`w%DYJ{&?qbg?MPwYXm7YX7B{T(im zKwb^gI2A3?S<)EcQSbBDAS)3s?1X0K0UGGjJ<_`o=PjTP^dW^&Xj4Cx>cxHNi-0fg zD$Yg-MCf`=Ye#1dQBzT{UE*wvgCSt^6`%@bQ)Xm1>+OHq{>RaKto}BI0ImNbE<7Y+sFzhw3vBBq5MN+XdWV&vuexh zaNd%Cc+8(6t5n>8Ov8Gg+%}WbYK~pXT4UL7r}-eO_)7M>LblWn>y@)%UI%iJp|Mc` z>qB5bhJrh@*?0|@S>3c%?%`nWwEklmE}vvx#(M&AW5}hKEpx8`(_R2W(C-C;Cz%(g zVUR^>QcB`jx1TAdcQX)CuoQD|na4fQlX{`xn8wJo%T-#EMWLRBO60VbfhU*Ke$2cj z?u9Ai%!?AWa=07;x7|;|2W6r^x3{-PDy+~6N6_0=xTx8vskqB4n6^YohPei3xs^p- zo}0Z?D(_JdnL9zR#}g)wg9`CHkcKls=KgGv%*f9m_we0Yt+d^Se8zVNMaxO}8mfHA z39F*8rvRlAF+XuI=cpN{XpNqtu5pa6@6{ez&eeFnQ4z1ebnz;Z*N`AS)33u@*m@7i zWI@$ZCUG+>hvM)gsV}|QGbH* fOQSL64lCyF8J%r>h<70IrE@XCg5&Kwiod@BjRb}C literal 0 HcmV?d00001 diff --git a/analyse.py b/analyse.py new file mode 100644 index 0000000..a0112dd --- /dev/null +++ b/analyse.py @@ -0,0 +1,37 @@ +import numpy as np +import matplotlib.pyplot as plt + +figure = None +plot = None + +def plotValues(Organisms): + '''This function plots the interesting values of the organisms + ''' + global figure + global plot + speeds = [] + sizes = [] + + if figure != None: + + for Organism in Organisms: + speeds.append(Organism.speed) + sizes.append(Organism.size) + + plot.set_ydata(sizes) + plot.set_xdata(speeds) + + + else: + + plt.ion() + figure = plt.figure() + + for Organism in Organisms: + speeds.append(Organism.speed) + sizes.append(Organism.size) + + plot, = figure.add_subplot(1, 1, 1).plot(speeds, sizes, 'b*') + plt.title("Living organisms attributes") + plt.xlabel("Speed") + plt.ylabel("Size") \ No newline at end of file diff --git a/configuration.py b/configuration.py new file mode 100644 index 0000000..17dada5 --- /dev/null +++ b/configuration.py @@ -0,0 +1,8 @@ +# Simulation configuration +windowSize = 100 +tickTime = .5 +gameTicks = 200 +eventLog = False +speedFactor = 1 +loop = False +energyFactor = 0.0001 \ No newline at end of file diff --git a/configuration.pyc b/configuration.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d88d26db58cdde5b72d006b9dcd9df4a939c819f GIT binary patch literal 362 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 F|1YcP53B$H literal 0 HcmV?d00001 diff --git a/natural_selection.py b/natural_selection.py index 129ffe1..1fd70e6 100644 --- a/natural_selection.py +++ b/natural_selection.py @@ -1,534 +1,183 @@ ''' 2016 CS-167 Final Project: natural_selection.py - This program runs a simulation on natural selection in a -graphical interface. Watch as the organisms move about +graphical interface. Watch as the Organisms move about targeting prey (or plants) and attempting to avoid predators. -The largest fitter organisms will survive. - +The largest fitter Organisms will survive. by Owen Davis-Bower ''' import random from graphics import * - -# Simulation configuration -windowSize = 100 -tickTime = .5 -gameTicks = 200 -eventLog = False -speedFactor = 1 -loop = False - -class organism: - ''' - This class represents organism objects that all - have different traits and allows them to move about - and consume each other every game tick. - ''' - - def __init__(self, window, x, y, size, speed, organismType): - ''' - Initializes the organism by assigning it's traits - and drawing the organism on the screen. - - Parameters: - window: The graphical window to draw on. - x, y: The x and y starting coordinates of the organism. - size: The size of the organism. This effects the graphical - size of the organism as well as the strength of the - organism in combat. - speed: The maximum speed at which an organism can move each - game tick. - organismType: The type of an organism (Plant, omnivore, - herbivore, or carnivore) - - Return Value: none - ''' - self.pos = [x, y] - self.size = size - self.speed = speed - self.type = organismType - self.prey = self.preyList() - self.hunger = 50 - - self.organismGraphic = Circle(Point(self.pos[0], self.pos[1]), self.size) - - # assign a color based upon organism type - if self.type == 'omnivore': - self.organismGraphic.setFill('orange') - elif self.type == 'herbivore': - self.organismGraphic.setFill('blue') - elif self.type == 'carnivore': - self.organismGraphic.setFill('red') - elif self.type == 'plant': - self.organismGraphic.setFill(color_rgb(10, 117, 31)) - self.organismGraphic.draw(window) - - def update(self, organismsList, window): - ''' - Updates the organism's position and hunger every - simulation tick. - - Parameters: - organismsList: the list of organisms (including - the organism itself) - window: The graphical window which the organism - resides on. - - Return Value: none - ''' - self.closestTarget = self.nearestTarget(organismsList) - - # move the organism - if self.isPrey(self.closestTarget): - self.moveToTarget(self.closestTarget) - else: - self.moveRandom() - - # keep the organisms from leaving the screen - self.stayInScreen() - - self.draw(window) - - # checks for collisions and responds accordingly - self.checkCollisions(organismsList) - - self.hunger += -0.5 - if self.hunger <= 0: - if eventLog: - print('Self starved') - self.die(organismsList) - - def isPrey(self, target): - ''' - Given a target organism, checks if the target is prey - for the checking organism. - - Parameters: - target: The target organism that is being checked. - - Return Value: - True if the target organism is prey for the self; - else False. - ''' - if target.getType() == 'plant' and 'plant' in self.prey: - return True - elif target.getType() in self.prey and target.getSize() < self.size: - return True - return False - - def preyList(self): - ''' - Taking in the self organism's type, returns a list of - prey types. For example an herbivore will only return - 'plant'. - - Return Value: - A tuple containing all of the acceptable prey types. - ''' - if self.type == 'omnivore': - return ('plant', 'omnivore', 'herbivore', 'carnivore') - elif self.type == 'herbivore': - return ('plant') - elif self.type == 'carnivore': - return ('omnivore', 'herbivore', 'carnivore') - - def getPos(self): - ''' - Returns the position of the given organism as a list - containing two points [x, y]. - ''' - return self.pos - - def getSize(self): - ''' - Returns the size of the given organism as a float value. - ''' - return self.size - - def getType(self): - ''' - Returns the type of the given organism as a string value. - ''' - return self.type - - def die(self, organismsList): - ''' - "Kills" the given organism by undrawing it and then - removing it from the list of organisms. - - Parameters: - organismsList: The list to remove the given - organism from. - - Return Value: none - ''' - self.organismGraphic.undraw() - organismsList.remove(self) - - def distanceFromTarget(self, target): - ''' - Calculates and returns the distance between the given - organism and the target organism. - - Parameters: - target: A target organism. - - Return Value: The distance between the given organism - and the target organism. - ''' - return (abs(target.getPos()[0] - self.pos[0]) + abs(target.getPos()[1] - self.pos[1])) - - def nearestTarget(self, organismsList): - ''' - Searches through the list of other organisms and - returns the organism object of the nearest organism. - - Parameters: - organismsList: The list of living organisms. - - Return Value: The organism object of the nearest - organism. - ''' - self.selfIndex = organismsList.index(self) - self.otherOrganisms = list(organismsList) - self.otherOrganisms.pop(self.selfIndex) - self.closestTarget = self.otherOrganisms[0] - for organism in self.otherOrganisms[1:]: - if self.distanceFromTarget(organism) < self.distanceFromTarget(self.closestTarget): - self.closestTarget = organism - return self.closestTarget - - def moveToTarget(self, target): - ''' - Moves the given organism towards the target organism. - - Parameters: - target: A target organism. - - Return Value: none - ''' - self.targetPosX, self.targetPosY = target.getPos() - self.distanceX, self.distanceY = (self.targetPosX - self.pos[0], self.targetPosY - self.pos[1]) - - if self.distanceX >= 0: - self.velocityX = self.speed * speedFactor - if abs(self.distanceX) < abs(self.velocityX): - self.velocityX = self.distanceX - else: - self.velocityX = -self.speed * speedFactor - if abs(self.distanceX) < abs(self.velocityX): - self.velocityX = self.distanceX - self.pos[0] += self.velocityX - - if self.distanceY >= 0: - self.velocityY = self.speed * speedFactor - if abs(self.distanceY) < abs(self.velocityY): - self.velocityX = self.distanceX - else: - self.velocityY = -self.speed * speedFactor - if abs(self.distanceY) < abs(self.velocityY): - self.velocityY = self.distanceY - self.pos[1] += self.velocityY - - def moveRandom(self): - ''' - Moves the given organism randomly in 2D space. - ''' - self.velocity = (random.uniform(-self.speed, self.speed) * speedFactor, random.uniform(-self.speed, self.speed) * speedFactor) - self.pos = [self.pos[0] + self.velocity[0], self.pos[1] + self.velocity[1]] - - def stayInScreen(self): - ''' - Prevents the organisms from leaving the screen. - ''' - if self.pos[0] + self.size >= windowSize: - self.pos[0] = windowSize - self.size - elif self.pos[0] - self.size <= -windowSize: - self.pos[0] = -windowSize + self.size - elif self.pos[1] + self.size >= windowSize: - self.pos[1] = windowSize - self.size - elif self.pos[1] - self.size <= -windowSize: - self.pos[1] = -windowSize + self.size - - def draw(self, window): - ''' - Creates a graphical object for the organism based - upon it's size and type and then draws it onto the - graphic window. - - Parameters: - window: A graphical window. - - Return Value: none - ''' - if self.type != 'plant': - if self.organismGraphic: - self.organismGraphic.undraw() - self.organismGraphic = Circle(Point(self.pos[0], self.pos[1]), self.size) - - # assign a color based upon organism type - if self.type == 'omnivore': - self.organismGraphic.setFill('orange') - elif self.type == 'herbivore': - self.organismGraphic.setFill('blue') - elif self.type == 'carnivore': - self.organismGraphic.setFill('red') - elif self.type == 'plant': - self.organismGraphic.setFill(color_rgb(10, 117, 31)) - self.organismGraphic.draw(window) - - def checkCollision(self, collidingOrganism): - ''' - Checks if the given organism is colliding with the - "collidingOrganism". - - Parameters: - collidingOrganism: The organism to be tested against. - - Return Value: - True if the given organism is colliding with the - "collidingOrganism"; else returns False. - ''' - self.collidingOrganismPos = collidingOrganism.getPos() - self.collidingOrganismsize = collidingOrganism.getSize() - - if (self.pos[0] - self.size) <= self.collidingOrganismPos[0] <= (self.pos[0] + self.size): - if (self.pos[1] - self.size) <= self.collidingOrganismPos[1] <= (self.pos[1] + self.size): - return True - elif (self.collidingOrganismPos[0] - self.collidingOrganismsize) <= self.pos[0] <= (self.collidingOrganismPos[0] + self.collidingOrganismsize): - if (self.collidingOrganismPos[1] - self.collidingOrganismsize) <= self.pos[1] <= (self.collidingOrganismPos[1] + self.collidingOrganismsize): - return True - return False - - def checkCollisions(self, organismsList): - ''' - Checks if the organism is colliding with any organisms - and reacts appropriately by killing one of the - organisms if it is prey of the other. - - Parameters: - organismsList: The list of organisms. - - Return Value: none - ''' - for organism in organismsList: - if organism != self: # prevents organism from checking if it's colliding with itself - if self.checkCollision(organism): - if self.isPrey(organism): - if eventLog: - print('Self killed organism') - self.hunger += 8 - organism.die(organismsList) - elif organism.isPrey(self): - if eventLog: - print('Organism killed self') - organism.hunger += 8 - self.die(organismsList) +from organisms import * +from configuration import * +from analyse import * class simInterface: - def __init__(self): - ''' - Initializes the simulation window. - ''' - # initialize window - self.win = GraphWin('Natural Selection Simulation', 700, 700) - # transform coordinates - self.win.setCoords(-100, -150, 100, 100) - - self.lowerInterface = self.createLowerInterface() - self.lowerInterface.draw(self.win) - - self.organismCircle = None - - def getWin(self): - ''' - Returns the simulation window. - ''' - return self.win - - def createLowerInterface(self): - ''' - Draws the interface at the bottom of the screen. - ''' - interfaceRectangle = Rectangle(Point(-100, -100), Point(100, -150)) - interfaceRectangle.setFill("gray") - return interfaceRectangle - - def close(self): - ''' - Closes the graphical window. - ''' - self.win.close() + def __init__(self): + ''' + Initializes the simulation window. + ''' + # initialize window + self.win = GraphWin('Natural Selection Simulation', 700, 600) + # transform coordinates + self.win.setCoords(-100, -150, 100, 100) + + self.lowerInterface = self.createLowerInterface() + self.lowerInterface.draw(self.win) + + self.OrganismCircle = None + + def getWin(self): + ''' + Returns the simulation window. + ''' + return self.win + + def createLowerInterface(self): + ''' + Draws the interface at the bottom of the screen. + ''' + interfaceRectangle = Rectangle(Point(-100, -100), Point(100, -150)) + interfaceRectangle.setFill("gray") + return interfaceRectangle + + def close(self): + ''' + Closes the graphical window. + ''' + self.win.close() class naturalSelectionSim: - def __init__(self): - ''' - Initializes the simulation window and interface. - ''' - self.interface = simInterface() - self.window = self.interface.getWin() - - def runSim(self): - ''' - Runs the simulation from start to finish. - ''' - self.displayInformation() - - self.waitForClick() - - self.spawnOrganisms() - - self.keepRunning = True - for i in range(gameTicks): - self.update() - - time.sleep(2) - - # destroy all remaining organisms - for organism in self.organisms: - organism.die(self.organisms) - - def waitForClick(self): - ''' - Displays a message on the screen and waits for user - input in order to continue. - ''' - self.startText = Text(Point(0, 0), 'Click anywhere to begin the simulation.') - self.startText.setSize(20) - self.startText.draw(self.window) - self.window.getMouse() - self.startText.undraw() - - def displayInformation(self): - ''' - Displays information in the lower interface of simulation - window. - ''' - self.informativeText_1 = Text(Point(0, -105), 'Click anywhere inside the habitat to spawn a new organism.') - self.informativeText_1.setSize(20) - self.informativeText_1.draw(self.window) - - self.plantExample = Circle(Point(-90, -120), 3) - self.plantExample.setFill(color_rgb(10, 117, 31)) - self.plantExample.draw(self.window) - self.plantTitle = Text(Point(-75, -120), '= Plant') - self.plantTitle.setSize(20) - self.plantTitle.draw(self.window) - - self.herbivoreExample = Circle(Point(-90, -130), 3) - self.herbivoreExample.setFill('blue') - self.herbivoreExample.draw(self.window) - self.herbivoreTitle = Text(Point(-69, -130), '= Herbivore') - self.herbivoreTitle.setSize(20) - self.herbivoreTitle.draw(self.window) - - self.omnivoreExample = Circle(Point(-90, -140), 3) - self.omnivoreExample.setFill('orange') - self.omnivoreExample.draw(self.window) - self.omnivoreTitle = Text(Point(-69, -140), '= Omnivore') - self.omnivoreTitle.setSize(20) - self.omnivoreTitle.draw(self.window) - - def randomOrganism(self, organismType, position = None): - ''' - Generates a random organism. - - Parameters: - organismType: The type of the new organism (Plant, - herbivore, omnivore, carnivore) - position (optional): The starting position of the - organism. Otherwise the start - position is randomly generated. - - Return Value: A randomly generated organism object. - ''' - if position == None: - x = random.uniform(-(windowSize * .9), windowSize * .9) - y = random.uniform(-(windowSize * .9), windowSize * .9) - else: - x, y = position - size = random.uniform(1, 7) - speed = random.uniform(5, 10) - return organism(self.window, x, y, size, speed, organismType) - - def spawnOrganisms(self): - ''' - Spawns in randomly generated organisms by adding them - to a list of organisms. - ''' - self.organisms = [] - for i in range(7): - self.organisms.append(self.randomOrganism('omnivore')) - for i in range(5): - self.organisms.append(self.randomOrganism('herbivore')) - # BUG: Carnivores are not fully implemented yet. - # for i in range(5): - # self.organisms.append(self.randomOrganism('carnivore')) - for i in range(15): - self.organisms.append(self.randomOrganism('plant')) - - def spawnOrganismFromInput(self): - ''' - Spawns in randomly generated organisms at the location - of a mouse click. (Only works if the mouse click is in - the simulation window.) - ''' - self.mousePos = self.window.checkMouse() - if self.mousePos != None: - if abs(self.mousePos.getX()) < windowSize and abs(self.mousePos.getY()) < windowSize: - self.organisms.append(self.randomOrganism(random.choice(('omnivore', 'herbivore', 'plant')), (self.mousePos.getX(), self.mousePos.getY()))) - - def close(self): - ''' - Closes the simulation. - ''' - self.interface.close() - - def update(self): - ''' - Updates everything in the simulation every time - the function is called. - ''' - while self.keepRunning: - self.livingOrganisms = 0 - - self.spawnOrganismFromInput() - - for organism in self.organisms: - if organism.getType() != 'plant': - self.livingOrganisms += 1 - organism.update(self.organisms, self.window) - - # generates new plants to sustain the organisms. - if random.randrange(10) > 2: - self.organisms.append(self.randomOrganism('plant')) - - if self.livingOrganisms <= 1: - self.keepRunning = False - break - - time.sleep(tickTime) + def __init__(self): + ''' + Initializes the simulation window and interface. + ''' + self.interface = simInterface() + self.window = self.interface.getWin() + + def runSim(self): + ''' + Runs the simulation from start to finish. + ''' + self.displayInformation() + + self.waitForClick() + + self.spawnOrganisms() + + self.keepRunning = True + for i in range(gameTicks): + self.update() + + time.sleep(2) + + # destroy all remaining Organisms + for Organism in self.Organisms: + Organism.die(self.Organisms) + + def waitForClick(self): + ''' + Displays a message on the screen and waits for user + input in order to continue. + ''' + self.startText = Text(Point(0, 0), 'Click anywhere to begin the simulation.') + self.startText.setSize(20) + self.startText.draw(self.window) + self.window.getMouse() + self.startText.undraw() + + def displayInformation(self): + ''' + Displays information in the lower interface of simulation + window. + ''' + self.informativeText_1 = Text(Point(0, -105), 'Click anywhere inside the habitat to spawn a new Organism.') + self.informativeText_1.setSize(20) + self.informativeText_1.draw(self.window) + + self.plantExample = Circle(Point(-90, -120), 3) + self.plantExample.setFill(color_rgb(10, 117, 31)) + self.plantExample.draw(self.window) + self.plantTitle = Text(Point(-67, -120), '= Plant') + self.plantTitle.setSize(20) + self.plantTitle.draw(self.window) + + self.herbivoreExample = Circle(Point(-90, -130), 3) + self.herbivoreExample.setFill('blue') + self.herbivoreExample.draw(self.window) + self.herbivoreTitle = Text(Point(-59, -130), '= Herbivore') + self.herbivoreTitle.setSize(20) + self.herbivoreTitle.draw(self.window) + + self.omnivoreExample = Circle(Point(-90, -140), 3) + self.omnivoreExample.setFill('orange') + self.omnivoreExample.draw(self.window) + self.omnivoreTitle = Text(Point(-59, -140), '= Omnivore') + self.omnivoreTitle.setSize(20) + self.omnivoreTitle.draw(self.window) + + def spawnOrganisms(self): + ''' + Spawns in randomly generated Organisms by adding them + to a list of Organisms. + ''' + self.Organisms = [] + for i in range(3): + self.Organisms.append(Omnivore(self.window)) + for i in range(5): + self.Organisms.append(Herbivore(self.window)) + # BUG: Carnivores are not fully implemented yet. + # for i in range(5): + # self.Organisms.append(self.randomOrganism('carnivore')) + for i in range(15): + self.Organisms.append(Plant(self.window)) + + def close(self): + ''' + Closes the simulation. + ''' + self.interface.close() + + def update(self): + ''' + Updates everything in the simulation every time + the function is called. + ''' + while self.keepRunning: + self.livingOrganisms = 0 + + #show the evolution data + plotValues(self.Organisms) + + for Organism in self.Organisms: + self.livingOrganisms += 1 + Organism.update(self.Organisms, self.window) + + if self.livingOrganisms <= 1: + self.keepRunning = False + break + + time.sleep(tickTime) def main(): - ''' - Calls the simulation. If loop = True then loops the simulation - otherwise the simulation only runs once. - ''' - if loop: - for i in range(100): - simulation = naturalSelectionSim() - simulation.runSim() - simulation.close() - time.sleep(1) - else: - simulation = naturalSelectionSim() - simulation.runSim() - simulation.close() + ''' + Calls the simulation. If loop = True then loops the simulation + otherwise the simulation only runs once. + ''' + if loop: + for i in range(100): + simulation = naturalSelectionSim() + simulation.runSim() + simulation.close() + time.sleep(1) + else: + simulation = naturalSelectionSim() + simulation.runSim() + simulation.close() if __name__ == '__main__': main() diff --git a/organism.py b/organism.py new file mode 100644 index 0000000..c22e87a --- /dev/null +++ b/organism.py @@ -0,0 +1,280 @@ +import random +from graphics import * +from configuration import * +from abc import ABC, abstractmethod + +class Organism (ABC): + ''' + This class represents Organism objects that all + have different traits and allows them to move about + and consume each other every game tick. + ''' + + def __init__(self, window, x, y, size, speed): + ''' + Initializes the Organism by assigning it's traits + and drawing the Organism on the screen. + Parameters: + window: The graphical window to draw on. + x, y: The x and y starting coordinates of the Organism. + size: The size of the Organism. This effects the graphical + size of the Organism as well as the strength of the + Organism in combat. + speed: The maximum speed at which an Organism can move each + game tick. + Return Value: none + ''' + self.pos = [x, y] + self.speed = speed + self.size = size + self.prey = None + self.energy = 25 + self.age = 0 + self.type = self.getType() + + self.OrganismGraphic = Circle(Point(self.pos[0], self.pos[1]), self.size) + + def update(self, OrganismsList, window): + ''' + Updates the Organism's position and energy every + simulation tick. + Parameters: + OrganismsList: the list of Organisms (including + the Organism itself) + window: The graphical window which the Organism + resides on. + Return Value: none + ''' + self.closestTarget = self.nearestTarget(OrganismsList) + + # move the Organism + if self.isPrey(self.closestTarget): + self.moveToTarget(self.closestTarget) + else: + self.moveRandom() + + # keep the Organisms from leaving the screen + self.stayInScreen() + + self.draw(window) + + # checks for collisions and responds accordingly + self.checkCollisions(OrganismsList) + + self.updateEnergy() + self.age += 1 + + if self.energy <= 0: + if eventLog: + print('Self starved') + self.die(OrganismsList) + + #reproduces if he has enough energy + if self.energy >= 30: + self.energy -= 25 + self.reproduce(window, OrganismsList) + + def updateEnergy(self): + self.energy -= self.energyEfficiency(energyFactor/20, 10)*(self.size**3)*(self.speed)**2 + + def energyEfficiency(self, factor=1, offsetx=0, offsety=0): + #Calculate the enegy efficiency with the age + return (self.age - offsetx)**2*factor + offsety + + def reproduce (self, window, OrganismsList): + ''' + It teproduces the organism at the parent location + the mutation variable helps to create some genetic variations + they should be coded in the child functions + ''' + OrganismsList.append(self.__class__(window, self.pos[0], self.pos[1], self.size, self.speed)) + + def isPrey(self, target): + ''' + Given a target Organism, checks if the target is prey + for the checking Organism. + Parameters: + target: The target Organism that is being checked. + Return Value: + True if the target Organism is prey for the self; + else False. + ''' + if self.prey == None: + return False + + if target.getType() in self.prey: + if target.getType() == self.getType(): + if target.getSize() < self.size: + return True + else: + return True + return False + + def getPos(self): + ''' + Returns the position of the given Organism as a list + containing two points [x, y]. + ''' + return self.pos + + def getSize(self): + ''' + Returns the size of the given Organism as a float value. + ''' + return self.size + + def getType(self): + ''' + Returns the type of the given Organism as a string value. + ''' + return self.__class__.__name__ + + def die(self, OrganismsList): + ''' + "Kills" the given Organism by undrawing it and then + removing it from the list of Organisms. + Parameters: + OrganismsList: The list to remove the given + Organism from. + Return Value: none + ''' + #This is to avoid dying from hunger and eaten at the same time + if self in OrganismsList: + self.OrganismGraphic.undraw() + OrganismsList.remove(self) + + def distanceFromTarget(self, target): + ''' + Calculates and returns the distance between the given + Organism and the target Organism. + Parameters: + target: A target Organism. + Return Value: The distance between the given Organism + and the target Organism. + ''' + return (abs(target.getPos()[0] - self.pos[0]) + abs(target.getPos()[1] - self.pos[1])) + + def nearestTarget(self, OrganismsList): + ''' + Searches through the list of other Organisms and + returns the Organism object of the nearest Organism. + Parameters: + OrganismsList: The list of living Organisms. + Return Value: The Organism object of the nearest + Organism. + ''' + self.selfIndex = OrganismsList.index(self) + self.otherOrganisms = list(OrganismsList) + self.otherOrganisms.pop(self.selfIndex) + self.closestTarget = self.otherOrganisms[0] + for Organism in self.otherOrganisms[1:]: + if self.distanceFromTarget(Organism) < self.distanceFromTarget(self.closestTarget): + self.closestTarget = Organism + return self.closestTarget + + def moveToTarget(self, target): + ''' + Moves the given Organism towards the target Organism. + Parameters: + target: A target Organism. + Return Value: none + ''' + self.targetPosX, self.targetPosY = target.getPos() + self.distanceX, self.distanceY = (self.targetPosX - self.pos[0], self.targetPosY - self.pos[1]) + + if self.distanceX >= 0: + self.velocityX = self.speed * speedFactor + if abs(self.distanceX) < abs(self.velocityX): + self.velocityX = self.distanceX + else: + self.velocityX = -self.speed * speedFactor + if abs(self.distanceX) < abs(self.velocityX): + self.velocityX = self.distanceX + self.pos[0] += self.velocityX + + if self.distanceY >= 0: + self.velocityY = self.speed * speedFactor + if abs(self.distanceY) < abs(self.velocityY): + self.velocityX = self.distanceX + else: + self.velocityY = -self.speed * speedFactor + if abs(self.distanceY) < abs(self.velocityY): + self.velocityY = self.distanceY + self.pos[1] += self.velocityY + + def moveRandom(self): + ''' + Moves the given Organism randomly in 2D space. + ''' + self.velocity = (random.uniform(-self.speed, self.speed) * speedFactor, random.uniform(-self.speed, self.speed) * speedFactor) + self.pos = [self.pos[0] + self.velocity[0], self.pos[1] + self.velocity[1]] + + def stayInScreen(self): + ''' + Prevents the Organisms from leaving the screen. + ''' + if self.pos[0] + self.size >= windowSize: + self.pos[0] = windowSize - self.size + elif self.pos[0] - self.size <= -windowSize: + self.pos[0] = -windowSize + self.size + elif self.pos[1] + self.size >= windowSize: + self.pos[1] = windowSize - self.size + elif self.pos[1] - self.size <= -windowSize: + self.pos[1] = -windowSize + self.size + + def draw(self, window): + ''' + Creates a graphical object for the Organism based + upon it's size and type and then draws it onto the + graphic window. + Parameters: + window: A graphical window. + Return Value: none + ''' + if self.OrganismGraphic: + self.OrganismGraphic.undraw() + self.OrganismGraphic = Circle(Point(self.pos[0], self.pos[1]), self.size) + + def checkCollision(self, collidingOrganism): + ''' + Checks if the given Organism is colliding with the + "collidingOrganism". + Parameters: + collidingOrganism: The Organism to be tested against. + Return Value: + True if the given Organism is colliding with the + "collidingOrganism"; else returns False. + ''' + self.collidingOrganismPos = collidingOrganism.getPos() + self.collidingOrganismsize = collidingOrganism.getSize() + + if (self.pos[0] - self.size) <= self.collidingOrganismPos[0] <= (self.pos[0] + self.size): + if (self.pos[1] - self.size) <= self.collidingOrganismPos[1] <= (self.pos[1] + self.size): + return True + elif (self.collidingOrganismPos[0] - self.collidingOrganismsize) <= self.pos[0] <= (self.collidingOrganismPos[0] + self.collidingOrganismsize): + if (self.collidingOrganismPos[1] - self.collidingOrganismsize) <= self.pos[1] <= (self.collidingOrganismPos[1] + self.collidingOrganismsize): + return True + return False + + def checkCollisions(self, OrganismsList): + ''' + Checks if the Organism is colliding with any Organisms + and reacts appropriately by killing one of the + Organisms if it is prey of the other. + Parameters: + OrganismsList: The list of Organisms. + Return Value: none + ''' + for Organism in OrganismsList: + if Organism != self: # prevents Organism from checking if it's colliding with itself + if self.checkCollision(Organism): + if self.isPrey(Organism): + if eventLog: + print('Self killed Organism') + + self.energy += Organism.energy + Organism.die(OrganismsList) + elif Organism.isPrey(self): + if eventLog: + print('Organism killed self') + self.die(OrganismsList) \ No newline at end of file diff --git a/organism.pyc b/organism.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1ba0a1fe7ea54aa0cd97d65ea2e3f4fdd8daf195 GIT binary patch literal 11057 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 Y2Yn`i>Vl@z%iKDhLUG9G;P)Z(KNDvMKL7v# literal 0 HcmV?d00001 diff --git a/organisms.py b/organisms.py new file mode 100644 index 0000000..8e8dadc --- /dev/null +++ b/organisms.py @@ -0,0 +1,130 @@ +import random +from graphics import * +from organism import Organism +from configuration import * + +class Herbivore(Organism): + def __init__(self, window, x = None, y = None, size = None, speed = None): + ''' + Can generate a random Herbivore. + Return Value: A randomly generated Organism object. + ''' + if(x == None): + x = random.uniform(-(windowSize * .9), windowSize * .9) + if(y == None): + y = random.uniform(-(windowSize * .9), windowSize * .9) + if(size == None): + size = random.uniform(1, 7) + if(speed == None): + speed = random.uniform(5, 10) + + Organism.__init__(self, window, x, y, size, speed) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('blue') + self.OrganismGraphic.draw(window) + self.prey = ['Plant'] + + def draw(self,window): + super().draw(window) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('blue') + self.OrganismGraphic.draw(window) + +class Omnivore(Organism): + def __init__(self, window, x = None, y = None, size = None, speed = None): + ''' + Can generate a random Omnivore. + Return Value: A randomly generated Organism object. + ''' + if(x == None): + x = random.uniform(-(windowSize * .9), windowSize * .9) + if(y == None): + y = random.uniform(-(windowSize * .9), windowSize * .9) + if(size == None): + size = random.uniform(1, 7) + if(speed == None): + speed = random.uniform(5, 10) + + Organism.__init__(self, window, x, y, size, speed) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('orange') + self.OrganismGraphic.draw(window) + self.prey = ['Plant', 'Omnivore', 'Herbivore', 'Carnivore'] + + def draw(self,window): + super().draw(window) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('orange') + self.OrganismGraphic.draw(window) + +class Carnivore(Organism): + def __init__(self, window, x = None, y = None, size = None, speed = None): + ''' + Can generate a random Carnivore. + Return Value: A randomly generated Organism object. + ''' + if(x == None): + x = random.uniform(-(windowSize * .9), windowSize * .9) + if(y == None): + y = random.uniform(-(windowSize * .9), windowSize * .9) + if(size == None): + size = random.uniform(1, 7) + if(speed == None): + speed = random.uniform(5, 10) + + Organism.__init__(self, window, x, y, size, speed) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('red') + self.OrganismGraphic.draw(window) + self.prey = ['Omnivore', 'Herbivore', 'Carnivore'] + + def draw(self,window): + super().draw(window) + # assign a color based upon Organism type + self.OrganismGraphic.setFill('red') + self.OrganismGraphic.draw(window) + +class Plant(Organism): + def __init__(self, window, x = None, y = None, size = None, speed = None): + ''' + Can generate a random Plant. + Return Value: A randomly generated Organism object. + ''' + if(x == None): + x = random.uniform(-(windowSize * .9), windowSize * .9) + if(y == None): + y = random.uniform(-(windowSize * .9), windowSize * .9) + if(size == None): + size = random.uniform(1, 7) + if(speed == None): + speed = random.uniform(5, 10) + + Organism.__init__(self, window, x, y, size, speed) + # assign a color based upon Organism type + self.OrganismGraphic.setFill(color_rgb(10, 117, 31)) + self.OrganismGraphic.draw(window) + + def draw(self,window): + pass + + #Plants gather energy from sun + def updateEnergy(self): + self.energy += self.energyEfficiency(energyFactor, 10, 100*energyFactor)*(self.size**2) + + def reproduce (self, window, OrganismsList): + ''' + It teproduces the organism at the parent location + the mutation variable helps to create some genetic variations + they should be coded in the child functions + ''' + x_offset = random.randint(-15, 15) + y_offset = random.randint(-15, 15) + random.seed(time) + + if self.pos[0] + self.size + x_offset >= windowSize or self.pos[0] - self.size + x_offset <= -windowSize: + x_offset *= -1 + elif self.pos[1] + self.size + y_offset >= windowSize or self.pos[1] - self.size + y_offset <= -windowSize: + x_offset *= -1 + + newpos = [self.pos[0] + x_offset, self.pos[1] + y_offset] + OrganismsList.append(self.__class__(window, newpos[0], newpos[1], self.size, self.speed)) diff --git a/organisms.pyc b/organisms.pyc new file mode 100644 index 0000000000000000000000000000000000000000..554c2524e048245d58e5ee767b345960ba6ded6c GIT binary patch literal 5998 zcmds5OK%)S5boKR?R5envGX7i8FE0YNREYscq!o#E8!t969p`_!C?>a)Up?2?;KU9{}H1y)zq;2S#X}z}Vf}U0vN>U0wZkSJi(%*uHW4 zn;Vgue0BW3g;acnEXKd55~Z%Ya!nN)RNOA9ixqXALTq#nKp^u6zV(iWqGfj073WdBlJ~>Z z6a%|}%DXz>G&i$cSLHf2Hm=xEf3a$*(t5u+gC|q82iyIixkD z;wNNx&~;wz)Kq?!f^656m99&Rli%H%`m&}{aDwhQuRWZzE}V^$b2Q>+ziGqnA?M z1&o;MpWT$=mKmNe)*EbFK*HG(*duQ6nut23YF{&l$Y7(Y)y;C);XQ{T_Dkqs` z-%)CMSw662x@92ntqt?J4#a?HHQlaBjqP^r)2Ng}y_1K-EfdKAg|?SXlE}<)9^R6| zFxTS_XOdc>lb+1$CJ@8CE&15BV@46U7-}7N&`n8Je2CKORyNS9CSQrNu&_E`DYBkj zy*SEsI9go~p~x^<+0Y4;WU_Q+!wg1AXtR9f>ez09u$oQmzBo4=2i!C+yEu+aH4k{t zc`hyEce!?|cE~&AMK!dQNlf}B5UiZnZPOA0S4XE{Ck*#D5o?=Et&r}DT`6N=o4N~4Ata-gdd$DfA({P}%;gqf09c1w+ zK{X(Qs81xH3OK8sqCzNOLA|xS+bEu=i2m*HPiPLJ((S(f^#Y_q7+Pg z4vKs)qJV3u0h7TGd^3w1SOOa;EWy%9g$GwxN0wfxbtjAAs@BDyHdvf89NoEZ+#@>p z{jufS(G@TCdL}YDjmDM&IpXCof)gt5N>PqzWR}X1xktkov4=|{VFp=B#qjE*?3H3p zLQQaJp%JGJ#!%|_Q5r&#*iCsPfmU^Of@*83V+f!egJZwbFKxhy2_|g@qsCdw=5DPi7&{(KT05Xs*B)RWma)s!$G)))B<0eE|+B1Cw%V<^NQoDCB h-z?&5&wLdk*m)OEdV?rk@UlDLwGnY^*N&d#-=F44$+Q3f literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ec11f86 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,66 @@ +apturl==0.5.2 +asn1crypto==0.24.0 +Brlapi==0.6.6 +certifi==2018.1.18 +chardet==3.0.4 +chrome-gnome-shell==0.0.0 +command-not-found==0.3 +cryptography==2.1.4 +cupshelpers==1.0 +cycler==0.10.0 +defer==1.0.6 +dell-recovery==0.0.0 +distro-info===0.18ubuntu0.18.04.1 +httplib2==0.9.2 +idna==2.6 +keyring==10.6.0 +keyrings.alt==3.0 +kiwisolver==1.3.1 +language-selector==0.1 +launchpadlib==1.10.6 +lazr.restfulclient==0.13.5 +lazr.uri==1.0.3 +louis==3.5.0 +macaroonbakery==1.1.3 +Mako==1.0.7 +MarkupSafe==1.0 +matplotlib==3.3.3 +netifaces==0.10.4 +numpy==1.19.5 +oauth==1.0.1 +olefile==0.45.1 +pexpect==4.2.1 +Pillow==8.1.0 +progressbar==2.3 +protobuf==3.0.0 +pycairo==1.16.2 +pycrypto==2.6.1 +pycups==1.9.73 +pygobject==3.26.1 +pymacaroons==0.13.0 +PyNaCl==1.1.2 +pyparsing==2.4.7 +pyRFC3339==1.0 +python-apt==1.6.5+ubuntu0.5 +python-dateutil==2.8.1 +python-debian==0.1.32 +pytz==2018.3 +pyxdg==0.25 +PyYAML==3.12 +reportlab==3.4.0 +requests==2.18.4 +requests-unixsocket==0.1.5 +screen-resolution-extra==0.0.0 +SecretStorage==2.3.1 +simplejson==3.13.2 +six==1.15.0 +system-service==0.3 +systemd-python==234 +ubuntu-drivers-common==0.0.0 +ufw==0.36 +unattended-upgrades==0.1 +urllib3==1.22 +usb-creator==0.3.3 +wadllib==1.3.2 +xkit==0.0.0 +zope.interface==4.3.2