From 62966a76a08c5d0f1b7225883d6b8123e14dc3f8 Mon Sep 17 00:00:00 2001 From: Jakub Sztuba Date: Fri, 10 Jun 2022 04:05:23 +0200 Subject: [PATCH] Added genetic algorithm --- .idea/.gitignore | 8 + .idea/KELNER.iml | 8 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + can.png | Bin 0 -> 3074 bytes mess.png | Bin 0 -> 3162 bytes restaurant.py | 163 ++++++++++++++++++ restaurant.xlsx | Bin 13819 -> 15345 bytes tiles.py | 73 +++++++- trash.png | Bin 0 -> 3131 bytes 12 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/KELNER.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 can.png create mode 100644 mess.png create mode 100644 restaurant.py create mode 100644 trash.png diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/KELNER.iml b/.idea/KELNER.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/KELNER.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d56657a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c9d4f1a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/can.png b/can.png new file mode 100644 index 0000000000000000000000000000000000000000..d03d4afc503fa9f5ce2a3050c79e3892b019a5a5 GIT binary patch literal 3074 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 literal 0 HcmV?d00001 diff --git a/restaurant.py b/restaurant.py new file mode 100644 index 0000000..0fe2bd0 --- /dev/null +++ b/restaurant.py @@ -0,0 +1,163 @@ +import numpy as np +import pygame +import tiles + +#Parameters for genetic algorithm +n_trashes = tiles.howManyMesses +n_population = 100 +mutation_rate = 0.5 +listDraft = [] + +#Some settings for the whole project window +pygame.display.set_caption('Inteligentny Kelner - projekt SI 2022') +Icon = pygame.image.load('waiter.png') +pygame.display.set_icon(Icon) + +#Take data from tiles.py +for i in range(len(tiles.messesArray)): + # Generating a list of coordinates representing each trash + coordinates_list = [[x*32,y*32] for x,y in tiles.messesArray] + listDraft.append(tiles.coordsToNum(coordinates_list[i])) + +#Add some data +names_list = np.array(listDraft) +trashes_dict = {x:y for x, y in zip(names_list, coordinates_list)} + +#Testing: +#print(trashes_dict) + +#Function computing the distance between two points by its coordinates +def compute_trash_distance_coordinates(a, b): + return ((a[0]-b[0])**2+(a[1]-b[1])**2)**0.5 + +def compute_trash_distance_numbers(trash_a, trash_b, trash_dict): + return compute_trash_distance_coordinates(trash_dict[trash_a], trash_dict[trash_b]) + +#First step is to create the first population set +def genesis(trash_list, n_population): + + population_set = [] + for i in range(n_population): + #Randomly generated new solution + sol_i = trash_list[np.random.choice(list(range(n_trashes)), n_trashes, replace=False)] + population_set.append(sol_i) + return np.array(population_set) + +population_set = genesis(names_list, n_population) +#Testing +#print(population_set) + + +def fitness_eval(trash_list, trash_dict): + total = 0 + for i in range(n_trashes - 1): + a = trash_list[i] + b = trash_list[i + 1] + total += compute_trash_distance_numbers(a, b, trash_dict) + return total + + +def get_all_fitnes(population_set, trash_dict): + fitnes_list = np.zeros(n_population) + + #Looping over all solutions computing the fitness for each solution + for i in range(n_population): + fitnes_list[i] = fitness_eval(population_set[i], trash_dict) + + return fitnes_list + +fitnes_list = get_all_fitnes(population_set, trashes_dict) +#Testing +#print(fitnes_list) + + +def ancestors_choose(population_set, fitnes_list): + total_fit = fitnes_list.sum() + prob_list = fitnes_list / total_fit + pop_len = len(population_set) + ancestor_list_a = np.random.choice(list(range(pop_len)), pop_len, p=prob_list, replace=True) + ancestor_list_b = np.random.choice(list(range(pop_len)), pop_len, p=prob_list, replace=True) + + ancestor_list_a = population_set[ancestor_list_a] + ancestor_list_b = population_set[ancestor_list_b] + + return np.array([ancestor_list_a, ancestor_list_b]) + + +ancestor_list = ancestors_choose(population_set, fitnes_list) +#print(ancestor_list[0][2]) + + +def mate_ancestors(prog_a, prog_b): + offspring = prog_a[0:5] + + for trash in prog_b: + if not trash in offspring: + offspring = np.concatenate((offspring, [trash])) + + return offspring + + +def mate_population(progenitor_list): + new_population_set = [] + for i in range(progenitor_list.shape[1]): + prog_a, prog_b = progenitor_list[0][i], progenitor_list[1][i] + offspring = mate_ancestors(prog_a, prog_b) + new_population_set.append(offspring) + + return new_population_set + +new_population_set = mate_population(ancestor_list) +#print(new_population_set[0]) + + +def mutate_offspring(offspring): + for q in range(int(n_trashes * mutation_rate)): + a = np.random.randint(0, n_trashes) + b = np.random.randint(0, n_trashes) + + offspring[a], offspring[b] = offspring[b], offspring[a] + + return offspring + + +def mutate_population(new_population_set): + mutated_pop = [] + for offspring in new_population_set: + mutated_pop.append(mutate_offspring(offspring)) + return mutated_pop + + +mutated_pop = mutate_population(new_population_set) +#print(mutated_pop[0]) + +best_solution = [-1, np.inf, np.array([])] +for i in range(1001): + #What I put here: iteration number, minimal fitness value, average fitness value + if i % 100 == 0: print(i, fitnes_list.min(), fitnes_list.mean()) + fitnes_list = get_all_fitnes(mutated_pop, trashes_dict) + + #Saving the best solution + if fitnes_list.min() < best_solution[1]: + best_solution[0] = i + best_solution[1] = fitnes_list.min() + best_solution[2] = np.array(mutated_pop)[fitnes_list.min() == fitnes_list] + + ancestor_list = ancestors_choose(population_set, fitnes_list) + new_population_set = mate_population(ancestor_list) + + mutated_pop = mutate_population(new_population_set) + trashesList = [] + + for i in range(len(best_solution[2][0])): + trashesList.append(0) + + for i in range(len(best_solution[2][0])): + trashesList[i] = best_solution[2][0][i] + +#Prints some specs to recreate if needed +print(trashesList) +print(tiles.messesArray) + +#Pass solution to draw +tiles.main(trashesList) diff --git a/restaurant.xlsx b/restaurant.xlsx index 212a2da0dbb322354af765c6edc5ddd7c4733b33..35bacf55da6f1f641b7d4d0e40a6fdd213594cad 100644 GIT binary patch literal 15345 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 Bo74aR literal 13819 zcmZ{L1z40#_deYvt)u}+io$|4C?bNCbPGt!5=*zVqN12Is3@@P0+I_7vJwglh`=f- z;es^M{hw#`{oe2M`u%leFL$1E=FENW6QlDO>XK8ilaP?mfIn&^4z^bm4M<5yQYc7B z*uXc|7ro*B&TxNwlMo+ggsoJt*G<&p4tTRP%cafzJMBYaXZ?*#Ic{AN=-@0|Bew~= zAi+EIi-G;1;nA|8wNY-2Uh$2^VMN<~Wo}8HXOe<>j1BDjFGS8QD{{}h$q&v^o(?*3 z@!IHVF6GCLl&7_@$oDrmNM+y~7I)H5kLup8P0(^Uav~UQavXMN3#R9668ieJpm%7! zbz!W?@?+z<;|Z~s3;KqQHY%pN=LBha@60<$-n7g&JgbQ0@U@kCw|(iOd|Zr@661i} z1dKjzSl3NFid-(D&Zx<4E&-FSg3_^XWN*??H}_NBj=@)MDrNQusnptk30j!WnJ$rW(V%5$%hrMGAj=X_o1H=s&I@45JW_D=>K?iWP6`+g<`Hr-z< zLNEF6e2gZ<6;^er57r75?4Rw0-Gp0v|9rUM@IuhlYVXtO8&~;m-wNql%1kgP-JRMWNY{2c@fhY-!0@Yk+t zI@KWWly1SK%IaEXevZ4^rG)|mOJ6;^WTtAhPb3Ck`~G|~`SA^2rt~{3pQm$#Uuhto z7Cte`sD~R#efo9fwL4Xxd77gq$14;{eZDp6@FSDnm!si~1W)yDd9kS=?J&Qj%!>gY z4>@ckQs2B0^Al?yl1^4|INv=X(0(NwSI5wya5Sk+^~@TX@4)7)dHH}+R!^kQC%jz# z^T9^xU$YalC;t~839D>3q2nYZ11zK@+`sXGkU_XPJNqNf5I@dB5Z%kdrSf0)bKYEK zm!9w68eVO@_v-4Sv!;11&p*C8y72kN!#LRO7o>&=!UAP(98N!h$ysaFavc_N_VaGxo~w_77GP<-MbJHhvuLs|6iaG={GnVCSmU z-W~i{S-@7GIXuMfK0DkSIou*_wgp8+9Ij%qiCh9v?}s+W8uqraiDL(Qv;DhEQIT8g z>$_?y2OG;9FQ?nuf*KnRmRA~=B16{?s)LwIqPBR~=FXJ-3beN0-`T+pJ&W2)P-_h9 zS_6W@gfyRjK zGb_{Cy9+;%OAXt~8&M4*Tl@RwhmkAe>-Gner75@PK3ZoHNL~KhPsH=S#N>Fy@L*ez3vr}7Y82{4m1aH z+$IgKu8SPtx7ZN-x9e6!p6;-1P8t-ii|lN%4UI)j^tUyB89THPJ+#=`i;F_agKZGVvKS;p6qSu>OS{dm`_{*Ty3)->f6jNH94 z(q;%|eF{rIEcWLfFsOXC)%VBaXQUu8dA5;}JB#p3K_N0R56*qQsK2%~Ss0i#a~w=A zY0eWw4kArulAV_?@F@C&}CjO#CB5 z2bjsaUH=RI5+EfX-J>YRS#!TKwU@w|Z0#iex+v&8lB>S;lEH$slVkxIyQ$lie4J!v z0Uffa`BTxENk*B3Ttz2Tv12T3U{EK+`h0+C=H%Vv&7$Y)!SxgmA2UdnIVR3oBo{yU z^rmI8Yjz~Nzb=Bm13M#hdc6Kj#lRi%E)P^y1*T9;jYXF|wGncQf$5_#zg~CG z_ND7)SdVtzO-5Ka&DG;4*I6}}7z<(MF$5hHrr~+wUA^b!wdWJ(&Z7vu&}8>y90iAS zf#4-d1+k1*I!cojG6~B4cnvmG*?0wV&l<(L&Th`Kf2#*j35NcW(kVlDAUgU- zFvWzT(edJebR>n|a%83z;s=%M`fJx>m^mEYnqfORQ9tVu!Cgo4wWPh)ggoGFA+nAdTzr;gK^uh>0} zYhi&!v*^$g*Gkp9b}=(uFpU78-rCUK5cCyK^hYxqk)RUv=v=*(fYup}$KNt42t+m1{jzCM z;A}8ganDGcDF$;L)7Bjt448t>ope-R=$~zD^Glc0< zY1u^xHyI$9po}kuJ(H{c=8pd6fu5~*p;!alG}5~MXKvM|ybFQTN8qZeEb8&$L}X6e zt9asI20L9aPrwVWz{-|yrp!w&NQ_I?w3vo}Nw$M0=K?MUXIZM$0n{#ar!U;CB#3F8 zcS2zZlmix=>-xZ!FE-^U$*!uZg0?xKB)_!s0UH@NwB|tEm5jZR2 z0DCY);N-gVK@Jd9L~@}pob3onh`!dD1S^Q54k?8LHbO~7g~%zMB7XvA|?VkF^ec*p9FGhl-NP#V02Cz|q?P4d5{ zFwwmVO@s~XVsv`0LY^nZRk{(!d0eFhG>E_yH5XeUQ1TIGB}8Ph2v#WK0LJ9J#F(Kl z13jMaW|i?pn+TLtw`nFe%d@ib610b9e=G2i1_A}-!I0{%w8B*m4!$79lAdFKx+f*B za#k5|t-l{&YHjm7Eyax?-Eoy&(!f_07?eH&B?k$DJ*5>v@gUui(q)VU5r`QbT6T*RvGUB ztTiK=)mP2j!x4P%>kATRl|$H46T3f9)>{C-AbE%KcwuJU5GCq5k-LFvfziLgB>6KHEaY@3Zd-v+CKB55oK-~x7$S5-4NI6>42VlW6j!8gd|jx&uZAle#B z7_5YlQNmS1iNyR#A(Vo|ydbS^Xs|38BR?>Kbvd5ZyO=eHwS9$MOrTrarTv=R<6Qnz zAU9WsplA68xNH45aFpJx|1qZmv!IVy*r;n6@j%-`CB}4+358+mu}K^t4x}VMk)_01 zFw}R^6HUH>;IkqQA~t3M#Q1GP{Qf!@1Brw22E&vwtvDYE_NbO!o-@~zK1YHJaKi=6 zDC5V$vsG2WAb_E5jB+xA=i3o{*XA<^hao{EB>SfWfL4^n=dIc#q9ytDiE>||5RFuR zQxy!a`2`E(JY|9D{j^xPY43aocq!S6GFnWO{O_=xBkcSOHq3 zEuhz6V=iq!gd{U?{eIThqA)kn_PDT$|?uBs)B~7w+HYk=3uibuP^BE)re&ZJM;RFJiNAmVZdlGr|m8dgK?Q zV!^2T3l)V{(?sDS`Rcib&=#+*!2Cq8dd7+zHOj=hPj{UPXX0&zir{Z5t{tHd^i4rB z@tNv!mng28)EgQ1^Z1+gZ)}8+l+QMl&Emx5xy$j=4cLo_ejd<^XoQ)1dFN0|8&}gU zPVgH9&y-m;m!jqwYl}wb@*+!pAoLThk&-*sJprF(eV>L{@mPg~^ zXJEUCEy65&bk#07blPE;G56~ikEd-+aW5`^T^!x4tLABwTFmp7t$LR-Jv?6cQzft- zzrWDk6ER~QH&h{Tn7bMg47*&vq|2Sp7F#<;U8pb;e84cm)fm4NEntU>A8BN6>-FR| zt&bV}?j#WI5oeIK93j3}im6HttHBz}?+r5LEH3vkt7+qmE{A*E7BIub>($y0lT$|z zPCSz?dPo6lWo~~Lzj!5zYQ2>iNoYo5qI&pqb|#-m>vT~Bw6}3?=QS2Gc%%xTe;qx{ z)r$;Yf}DoJ8bik z;bVKt9#S`5m|EvycZ=vqajPe9TTm>lz8`It>nRysiKwqlG&L|pum`3o7ASbU6zI9E zmisXBl_{di@?fMzr8it1*AL%0A8>*DIF_a_6J9ZP0+o)mU2QYn^w3ZF=E+^8FoP7Z zSHvfqJ}X*aa6<{W_uCBWd5lIdJ8c|G@P_wXS1Z6qswYR3R+s8+AkBM_%7dqm%bPbF z_Nu?x*KXz!nj++Wi+qL5H7j{uyRc6OfvSqn`w@AnP{FPC@P@z}xY6Z?rGplg(eZ$w zyT`PwjmSfnE?k)bPsUzA$(oy{ejoD3<< z1mc()X5Jj!uYuDuanDl6X{a4OzX|W!m~UKN3_JhS4r|zc!Tj*~Y56xivpLtj&sxH! zt#=cb7KmQ4Jm$6}&^M;$@47FOi;cQ!hTG;pgd)Ek*DrVY_+h;2;aMX%lj1&g#ZJn{ zB88!@LlA;GETK>wty3O5pbpq$9`QV6nAsL6-_@=NrM&&s+-e=bA+BDkCN>&sUUW2p4k)9IFzC=sYL_y(8My5_m`YO7#AbOSqx!BL!L*@Zk`;sbrMCAc}W-GD&*k`(^5b0GPwtLgwHW` zmZY=|oV!I6?FMJLDT4o`k8es)upvT-!5b0HO5;cyw>S|+)kEP}=7DA9Q5-4ci34DuRvi8T(2@04U)WMyA<<|a0Al3)`~ zxd|&pvFW?LZT6YV*EF)OdzV?js<(8Iu8a^VS1Or2;KyOqO}9uU)Fn2=lUkxE%eG1c zqZJLYK5EK7)Q)*Nb7Z@KH}THQaf!?}!;?i=a~7ey=6rp;M`*HnCxL>l3p7RM#kD0B zWQn;6<8$;6XkrX04DR~^YFQrBSigU)p_ZDFSv^LVdz7G#lkAZ{MWREp!O5v>SUfU!;&CQB#wM=Zfa+lMas{y{W-cEhwA!odV1e2xgGe$JZ%mC}9ji zhNO*xX4eqv(j;N@9nwH0reQ}%{5pdNcfdL`$ z6bdCEcFfKvroP3ae|WavCLqN)ad>#Ac$hbrG3F~(o+y>8+n_pROt<{dNUbP!x+>kNxo_nKL$Nvtc+|_ZagKwNl9=`$nQigp-j3i zXjW7~wh4%2h9oHOe4pTd!{mXE8^$>7ap})=6|@<~(w0D!PVQ{d zpdmXRr^S+)M@uUyL4RCg@q1U@(m2Rr*kN9hBQZ%dq}p*JyFMuE(-(rpnp;#dmqR-v zXMU}{|3@pE*q^)<9Lcfo%Mn-y_Ln)3+s0ZcZV}o zL9SS4VlIvow75Vbd0e(3H~xoE9JMgu3N14R^XY0+A=te~^CPEB#VLZs`Ml7UzWVep zP;&QDjLv4^F}1pt1J=qgMP!szz#Dq$SmKW*l$?n+O1jsVDa;M=;oER#zRvM;PbgQayd^QCIUyeBax63NA-!ZEk`PFYcHNiI zCRUf#Et0bOG805I^YW-AC7km@+dLyScL{4{YsV6Tg4HEI=sz*jQ#gO|BDa;rFxcbo zI(5e3Jg5swg$lV+(e?2^q@dt4N7%RWzF~5B1~xb(Do?#dSz7%Sl|HoJfEl@6ze_@O zkx{o6OCEom2FudqKtpmiPUx&jiABJn9+Dq$ci4*Le1ahVMUn^OA64~77BhzG(~*lS zOaQby&bcaYo1AILWa6}>GxLmSB?GP9N1$on*-~$G+zOVlZ&=@6!%eRFXp<^!sf@sK;d8 zKHpixWGR;b^%IKn=2)7@)TWqro&ro?XCi2*y!COWOUpKmHEo4+!#0eQrg#r2Z*?uA zF1ViS2v1p4(rnoETMfeK*34z)!K?vbNxOt8x&^x7YU#7 z_rM}o|G~xzX70c|+4rRc^wD&6SNZyefp?#Szj%44nc?!y5$@tBsM*`vA(Kct#icDK}(G1^rIIsG(>IZm#pT`cf_^wRl{Y9H7t& zHUC7VAa?wqo*zzu$03^Ysgy3TD z-Vc>&W_h5AVI;o9h8sF&V&aKzimCtMh(IKF<4iYwn&%)lK}o?6w6jD=rOa?4kmvPnqrO;S zr6obE?ZsGf3&5LVNWyeGVzj$s{?9T}81+UBa0K9;B>fAh5P_x=7`i1&LeyCu z4cR7D)obOzjO80G7bJ$wGqb{Oieg7g#1|{jWr4;Aim8z#;Bky0oas-J{b|Vp1~Kq$sEPFezzkdrHMEBuajqIr z9}lW55W4nT2m^Z7P-s9^7V6Z8>GlagDHLe`#Hcx+AK<*kM>pVE(CYq^&;cFn-6=UW zRgh64`j;}kK&NZrm%s+`LJUWPd;gyl1d0T7ptNKOMuBdRn4Qwn zk9_v4+$D(3gE)=I=YS$N)D#2>NDIIj0Bp1w4iz~D7)soOE?_%x3Y1tIFL)OeVk_fR zpxa%cWrkAkKgD-VA}Kj6Q*k~++~N6Cpa#@PA|}K%;M*@LHo<>Cf4ZEw$|+z90h^ZI z(c@R{0bhMGFw1XebqnxTnweQ5X;>TZmh9iub*B^Z`RN-#oxL=@d$UJlT zQT@O=)Fdu}9Q7L-$Wz~R<_O}bjKkNa&_8D6fHWf~7?uz6+V2u6{(7-L6XL@j9T_oK zinKwQm>4H<;9o$XunbS6hFyjL0T~uQI|;6w}fktGIx5{X_g>f0amJCx<7#_j75x5vjXhV7592aWA* z?7T@l+}{~7@E&c5TIs;12*kppc7iM4g{^++HaI+3-Wr;Yig*_QE+SwP+w5}=HdnE8 z0{o*9J7aCGKT}dt1hNlSXD7KE)f#r^rhOZBz5n-WMJ%_6kT$psB@C{fF#mhC;-5<= z_l!Egg&dZ5s~iKP?))Antzd;8bWJWqYr1y}kII_yDZS#;O+ zi5>H{HKFddyU`b2=bKm+qq-Cu&xiEpCwH_ix%0XjVe=EpvCRinu!r+j8k-EzY!;1;l zU$}F(IF=rd^?1Bg$`a3d?arxq5pU+W6q!Kg+?LhXyr%HVxOU$C#zzJVweMN%4Z_Eh zr@0nre>7|;be2mn5k8;U9FKHz4yD=T_qlM$KAXNFa+51H+BW%y4|kgmT1SWNQ_pjK z*N?mw{h|Sv2a%C-;nFl0ol+-w{ugwa3ttM$0O*_G1{!oP4czxZxH|wU;%yA|euF=5l+nJ4Q`4 zcMf0V_0}_^H&9p2(S5d8Ze8iuEy7fB^7GY)7QP=&5_~UtyGegxy*zc2ar9(L%1PxW zoq4)rXJc)bq>DsD1ARFUl0>SPa$n~z(CEQ4?{kM#zo;FEzC^2adn$>8b?9eOf{?*g z_QyA=nBTkmf6Vn_XXHxl)lMaUHD$Ul2shACKHq6Hl25+aBjr~0Xpa!Tz_faV|LDS= zy^wQbFpBJ5`rYExoU&MbXG)%T&Lc|^-^u0$vmg8le9pSfCPtFN_9;eGSYx8?YQ_nz zQGpR!{$X28(+yN{YOl+u0m(~C+Rcw2h!&k>xuHX^ST1kLAF`k$8k041L(eC0rm~Yn zf={1!FhA2j;=R)8^=$bxt)p5DhoSZzImmtb|8=oDI*xl6xLAdfgoN>ri~U1xIum_c zZ!(sgDa{hOWPjvW~+;a6DAH*L-ac~hZ%-@weys^bH1^GLYfTfL$q{B3;s!D(Sx$<+ZjpI34( z6JlI+b2~@q6=ZIE<;#k$4r)8m3aV@zIgu{Pe`M@A`x6e;ujhoOc(G~BarZehSqCiy zt~$nVp;8Zx#3h&>#XZJj9dkRWshUu#FD`QK$}(HnyN%vds(?+=b@QtfcL#A)ow_iVr^m`KE%JG7NLih$6hE~7_LJw^&!>7{rQ5gNCc;05(KX=?#V)`Nk$QNMvX1snqmg$1rGFIGv~!FjEf)sbrq6( zN6VxXFytD~@2jXF5%{|~dpZC9NxajxV5yffq{-c|Dz4Q~eVOj4CY@4cc4MtVDa9V-KaGFYd?os*f%Z^3tGn&c z&Udj$JyiNT5(hSNUU0G(X+IUqXt!+Nx*l2& z?@n9oApN@e{+cW8+=jKjYpXFi$Fq)ib+8hG*~+oQR@TUuUw#JjaD+SE3VODTvidTD zHeX&OTaug``?eUE!SSxTN&eaLzBrFw^_^~wBQHM&(`L0G_|p__eE7zA@*U;!fCMS$ zY3mMjjH(gRPqK9rGea)OEM+FE;gOztWP=pnvSMhMN!ye`;Td#C(q78T`R#)>NtgO36g&%$;8RHBtz*5T!vyPl-n~83_o}oc< z^vvOwy|7J}zd{d3mQ^5H@D(fNP3*EXpLwF~X5M zVUNxBYA;8;7ZMQlPkF)gTI(6ZjA7bscn|l)IhZI-9(v1VNov-|#j)|?{UYttG@Vx^ zXpuGGzSL=69$4$yFAwF*?p)R3*N?aNtubNw`9S)9DCxsqO@#GT@!3Vk8O_$xr80M$ zOLUjogs1d6G53eZC*g6EeFZXlC-`>rcrV^@tmuAXL~Dn7aFfxu>EkD#v3$*}lH#Qv z>2o65fvzV$p>2OQp4IE}XuW$uK631?>#|p{Y?{u5KfPW2u7KPqpYoLr+Nqu0hTVpx zhUADKQ^}GcFD}M`f$51%`*(iY{6?)z{f{4Job$%9K4#h}O*`ZFV*6^gmXGBf^v`;k!}`E^7W(5ldw!=&9`a3(q#2fNlpKnwCdQZi>tc2Q)OGMV_jYjso^Y|-6zf9dfc_wdHyeCxndx$flleFValq|F;O(Q)wW=~np z*l!MZGIKda=kcK4TzdIqFWKtrn~S3uxM)jFW{K%n3{0}Hpa!eCX6;gLkC$69?$^xV9DmbqLpZ`(~SNQ8}L{?xh88G-z6 zB#V*0MlGuubK#BgL%|#NPXZef(v0yrB{EvhIcZ4oFB3u9_i1=;^bd8;R~yRC3Fn{m z8~&O5?e*-jg#E+isY&$n@GgF4&Y0oV&J*Z?waUxyTZamLx-NT--1Hr>-Zjc-9w&FU z@2M$V{^r=gw@jX-nr`rzhIQo{QlfF2z~T>gZ*?v{_;%LgNX)>UVEd`%LWR1r=5Maa zVF=eSD*G_kx=?oX-Eu@ku6zwP%>7FoQ0l z_}R~sI^ox?N(bBudPtS6`htY2AM;RqcUkyo#2B2=4*TR4A9&p2PT91QVW;coyq7gF z{W2C^{Pm74c~26qxX!YeCJK6n&8EKln*JB)R8K6Vcv44y=e9D;jcp5gI+-jVZ5;X5 z!4RFPlMow!WzLd!B<##(CwzdVJWui2sQZm(B}>?%!oK~&^SQO`nSRs~+~&`=YLgN@ z)0mOL6DW!m|D>G{L+%fq1d>is<+jzh{y=Q(y|sH$D|qQ)YGTFn62t}Cyv-Y5Qr`V+ zBEd(~`C;{SU~*-`2_?0wT^;)eKh3%?Z9(LEmVRa6Ni{ zL42}GC~R;z>(J?Fs^62hqZ%JKqUUw8Z=0@>o;cbhA#`5C@*+ED=1X|4>3LnJXTp^! zs23)!lA8fuvctjqqcJB{yH|CYl*r6A0{C0i1GR1Z*YG``=CYY{p{ut`? z{;NH2|Fs#aM|3@zTTm0`p|5v=} b?0<>>3423bN-F3HI`BIh_}N(o`rH2lgpdm6 diff --git a/tiles.py b/tiles.py index ff730ed..837cd55 100644 --- a/tiles.py +++ b/tiles.py @@ -5,6 +5,7 @@ import pygame import pytmx from queue import Queue import pandas as pd +from pygame import surface from sklearn.model_selection import train_test_split from sklearn.tree import DecisionTreeClassifier import json @@ -29,6 +30,9 @@ waiterImgL = pygame.image.load("waiterL.png") waiterImgR = pygame.image.load("waiterR.png") tableImg = pygame.image.load('table.png') chairImg = pygame.image.load('chair.png') +messImg = pygame.image.load('mess.png') +messImg2 = pygame.image.load('trash.png') +messImg3 = pygame.image.load('can.png') clientImg = pygame.image.load('client.png') image = pygame.image.load('test/0.jpg') @@ -114,6 +118,13 @@ class Chair: def render(self, surface): surface.blit(chairImg, (self.loc[0], self.loc[1])) +class Mess: + def __init__(self, loc): + self.loc = loc + + def render(self, surface): + surface.blit(messImg, (self.loc[0], self.loc[1])) + def pos_of_chair(table_cor, k): pos = ((table_cor[0], table_cor[1] - 32), @@ -336,6 +347,9 @@ class Map: def add_chair(self, loc): self.arr[loc[0] // 32, loc[1] // 32] = 100 + def add_mess(self, loc): + self.arr[loc[0] // 32, loc[1] // 32] = 100 + def add_table(self, loc): self.arr[loc[0] // 32, loc[1] // 32] = 200 @@ -576,6 +590,9 @@ def get_pizza(number): def display_img(surface, image): surface.blit(image, (120, 120)) +def display_sth(surface, image, coordX,coordY): + surface.blit(image, (coordX, coordY)) + def create_training_data(): DATADIR = "Images" @@ -638,14 +655,12 @@ def learn_neural_network(X, y): return model - def prepare_img(filepath): IMG_SIZE = 90 img_array = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE) new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE)) return new_array.reshape(-1, IMG_SIZE, IMG_SIZE, 1) / 255 - def predict(model,filepath): return model.predict([prepare_img(filepath)]) @@ -685,7 +700,31 @@ client = Client(generate_client()) neural_prediction_in = False -def main(): +restaurantIsClean = False + +howManyMesses = random.randint(8, 12) + +messesArray = [[0 for x in range(2)] for y in range(howManyMesses)] +for i in range(howManyMesses): + whereMessX = random.randint(1, 18) + whereMessY = random.randint(1, 18) + messesArray[i][0] = whereMessX + messesArray[i][1] = whereMessY +#messesArray = [[3, 14], [7, 17], [10, 9], [16, 10], [12, 18], [4, 11], [11, 14], [3, 5], [7, 18], [6, 13], [10, 8], [13, 16], [10, 6], [8, 6], [4, 10], [14, 6], [18, 1], [12, 17], [10, 11], [18, 3]] +#messesArray = [[9, 5], [16, 5], [5, 5], [10, 13], [3, 10], [8, 15], [13, 8], [14, 14], [12, 12], [3, 1]] +#messesArray = [[12, 8], [15, 9], [14, 9], [13, 6], [7, 7], [9, 7], [2, 15], [18, 16], [13, 15], [8, 18], [7, 14]] +#good example below +#messesArray = [[10, 12], [5, 17], [18, 3], [13, 2], [4, 5], [7, 4], [16, 5], [3, 2], [14, 17]] +#messesArray = [[12, 3], [11, 9], [13, 15], [3, 5], [2, 14], [17, 15], [1, 12], [14, 9], [7, 1], [7, 6]] +#this one below! +#messesArray = [[2, 15], [11, 9], [5, 11], [17, 1], [15, 7], [14, 10], [18, 8], [2, 9], [6, 4], [18, 10]] +#print(messesArray) + +pygame.font.init() +default_font = pygame.font.get_default_font() +font_renderer = pygame.font.Font(default_font, 12) + +def main(trashesList): direction = [] first_time = True number = 0 @@ -706,6 +745,20 @@ def main(): if tile is not None: display.blit(tile, (x * gameMap.tilewidth, y * gameMap.tileheight)) + key = pygame.key.get_pressed() + + + messesToDisplay = messesArray + for i in range (len(messesToDisplay)): + currentMessX = messesToDisplay[i][0] + currentMessY = messesToDisplay[i][1] + if i % 3 == 0: + display.blit(messImg, (currentMessX * 32, currentMessY * 32)) + elif i % 3 == 1: + display.blit(messImg2, (currentMessX * 32, currentMessY * 32)) + elif i % 3 == 2: + display.blit(messImg3, (currentMessX * 32, currentMessY * 32)) + waiter.handle_events() for table in tables: table.render(display) @@ -713,7 +766,6 @@ def main(): for chair in chair_list: chair.render(display) - key = pygame.key.get_pressed() left, middle, right = pygame.mouse.get_pressed() if key[pygame.K_e]: @@ -801,6 +853,19 @@ def main(): neural_prediction_in = False + font = pygame.font.SysFont('Arial', 18, bold=True) + trashesArray = trashesList + trashesLen = len(trashesArray) + #pygame.draw.line(display, (15, 0, 148), (32, 32), (numToX(trashesArray[0]), numToY(trashesArray[0])), 4) + for i in range(len(trashesArray)-1): + img = font.render(str(i), True, + pygame.Color(255, 255, 255), + pygame.Color(10, 148, 0)) + pygame.draw.line(display, (10, 148, 0), (numToX(trashesArray[i]),numToY(trashesArray[i])), (numToX(trashesArray[i+1]),numToY(trashesArray[i+1])), 4) + display_sth(display, img, numToX(trashesArray[i]), numToY(trashesArray[i])) + + img = font.render(str(trashesLen-1), True, pygame.Color(255, 255, 255), pygame.Color(10, 148, 0)) + display_sth(display, img, numToX(trashesArray[trashesLen-1]), numToY(trashesArray[trashesLen-1])) pygame.display.update() diff --git a/trash.png b/trash.png new file mode 100644 index 0000000000000000000000000000000000000000..537c989e76e5671b80e6196698691f232d4a3ab9 GIT binary patch literal 3131 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 ZEpG>%OS#BIsVV>Sd%63%RT0CIegkVL0}TKG literal 0 HcmV?d00001