From 71fcd755aad925b0bd7d5f2a7ee8b8c1d3dfc22c Mon Sep 17 00:00:00 2001 From: Vadzim Valchkovich Date: Fri, 5 May 2023 02:56:22 +0200 Subject: [PATCH] full refactor and upgrade code to first part of project --- README.MD | 24 +++++++++- agent.py | 27 +++++++++++ main.py | 76 ------------------------------ models/Kitchen.py | 18 ------- models/Object.py | 39 ---------------- models/Table.py | 41 ---------------- models/Waiter.py | 44 ------------------ src/Engine.py | 80 ++++++++++++++++++++++++++++++++ src/StateController.py | 60 ++++++++++++++++++++++++ src/UserController.py | 20 ++++++++ src/img/blank.png | Bin 0 -> 142 bytes src/img/block.png | Bin 0 -> 2398 bytes {images => src/img}/done.png | Bin src/img/front.png | Bin 0 -> 24640 bytes {images => src/img}/kitchen.png | Bin src/img/left.png | Bin 0 -> 22357 bytes {images => src/img}/order.png | Bin src/img/right.png | Bin 0 -> 13998 bytes {images => src/img}/table.png | Bin {images => src/img}/wait.png | Bin {images => src/img}/waiter.png | Bin src/obj/Block.py | 9 ++++ src/obj/Kitchen.py | 20 ++++++++ src/obj/Object.py | 47 +++++++++++++++++++ src/obj/Table.py | 24 ++++++++++ src/obj/TemporaryState.py | 51 ++++++++++++++++++++ src/obj/Waiter.py | 62 +++++++++++++++++++++++++ 27 files changed, 423 insertions(+), 219 deletions(-) create mode 100644 agent.py delete mode 100644 main.py delete mode 100644 models/Kitchen.py delete mode 100644 models/Object.py delete mode 100644 models/Table.py delete mode 100644 models/Waiter.py create mode 100644 src/Engine.py create mode 100644 src/StateController.py create mode 100644 src/UserController.py create mode 100644 src/img/blank.png create mode 100644 src/img/block.png rename {images => src/img}/done.png (100%) create mode 100644 src/img/front.png rename {images => src/img}/kitchen.png (100%) create mode 100644 src/img/left.png rename {images => src/img}/order.png (100%) create mode 100644 src/img/right.png rename {images => src/img}/table.png (100%) rename {images => src/img}/wait.png (100%) rename {images => src/img}/waiter.png (100%) create mode 100644 src/obj/Block.py create mode 100644 src/obj/Kitchen.py create mode 100644 src/obj/Object.py create mode 100644 src/obj/Table.py create mode 100644 src/obj/TemporaryState.py create mode 100644 src/obj/Waiter.py diff --git a/README.MD b/README.MD index 9f7123a..9d16b79 100644 --- a/README.MD +++ b/README.MD @@ -17,4 +17,26 @@ ## RUN INSTRUCTIONS - pipenv run python main.py + pipenv run python agent.py + +## TODO + +--- + +- [x] **Planowanie ruchu: Wymagania dot. pierwszego przyrostu** + + - [x] Agent powinien dysponować co najmniej następującymi akcjami: ruch do przodu, obrót w lewo, obrót w prawo + - [x] Należy wykorzystać „Schemat procedury przeszukiwania grafu stanów“. + - [x] Należy zaimplementować strategię Breadth-First Search. + +--- + +- [ ] Planowanie ruchu: Wymagania dot. drugiego przyrostu + - [ ] Należy wykorzystać „Schemat procedury przeszukiwania grafu stanów z uwzględnieniem kosztu“ + - [ ] Należy zaimplementować strategię A\*, czyli zdefiniować funkcję wyznaczającą priorytet następników uwzględniającą zarówno koszt jak i odpowiednią heurystykę. + - [x] Agent powinien dysponować co najmniej następującymi akcjami: ruch do przodu, obrót w lewo, obrót w prawo. + - [ ] Koszt wjazdu na pola poszczególnych typów powinien być zróżnicowany. + +> _Przykład: Koszt wjazdu traktora na pole marchewek to 10 a koszt wjazdu na pole puste to 1._ + +--- diff --git a/agent.py b/agent.py new file mode 100644 index 0000000..d41e7e5 --- /dev/null +++ b/agent.py @@ -0,0 +1,27 @@ +from src.Engine import Engine +from src.obj.Waiter import Waiter +from src.obj.Block import Block +from src.obj.Kitchen import Kitchen +from src.obj.Table import Table +from src.UserController import UserController +from src.StateController import StateController + +waiter = Waiter([0, 0], 0, 50, 450//50) +objects = [ + Kitchen([0, 0], 0, 50, 450//50), + Table([3, 6], 0, 50, 450//50), + Table([2, 4], 0, 50, 450//50), + Table([1, 5], 0, 50, 450//50), + Block([3, 5], 0, 50, 450//50), + Block([1, 4], 0, 50, 450//50), + Block([2, 5], 0, 50, 450//50) +] + +user = UserController(waiter) +state = StateController(waiter) +engine = Engine((450, 450), 50, user, state) + +for o in objects: + engine.subscribe(o) + +engine.loop() diff --git a/main.py b/main.py deleted file mode 100644 index 1f8aa39..0000000 --- a/main.py +++ /dev/null @@ -1,76 +0,0 @@ -import pygame -import random - -from models.Kitchen import Kitchen -from models.Table import Table -from models.Waiter import Waiter - -pygame.init() - - -screen_size = (600, 600) -screen = pygame.display.set_mode(screen_size) - - -square_size = 50 -num_squares = screen_size[0] // square_size - - -squares = [] -for i in range(num_squares): - row = [] - for j in range(num_squares): - square_rect = pygame.Rect( - j * square_size, i * square_size, square_size, square_size) - row.append(square_rect) - squares.append(row) - - -tables = [ - Table(square_size, screen_size, 2, 4), - Table(square_size, screen_size, 6, 5), - Table(square_size, screen_size, 4, 2), - Table(square_size, screen_size, 5, 6), - Table(square_size, screen_size, 4, 4), -] -kitchen = Kitchen(square_size, screen_size, 0, 0) -waiter = Waiter(square_size, screen_size, 0, 0) - -running = True -while running: - - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_UP: - waiter.up() - elif event.key == pygame.K_DOWN: - waiter.down() - elif event.key == pygame.K_LEFT: - waiter.left() - elif event.key == pygame.K_RIGHT: - waiter.right() - elif event.key == pygame.K_ESCAPE: - for table in tables: - table.new_order() - - screen.fill((255, 255, 255)) - - for row in squares: - for square_rect in row: - pygame.draw.rect(screen, (0, 0, 0), square_rect, 1) - - for table in tables: - table.blit(screen) - kitchen.blit(screen) - waiter.blit(screen) - - for table in tables: - if table.collision(waiter): - waiter.do_smth(table) - - if kitchen.collision(waiter): - kitchen.take_orders(waiter) - - pygame.display.flip() diff --git a/models/Kitchen.py b/models/Kitchen.py deleted file mode 100644 index 1035a16..0000000 --- a/models/Kitchen.py +++ /dev/null @@ -1,18 +0,0 @@ -import pygame -from models.Object import Object -from models.Waiter import Waiter - - -class Kitchen(Object): - def __init__(self, square_size, screen_size, left_square, top_square): - super().__init__( - 'kitchen', - square_size, - screen_size, - left_square, - top_square - ) - - def take_orders(self, waiter: Waiter): - for table in waiter.get_order_list(): - table.done_order() diff --git a/models/Object.py b/models/Object.py deleted file mode 100644 index c2b30e4..0000000 --- a/models/Object.py +++ /dev/null @@ -1,39 +0,0 @@ -import pygame - - -class Object: - def __init__(self, role, square_size, screen_size, left_square, top_square): - self.role = role - self.image = pygame.transform.scale(pygame.image.load( - 'images/{0}.png'.format(role)), (square_size, square_size)) - - self.square_size = square_size - self.screen_size = screen_size - - left = left_square * square_size - top = top_square * square_size - self.rect = pygame.Rect(left, top, square_size, square_size) - - def up(self): - if self.rect.top > 0: - self.rect.top -= self.square_size - - def down(self): - if self.rect.bottom < self.screen_size[1]: - self.rect.top += self.square_size - - def left(self): - if self.rect.left > 0: - self.rect.left -= self.square_size - - def right(self): - if self.rect.right < self.screen_size[0]: - self.rect.left += self.square_size - - def blit(self, screen): - screen.blit(self.image, self.rect) - - def collision(self, obj): - x = self.rect.left == obj.rect.left - y = self.rect.top == obj.rect.top - return x and y diff --git a/models/Table.py b/models/Table.py deleted file mode 100644 index 9e7ba05..0000000 --- a/models/Table.py +++ /dev/null @@ -1,41 +0,0 @@ -import pygame -from models.Object import Object - - -class Table(Object): - def __init__(self, square_size, screen_size, left_square, top_square): - super().__init__( - 'table', - square_size, - screen_size, - left_square, - top_square - ) - - self.state = 'table' - - def new_order(self): - self.state = 'order' - self.update_pic() - - def wait_order(self): - self.state = 'wait' - self.update_pic() - - def done_order(self): - self.state = 'done' - self.update_pic() - - def reset_order(self): - self.state = 'table' - self.update_pic() - - def is_order(self) -> bool: - return self.state == 'order' - - def is_done(self) -> bool: - return self.state == 'done' - - def update_pic(self): - self.image = pygame.transform.scale(pygame.image.load( - 'images/{0}.png'.format(self.state)), (self.square_size, self.square_size)) diff --git a/models/Waiter.py b/models/Waiter.py deleted file mode 100644 index 652a1fc..0000000 --- a/models/Waiter.py +++ /dev/null @@ -1,44 +0,0 @@ -import pygame -from models.Object import Object -from models.Table import Table - - -class Waiter(Object): - def __init__(self, square_size, screen_size, left_square, top_square): - super().__init__( - 'waiter', - square_size, - screen_size, - left_square, - top_square - ) - self.orders_limit = 3 - self.orders_list = [] - - def do_smth(self, table: Table): - if table.is_order(): - self.take_order(table) - elif table.is_done(): - self.deliver_order(table) - - def take_order(self, table: Table): - if self.orders_limit <= 0: - return - - if not table.is_order(): - return - - self.orders_limit -= 1 - self.orders_list.append(table) - - table.wait_order() - - def deliver_order(self, table: Table): - if table.is_done() and table in self.orders_list: - self.orders_limit += 1 - self.orders_list.remove(table) - - table.reset_order() - - def get_order_list(self) -> list[Table]: - return self.orders_list diff --git a/src/Engine.py b/src/Engine.py new file mode 100644 index 0000000..bbaa2b5 --- /dev/null +++ b/src/Engine.py @@ -0,0 +1,80 @@ +import pygame +from .obj.Object import Object +from .UserController import UserController +from .StateController import StateController + + +class Engine: + + def __init__(self, screen_size, square_size, user: UserController, state: StateController): + self.user = user + self.state = state + self.screen_size = screen_size + self.screen = pygame.display.set_mode(self.screen_size) + + self.square_size = square_size + self.num_squares = self.screen_size[0] // self.square_size + self.squares = self.__init_squares_field__( + self.num_squares, self.square_size) + + self.objects: list[Object] = [] + + self.runnin = False + + def __init_squares_field__(self, num_squares, square_size): + squares = [] + for i in range(num_squares): + row = [] + for j in range(num_squares): + square_rect = pygame.Rect( + j * square_size, i * square_size, + square_size, square_size) + row.append(square_rect) + squares.append(row) + + return squares + + def subscribe(self, object: Object): + self.objects.append(object) + + def loop(self): + self.running = True + while self.running: + + self.action() + self.redraw() + + def quit(self): + self.running = False + + def action(self): + self.user.handler(self) + + conditionals = [ + not self.user.obj.collide_test(self.user.obj), + all([not o.collide_test(self.user.obj) for o in self.objects]) + ] + + if all(conditionals): + self.user.obj.dampState() + else: + self.user.obj.rollbackState() + + self.user.obj.goal_test(self) + + def redraw(self): + self.screen.fill((255, 255, 255)) + + for row in self.squares: + for square_rect in row: + pygame.draw.rect(self.screen, (0, 0, 0), square_rect, 1) + + for o in self.objects: + o.blit(self.screen) + + self.user.obj.blit(self.screen) + + for s in self.state.path: + s.blit(self.screen) + + pygame.display.flip() diff --git a/src/StateController.py b/src/StateController.py new file mode 100644 index 0000000..88b0c7d --- /dev/null +++ b/src/StateController.py @@ -0,0 +1,60 @@ +from .obj.TemporaryState import TemporaryState + + +class StateController: + def __init__(self, istate): + self.path = [] + self.explored = [] + self.fringe = [] + self.istate = istate + + def reset(self): + self.path.clear() + self.explored.clear() + self.fringe.clear() + + def build_path(self, goal_state): + self.path.append(goal_state) + while self.path[-1].agent_role != "blank": + self.path.append(self.path[-1].parent) + + return self.path + + def graphsearch(self, engine): # BFS + print("Search path") + + self.reset() + + self.fringe.append(TemporaryState(self.istate)) + + while self.fringe: + self.explored.append(self.fringe.pop(0)) + + if self.explored[-1].goal_test(engine): + print("Goal!") + goal_state = self.explored[-1] + self.reset() + return self.build_path(goal_state) + + self.succ(self.explored[-1].front(), engine) + self.succ(self.explored[-1].left(), engine) + self.succ(self.explored[-1].right(), engine) + + self.path = self.fringe + engine.redraw() + + self.reset() + + print("Not found") + + return False + + def succ(self, state, engine): + if state.collide_test(): + return + elif any(e.compare(state) for e in self.explored): + return + elif any([o.collide_test(state) for o in engine.objects]): + return + + self.fringe.append(state) diff --git a/src/UserController.py b/src/UserController.py new file mode 100644 index 0000000..5dbe326 --- /dev/null +++ b/src/UserController.py @@ -0,0 +1,20 @@ +import pygame + + +class UserController: + def __init__(self, usrObj): + self.obj = usrObj + + def handler(self, engine): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + engine.quit() + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_UP: + self.obj.front() + elif event.key == pygame.K_LEFT: + self.obj.left() + elif event.key == pygame.K_RIGHT: + self.obj.right() + elif event.key == pygame.K_SPACE: + engine.state.graphsearch(engine) diff --git a/src/img/blank.png b/src/img/blank.png new file mode 100644 index 0000000000000000000000000000000000000000..0cb6d4116a1a0206a71afb87515b19fee550e062 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0y~yU^>9Sz}Umc3>0}cxlIj7F$egBxc>kDfB6yV6F@Fw zNswPKgTu2MX+Vypr;B4qMcms1hKxYoA%)+|w;kh)kN~prg9D76YZw?Ce$9;psq=L8 Kb6Mw<&;$T<@gS4{ literal 0 HcmV?d00001 diff --git a/src/img/block.png b/src/img/block.png new file mode 100644 index 0000000000000000000000000000000000000000..6012ad1634e6384e6f7ae67b5d46d3dfb36c96c1 GIT binary patch literal 2398 zcmY*beOOX?76!{y{2EEJbkQ=!{3xdht@uzxP_a-U%km?&b_y_cTS1eIF_keWGovyw z6bY5l&9+H%#I)II9c$e3ikO9i&Qy+9O?{sH8ZmV*TiY~$+~KKF>C zB0{YZjtCeGW=#vDFkvt_%lNEb1u^Hka(;sV6}2~-y0Wq|IXQ{P<4GhEkH>R&cP9`C z*G~Gyz+e`uX_TPoQ@RORT-sQeJvCJX2bdvAj%#wOb0pr|;jfRu-I3*@b9l$&m41z8%hg63D!7FSm6NsK4O3k>pZf8X4}c0W^lL(a?K(vc;L z1^)ARN8HTZ#NShLfsX9?>?08UF!ch?MQyDXq(1@@fc<^n%LnA+>hn?y{hEaReV_6C zxenY^1%^Bz?^NBbq5~L?YooPVH_I3yHwO)+IQiMBZTVRzHUb?BNte@ZZp#MzK~Bt6 zBnA1*K@uG7IT-CZ|XaYoG@etX2Lx0R<%|=Bp3Up z?&9LP+RfZPs?0)fjV8|gI{ojnX@wUpxDGt$#tkmWH`#bG*lp^81dK)wT z1)M2#a+6fW8V{(z0mly6B9qqw3EG3;li?J&47>SC1h5ZGOU)H-BhqXo>4cf}Gxi4a zNOj!LK9>XhMSyTezK#rFuO)a$9^wbrEw*Ka586<6}a@ zqhloMF1%nj@EPw0MaE`kWp@@jD=tb@8T2uqso#NM?RF&Z8=7obZz*3?9d)YL*UIAs6t=R@Tkmtw8%teSEWm!i7RY~b!Y4(B#MdBW1%a`RRktiiCqw19#=N^XI zC;c%@8&5}g4_qiwwMgw_QXIE2?)rJ!;Nlg>QkY5m(^Zrw{YnxTC6eBzmCW`gBT;f% z2@r%tRY9-`iBkL@s)+Dzcdrl$xvFwc^aV^uW+FkN+DI1*1sFz<)ZTK5qEKMj_xy@3 zs}9notrq4IRT5pCfA|BGs91DFfxw5+BegeQicec*LgF}O6|X-uX6L+E6LjlA4j69 zX@`KrBC$q^g-T7?Oh-r}59?_Qm2Q__F`KxmT2Buzm7rkBkH@Vm)h&$zJ94Oo3x#v(#SmG_qjsfUzhW800X+@PT%^ zI6A^ue7c^tY2qD)mG0-MlvSEd+`{mD*V>%g6#OBPGFFf2Xq;ZV6JEh#M&Sc(-#2=Y z7wc%=kdUn|h93LXCZl~jM}yEj?arTzk+>S2Z0l(7iFX7rv`@JJS$seO*x9FSF~;wa z05)+n_cH~qGqHZ`!;m1qO^U6RRkG>*^|TB~r#$y~pK{dL@E!@^NT2c>WBeWo;3bZx z5fb2r`LSd1f!4Txj0RLgF97|FTWLIxO{%&$eZ+%Y=&$c=o}QLJET6Ol%T$MeU+MGD zcQ7*KN2QZ(S5*tf;dP0YxOP*Xd|PvpKL6bgXkfV2Qu{27SG=SlTB3Lg&5Wjr!_<~R z6Qw>(7w=w+YM?>q+({CNwMr`2oui;oIhrrpkxkhfxUs#&D21yZJKUW!?FwpZPT!yi zIhulSt(!>Pr?j}L@rXem zsv^wlGSh+@%BmvyQANkf_4whS#)RB1E5Zy!0bLPUEGY z8x4(scm{#W_L@nGX0|Iw6s}R4PUlx2p0|r2i45xEznO$<`_B~Y%cbb^s(Ow~_-3BUd!qtR#=MKWVCK8v@<|6|lcl4Lo?1jG=VBPP3BajCy&={o z)X;~z7VE4oa(uy^3XgWe2A!8pJ*qh!qtMAMfbwx`hz^73U{b`f)ui5~XoXE>Xk_kk zh27h349|URB=kQ7RFjiSK(RB=e{>5Y{l5OxqGj8WZVcLOY&oBEeG<4!J1x@LprcE( zIx6U#MBN1Nucn$T@P+cXYJE{peBc>~)`dX-q_=pukuL8lEwg$&)e?W_xTIpDE{afp|mXJ<;rX3ADc!j z@BkTG4*T;C!5MLdmXMEI#i4zl1VLTWKc_*n(iIa2K=SyfWNk9EFu`cl2ucGvDeu1` C>WNwa literal 0 HcmV?d00001 diff --git a/images/done.png b/src/img/done.png similarity index 100% rename from images/done.png rename to src/img/done.png diff --git a/src/img/front.png b/src/img/front.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba38d947c1abeda3348f8f685eb6b5aa21e9371 GIT binary patch literal 24640 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
    %b&c zG8gVkV&N{z`&hn+xmZoc0)6Vlr_P<;+fc>TO$o|0T87z1Z;goU^_9+JQ zF*r=#xL~05&matbWpEJ&Zsg563{3tREP?V8bLMG)fP1xwDc4Jaj6P;K7;KGJ33 zE(ga-xFf({06UDj&+$<$-)u>dYK`zMU{>|gs92r4gS?P~+6}EwGW`qsls!TA1UOLT ziphI0*%FEubqfc25KaTS4fs|43Po@PM$O=V)G;8S1v|xgN$J8%OFqQzFA_eN|5>c3 zB6*KMAP7i3;!A^b{3%%xPzoTHURUVbyBeybkI;hDLWDXn;9SC=X7DHHB9JixG8sSy zW$oHReTu7zu?89Q3}^e+>|dZle+;JB5`2sbBhp-vgwdqnK}sOJ+d%3~7A0H=#g-zB zrxl1)h8z$;$H6c2)UZ$F*YM%Ue^ezTd@})J-11tK!z_`j0CyWuU-B(1Dhg*K?=}_; zoY$wMx8AlLSa-u=VVi01AxRN&? zlQ$5g9Du?qvI9Iae{O_|a6QCsng-DP4ppiZthGm~K<_V7r}Pmg^S^*7N8x!bjz>_k zdEi+8S%_{mHd=&@?z{*lp%rxkUYu`+sTFV_?P4=KxgTXuyyAW`X{d+LWd#~?)3K2@ zM0rS5o)3(Pg2+q(H9RiA#b0)=SWlJq2X=ShTKUUC|3PLup+6F~ZLbBqd~2ioa^_m) zBAqNjlp@o{+Co31XGLa?*po|+Q6ucxK!~n}dhbE5BEg9#)dD*Lpu5SZ@WvT?Y(}2* z1q2=r))eB!;h}(fTX3fVc$OGy25qS4O9ZVfXg`o@w5M_}Op)4Qp z%%KPNun&m=w%!aqAh{WD1=xd1076xua0i5}g@w_^K;aBR`ndaQpozZ^6AO*-X!YUL zhI;57wG;<`+-Yp;JzgFRF$m>g^;$xA?!5>V=ld$WAOa60)&AvW$8TAU@1A$d4&Y? z5g}QD3_@yz6(dl`Rv;{K#QSja9vaSj8-t}7tOv~;8~~C9V89QM=?TfIOB_b2f2(%BO1d-yrB5m~gS?pU%Qu3N+{=$FsNtFYJPX0aXIN z-2l<9@Yp0Cr{Bkd^;@v-b|7(#>>JoKQ9xL1T8ydC)k7p!{T`}Bg(F7NM{;ZNE%^B% z_({@reH>Ku0f1ePxvn_Bc^d(C8_2m2awMMs>`H+B4}{BoA2`ni&Yj?i1InF*d{&{^e;;e|BdBZ}tZ^0VxtEukeGFF1zQJ}S zpyFE1xx|gJwGbo~35_F}d)pn>XApf#(!6nFYSSdZ%FnlAV~Pk69i6Z0&@tNd|x1 zsAVNi3Iy?Q#-51@@+$;acmd8b0Qr`5I}o=cou@AVfR~w1J;!;WiVy%uWm}oQ2RQO^ z!qaY`_!jV523g3&5HC&wVJYc1(XeshDbR5o@zg^^8^Q`~7ytvSg27Y$@I+OJ8l#S5 zqdQ2nqmUd)--eZ#q6#4WFErFr&m9vp$wWkZQIAkKvm)4>*$pS|Cpah(OZB- zDRwc5^|$2D61CET!zGz~)Puz^4SFvSBdNPd1u73AZ!rJ#pJzE=?~L6&Q=%dyd9TUS z=8q-w;kcDO6&xG6*bDKwWEr%HYYtso=_FB$gzpemf*KPD&ld8c2H+ZOuV=>bO2J48 zsyw{KU|da*U;TTj4X6tM!OGF5h1?uCNRkdB3&0%Y?)1kHC~p*;_MaTqEjb8gR3RNH z0W-J;AeNXp*Th_wwg6f{cLL{1*u(%#T=)VAL_T(LAbB~JjSzy16NcpF6iLkOSDOEs zw%vq1Lg0TXQjz_F%{Dq9&ZFEm*`S)CH%ebtCYH*anM#7c%|)bQU$()!y;PS}kfGj3 zP}wrQ4@*byT%S4%1t4et5hyP;3Kk!MKQ@KsQekjcriZXvgw&N%hU*&;IO^_3!iOR- zmA#yy_&YLGWFLV)oK&Fm1<)yg((qP-_G3_*W+JG4U=-<0^dsOB-hlFC5-5Eu2@$(6 zu>cce{L%h{H=$gCfi5s0DY-Hy&pinY#4zGSecWj>H7y?81N~ z)Ie}DfHE;~3`kg@LJcC#9QFpC&&yC&p=yU_nB^HY)2OUJLw4?E(}7-q_c*at`t$Cx z#P#xQIGQ$u81_%MFqMP^bBChD(g+F)_`4;l)IoBR-&4}>9(ti?bqd-4-`Z-QFnz|6 zDyd5-dgiKoo(=V9jMop?kp8qosLg5IoXOi5{4j1kol9{_IcZ z%tb)4zmwt_3LPOlYRI!b!mwPQN zz%BIKszcIz+6-Y38ffT)pjtDAOk(U1#A*+l8${7?@GXdk{{^V=ag0Lv_%PH^IE|Bm z(j7=+#9nF=b8R(=Cc$BTu?Fv`Auxk-3C{yK5`FpztcSWu@WHxnLgf)?EJ^Fv64B%$ z=ov$cE)F>XWxott+G9%;{V2(jLQz_#n_wQ#8XMG-4Qd?DCO-EtAkU`pEIp$}Ink+F z9PEdRWjZwwjy?YVhJEg7u1ZOlo%CJdsY4H~1Qv*Wu6DsMQgOe*dg;v|dk6<5mGkN> zNI=^_;zD*nH-O~)ylO(irX&xr46O?3e3ziW`jrGJKRj89Ckt`wK*_}VVFG}lsD{cn zgiJj=XG{tJ!fv<L@HeH$D->^0fG|ZCBg>od*r1xUUKk~xb^^EkMTp{FedybD(U@GZpzDgk_KUcBG2)?#LZrQQGu8GZ=1Awq z7X?4GpGR5mFceP0T~W1&JaJJ&Xha5U;kU_Pf8sW>XSKuC%fMo8+u`0Hl}WywfbD*w zqt1c;XPXnOp|~8E6qoCViJ%w8XJWV(?}+1<3}9fLVtw6>ymKrt7M_9zC6j>w1EUd> z`6RiAaWGUH{5DDMslgmihBO`11W-Yx4LX9RQ!s$P3DFISU&#N{ZY<1(P|NR8=(1?u&g*TmDKhEpcgvC0hqQPWMUaLoNc6G7?nphOE5z?VT(Y- z1mP=Xf6TMp7z7}%=T#73OV1k%b)XX&1Xw4;Z2}43CN^7w0uxF0O^AVUmjhq;EL(Ci zN`gVnyk=Zdzy`dU$*7mwZmJ&Z?2rfKGDO<0=Ez`RO4JiiF3sAsdh+ zzZ2e+Vz>bC8&}TzH&goW`p?6AmXNS%|UV(BE%ZPDb`lwCleg^qaE=el=Y-PHPVn75{^{t zLopgLgPtlndBVQQ4DvAM)&E!=j;3f&9QminO9|INDl4(~IeR1nx#%ULp5>5K@qXPZDlb5{z^Nv2QL? zeoDIHDC!c>4#I+|=jXiCJd8BXDhGIOq#-4~O;{hdrO)K;AtJReGgQX9?YzjP40!No zcNxT$gYaHSkwvZ|JMVZ>WI@l)hC~CB_Oh~uSaL;-vxcFPZgWV6Z^f7pg3cQA+5z6z zy*SSSN3=4VM}ANDkn@X_At|1%l_>aRgwSz^AS~C^Y8j0fZee zr0%T8jw`h#b_8|P0}&+A=j9Vo+G}Ig4Xh$wn?FaSf}9@i4YbQXGV^rwwV|Cj+LBS_ zy5{x88d6;L8cTybg?$Nbc{a2e-rgf`bLku8o(rkO4}J{BQ%ehsdHq1Zk08+bi495f zC9Py?NqU6vOqd~WDM6ci9uCtH4gnp1VGx2&igyMZC$TQ{5B&#PKd@fNj3cWVoU2QcB6qMkbx9E_Q`UHvUNTH5vfxVO%XIPc> za5@MlOn(X$en<`n&ISaGj`Bq^bcQUxQ!cNK5vl0^iaiM>+13ncw)0jJ8ZCrC00e(P z5I7;*%T#0*yQ^eEJ?1N4|9S%r5FN=pY>r|zMgQPn)o#pNq^;IQys%ImH#GE{IrM)5 z(SV|aPxnX3cZ0omZgS`n6oc)Ed*baM3asB^Lq9Uo$gUL=J(UE$iGO5)fOCQ@T*%)D zwP?ePiZ?ToMJi~%)9Af}^^4vN0)v#BbVEg|u<(d-A>=>?cNyhO)Kbulr_p}LvQT(i zoNe>$&x8uET~n%8t*Z@b!Do|0j!FW*$>8{#EvNFbBZNjPwK-aZ7i0g65c*+Y;9lCW zpO_ntFsy5)j^kEFdAZdYVv~{&u^-4cRqnR|0|@p4Vcg(KhBV@N5lUF6B80a<+hJf# z)m%udj}R`ykcgIIHx_H4{x0089ot0~B4|YEp7&pO;tQ!l?0Gm;SZea-8WQa59fsU? zRm-_oEMhY!R@^60}U4;Nv$RM9+iE{RrJ#E$I7Tvp~BsStBZAoPwI_Tty?+rV zjRW8z@wT|+t0Q?gL&cUTCv`Ipezc0_(3fzt=^2Xmxa@J!m;RW0v}vX>_n#r5&C&!lCGC1X|^2#SX@CA#wsa(R;; z2}`f7W~fMzAEX2dMM9^YCb1aB8?f4BL!UO(;AR&3l6z^`6xG|3gQ3C&NPfC@7SExC zyKBjMo}uhQ9tno1OXrM9>Ta4tf_nN-tJ0p;6K;3VG_fZc5#{#Md4pWHLz$>Tc+SgH0)92>>oYM=3H``19hN-vC23J+HTNtZpGxB}ssz16H7Q^DH%O0?qx&qR7-Cm*bD@QV(QIn+9 zs}1qu;Pb{bM{+Y`#5vE?aX-pvxLT9&xhSnZ+)x@FUmlzjpG~6mtvWnIsW1AWM@g?i z*``Ul!;v(io_As$G&EY2=7<#}&!=QQd3oVSUsyKNDTK3BVQmuN?KG5HE8kk=9g84$ z^u|cuMGkAyZ6BOZFyxy7%nn283gyJWq2QoGW9f>FG)JP&l}|;yws9@;Yj+F6IT{%jC~Wz8z-U^_Tds^AbMR=i)LDv zC?UdBW2st38fl`#P@fDjk&cnPY9oy}l4{{=4mc)z`68)lGd-lFXyB|dy6$NUiTtU~ z!RN&qaVJ7~c1q~6H5=qL1y-jO@0H|-@@^_o)0wPd2heFnHZCPe0>xW^_$!{wIT^~! zd^6|cqP!r-P+V~f1|}rtqHLe%WkrAFp@WNd=-v@T1F-QryjJp~YMqT_ySCa|5{4sP ziQwHd)QBSyCM8|M(7G$NNe^9UV|d94SIbBmD)<%Ma|^VSg~tt1JLNl!mjo9YbDf&$ z13;adzQQM8yazciWpN~ex4}^31l$e1SDPsmnV0u?!TF{7Hiig7*=7~VN20Wae0=I- zpND&rLGp2wbolmm-l} z@(MC8>rXV0{<9WU5$__;7nzsz_)kAx*PU=_HdFj~@((sZJ0JO0Jax%7Ps?4?YuWTtc=mIZ>~|UZfRTniX#x2?;!cOk zU9$Q{lJ3L>$*%f@q!0NxR*sx*@-!}Acr}c|bu#@{j)VhY?s=+Udu>v7PdsMbkL)9p z-Sbld<$th~OqW-6j>24nI=)p0wFh!x00pc-!8yew!GkME{B8w{4-?SPFq*R>GI>eU zLC;w=Ro*I5n))hji~pg!_EK=>uYxi2)4Y_mCbL%k@ zx%PNLA(Z$wa0Nw*yX={URlbv zzL>cU^&{8jpju@`b#Asn!6fYz%y01L0>#(zfvhg|6p>=0$ujlz%d&z!y%QSg26n;L z2_CVT#qH{}zn~=X?z-t$9h#3HX{%Y|*pzMz5jpu!C&(S4Zyo)YoI2jgsM#d9VPZtS zK1XlQ)0HgGVDr6ZnZTZN&8Lhs!ca?+#Ox`W@eE0+rOiz{vVfYdPspfMX+tq2TkSpm zm8mYpEj#M7VvV8srB=6p)>u1v){7G(<=dGJV~=a-y*jZs*<(zr*udwcO|T->*Z^EM1yKO9>Hr#jyq)pl;4M{@0H(SEty)uucunrfoF~;z1xOGE!D<>r`zqRn7@y; zM95C!DsspzgWIQ!T70bqA@UB=d-a_Rln=G6lx2$a%sMuCntun3ypKjEdpwR2PkB|J zfm%HJ)CMJ{G$R~-ZGU(Ou8b6#^ae}^%HIn4q(9Oyf6cJ0#dl%Dg+y+d5!H5MgXkna z5v!XBv|bE){U*1`moi6fbya6)&N?~E3+(GcU+2cWWR0@kZCW6%{c}{0{?SX#`cJJs zQkV+s%V6WhFGHpk=hOFoz-!7Fi5ys9ta%{ZXZ$xCHDNIr*}~y00N`5!kwV^5t@V0` zd?Y;}E+Fm(d%CG>>}jNiuUC97uul5ihGPw^VN-6;T(e$!&wR@!iF)me+BXY6vWBB1F!xoom@qhEcM*}6noe7LAEz4Jrk{;HxbBg@LhO@Gn z{so`6{3jY7S+dN|*Ib-(Y2<}!;TJMEhAFiZ#LdTXLX!HnjkYB^Ktq9(dWUJG^ zvm3mkOJ=%~WfZr1h1bjSo-OsIi7%Tb8q;0;1ZNt4R-9lNrrIa|HW(DURi{lD%KOx% zyJEzf>y9t4sI`AqFwwrz#XWx0x0<**^kp5~{`-r4%GfZ|`)*Ubh2TCkpE#=04Axy7 z@>QMH@FAu!`PlYu(zpF2cDMYymhk@st_D*2n?XnZsU<|?oJsMqvxJ=5-!KYZ};HAA+FdCD9z4%t63 z+!DS3Ux0|x-kNl%+zFX2p4!&uK7VtN!9;1g;&n&nfeJrCX=A+nZ}um~&MW>_zm;%w zi;mkb21S8&psXa6shcL;c7 zzA9#Wy`sxf&M95nH`iC`^oe!Mx7J@B@tfoOCk*^lk;W3lR_6+a7_L@wD=He1F!C{$#nD+Ym2tVv6I@c8Z$&0udqQ0%Rae%0(_C>De`6*=cCI8)a-k`F0ll}wi_nmO-GnlIO za`qAY600)Czz`N2mmAhyP4wuS)#ZhB2TrH6jZQ@?+yvPIpo!%F6PuJ{vs}4#R=eKB zPpoyryr!>;9(s+7^Bzt}u8T!$-33;{Z(;|3llg%Dtg`|H^Nl!@qdHB%a0q5Lq zR`YFqWceuJw(Oy()<##8n)=j6vOXh?6h@N

    lRdR9+U%{Kp~+`cn~2z{N4gecRU)1ms+M2g)143`(-b>96(Ku#XE42B$jh;8WVc3pdBdfeZb*b{&CvRW8n)=4 z4@wGfs+QXZ8%*41-39B?c4@~xWM8#}&#S8&VKNOigF`l3b)vG{_nN>O;(k9VaxPX{ zLuvYDblrJ!mv5778g9s758hBeN8Y5Dn#nV*8ydKNxG=^=Ud!mM*3Fx}Z?H4FI`sAH zk%^WAvipp{xK&kn5pcf`<*DJ~-;oI~d9<f-GHI}FfqoxVZ+iEk@9+ni7ZBDtbUs2j{ zdGC7@Rcu~XvkIv*p^PnAg73hS3b zpYiCrM2e$n=bPH7Xf!|EzVQjV36T;O2Dpu@ye%QE-&c*m#TQ^v2SZx%;}k{S8wPBRo&Z3$9asxrCqFIl}B%2!DcbCVa&@HDGJacI3_Pq!SC{l;$g%-51G@9~f< zadOVXRqE_tPm1(>ogYlR7N(|p|Sc%Mh>(3$o%d`$+bF;G z*94H`bhwIU7e~KO*$#LzwZ`S-5Wbuqkn)8l$GO>F!{O?Pcjk&xv(AYqReXQ&i5x-A zh>^yTUHAqzb&F#R64bTNFSTg0uXpr4RPTxP=yDf)Bs|Zx%pNa8bQzoJUNZDU`&l|s zP<+{V;-xODa2xe|ih6vfd41`dQbY7L2M>h4Zu|S2mPn2E zh}Vl+@y(Ti#M;TD{>j;tST^0_Sg6bpLX!&HS3iq}AHP7<_(G8I%&NoXw#f&AtG_jYxpVg(^P*$@8 z%719=F}p@n9^h%dV^{Kw!@1Dph3(_MoJK|7m{dj0=<*7lV|_T$EAc61%f6M?2WdQ8L1+ z(4l~7^0t>6nik3h+6WX&Qi>IMY`@rjve`g3h!{Gyk)6!aTb}He@{yY9os*(Q-|1>m zTJz}rzrTml&qqqalQ$FheVDreWW(nr7cV9r`Wpz8ozx@A|r$OEnf<+Cpnj9aAuS9(LHTO&mt) zWnH+>z8Rr9w=p#NqsMBZNRtf*HuxB95?GN7dmCgi1B| zN2vsB!3&dw-ary=Eol(d{Mp zS#hgnovhciL+)w*wy+{VkWm{i{~21?>(TvTz97^b`DZdiUz=vj~S>S7n>ay~bibPj=x#*}_ z$8E9;Zd<|sUr5{wkNI7oHEG`3>owDUMe4kAc(OXhwU#cOnSJtIsh_A0=HXyT>Sa$6 zWo=L@E50nX*UL|8M^Kj3*TSkXdN%s1FC7ib=TQ>PjJ@*`w&K?hjF@^6zWFqe%onA_ zaI|yLA&Kh=7teaYEr-hs(nl7hQ-cLaM>cq^@S9HLDYHA=KP6XJtIz2R&)9hVUxjoY z&3un4)P~TX|ytrFaB3yI{xgGu_V2c)g2RT9kn`xq%*1M+21Sc~!TB%rf z_aXvG-8sGf-RJk(lj}Hq{fxAGAhR&JAu(EB#cGQ5CQ#PeqDntyi;Ck zD9+iVvZ^0lcy~&5tKZtU;AhXUl=Qu zt&(Xq#))bV4Tw?H?a8E!rZvN^umvqsLFc&!7E7gV$J6W|X`; zq#>WrF6xfzvnxr?EDbihREcLfSBxi~A@VB!?p zmo%=aOXdEKFnlLt1Jg6}BMBXE!;9TElKA|4jH+Y{svd#U35e};H09S23sA1ripQNn z;^@XXQt_Gs^mTitM4+cCawpj zo}N}IX?^L_zNW|-)wzd1M-vux4&1}}+-o(wfZ3q8=e`WLe~j4!E#Z1~XZL<^^-9gX zj{XA&YcDHaiW}?QK?_j`ZcdKqC_Xc^pZog3x*%li6fdOIslVs^NM=a6C=U@oFWPCK z`E-4CV$ZsI{G3EoYtQS@0)63vsZZrIEp}RUr3%L`Ts8~Ns3}Se#7~RtXX?cd;qbZH z^Ah?<|DKX~DdUF3PcHzf_aWY4DhqkD(4c>5LW29mj3B!SK?{N`vwY-+GOUBYnvPJ*+wHD`zo~_d!@|((ISGdrcL_dE4~0;@XI$|@ZOo}EIq2^hDS9?u-@3od(mTEcbu`J(b+>w(%;}E zxT?5Iiktg6`f9i^Tcyzb>krn1oQ0(|;eC8+>d$T_MvrxN2R+hTp}eA6pWfsC!fBG# zWcjN11W!M1nsCEif(1sbF7s2CvoI-CPPd3PC3-V;ib!U*<`6@dksH-xw{h^=z=D^G zj=p$e&ZX$TeY&)Vd>tFf^+omxQkH<>hfHNHS7-1MY=C$4k(c0tq8K4U-N4zhe1!)^ zr`W$h;cs=Y^+Z)mfAY03d_P~Hc=@0yf@hG4uTg4;GH~8@sW&t#($hz5{)^s-A$y(u z|FY4zdz*dK*4n`2rF-*>XLidwTQc8H`TAt<#kcVTKOP2N7lFF6x==>_>U$YG_?^wad5MnKPK5R=1(TdoIUM7f-P&x7Z z8M}aKC*JM`>$!F$X8}4oKF-1Q8;}mPFPeDPqUgG5eqsk)%$bSX{hQ`kbYwB+b|+L& zClYXGRMc?0B;&H-L`_TkXgdnk{8~sN^X~vgE55*(`2$mPtjRozm*s%=(6Y|^76 zUgy5tz92@99juC+{rA~O{_5r7!+F^uWb)>_Oy{IbDa(iW&7eI+heS7h%h74+F1&0Z zTyy{12;OseJK;4&vb=|#5?A}Ce(e!*8oEKbDs7lAKgZr+n)lrn?w>4WCk;9@Px|Xv z#K949TwLVEY?tU|X-bV^Vq5BQ6{_u5PRh%Dq(IrFotGV{(T3D0HE25h;!Nw+ju<=S zhLbmo)w6q)=~fTCZ%stK zk#+wa9%H9TX$N;{4u$`#b&>@;Ji5jf+wNw6l_rSG9O zQmWHU>Yn+B>Lt<$-mZRcEy?cG;QDe!6FVj9jSoU6YX)l7P&KkiV?~)&`4A!y>Hb3{ z8v06`IM=><=2A-Jn-KJelxQ`|16e#twRR_SA8$7it4hCF@1y4WaimLqiDCnOZQyW@ z_^7vY7x9Q?P8CJHAK*UCT{g`F^&+YLJou0eWk!;eLt+j6QO9rM zHP%WSH|sDUF(8$*^04pQW_J@dO|Dm-xAe!4Jf;~oHRLzDN3LrM!?h%D<(H<^?$u7% zfY61+q~wcSn{@Q6%7cT0yvd;}eXDUxP%YXT^NE7k)Lc{SkZX~|q(IT}e#&B4)cnFA z>xmO2X7}kX-D@xG<91YNoZx?6Ne%ExnQ5&UF^iL7Y6U_~%ZwU{LMyA?E(xJ#nGxTi zaf{>Z0mbkmaoT-7c(cua#W1xdNQZgyb#Tp;ef~e;CTjLa+icX1JR4;~%4VKFY8=U% znk2s@@;eGrC&hNY&H;jLW3yM(D9&1xR^m&`%7QBu?IhyN935Z|!6Z(_*l-43{)9z$ z4aB6v>NT%EQtKedX58W|%jJ?_(v zJeE}bMJsRbkCA&aH}&=u;}`096+Y$;FSnqbwp*hYUT#yDwte@YIPF@VIMgj>Cbd|7 z;!9|CvtRG&{a^bFhlsT4v4c=gJvi)?cCtg<4USWcY!Ra+KIx^`YLhM)UCtcp z_t9yKfKwSP{eMF0)AwHDW(hYZ^tIDqFk_8&sCygcuWSw1X?tz~$ooizp`R2{2H1NQ z3WNWkXB<_umbA@w%G=nUYhjXsFkhXvXH%R?x(A{7C+KOSmH2Yq^dvEK;WC}rDd_Kt zJ;^yu@FNm2nf=r>BCUJ;KI@DcQo_GE8%6(ypj2Qokml&F+fg2Ad=fDVmAWpZ!Ax-vpBoL)l)lb2=$IP~3jQAMsnh_+?)6_=Xt! zbbsD>GU^H2jYv66m(3snE#>-iP1tZHoM>>M<40ZEaZM|HSJZ71B(o8`R|vQyo=(2? zg(ST863EUrtVWzk@eGhB63;?n6VwNVJ5O)2;mAWmEG6({v1uW@QE{_omM)n!KqEb_ zgDq@@Px<{{pJH)$h4+fQ8sqH0r|^?c=TPF{%NG-4ANc3!;N@$h?KeLwdR4*}Wjtch zY#~Z3&Pe_!AiWPLTHPcJBB%Nt)}|6^)U{a3$5@U9T_KXQ>jXS+-W zg!v^-DSX!(xNOqav>yC6#MC zUA6-GJe&jyBQZ@sWvMr5iCXvF=9MiGbkZLXQH+s3XPT4F{XY&RFPBN2fhmoQG{Cp89IXFu2hz}wycMt3n(p3aPW zzl_CcL5;OSi`0zs*A0`t5Pn26=EdcZDD;26&S7XD#9Xw+KjD2dlc~qzwiVRDEnL3o zFGo?Kty88fz&JH~;B-@*;F99bp@H4`51)j5{jiy~!ABiI)stNpbHwgmZ_W>q(+h+> z_^`W~tL;#hxT{Z1t5I31f3Vouvwj=)>uj*|(sFz9PkQNt^s?8Utl0dfCx5!h6>%#` zs>kR~aoTPKooO#7qvYl$H-+(VVTR_bKsc7tD& zE4Ern-gS}RYKc_seVDLY*8X}k=;_=^!Vq$LUsD$CJ0rymU4@v9eg<3c=u4l|Sg2S? zP66axE#bNj7m(ciz=py=_c$|Lo#buz7`i1htpJx0ukGEmO`tS~7pl(O|7#Ay>6M3j zJ$uB7pW_tI`!P~u;MH@swrYz`)ON$GHMk(KCub(|MVcoxymD{U1 z5H1`t=?&wrFEcXjk~1O2GepXnzr;x!smr z09!x~z8)MXAEGa~u+XVX_4U@++q+rMoQZEoa0|MUKK96?z8sC5aoHPp#oMP!!?H@4hLD;BrnYTi6?q z>h0e55)xyNvT%d8F3vvn5oqH1>%@+DM4Lqn4~SFHO3Bxjce^;o6s>KaX@t=VEe+Wt zE{<_UvwMqrP1yGEVaG?gDS~}P29I{B%?@@2YirAQ!*I=)H2u}W>b=Pe`UtkPFHY#I zA@VxXinuiL_~2oNULNh4pZ7xV6r&mDsmvi`r0b%KV|-Dy zw*0d9K}Y%ceotSu_69yXyYJ3u$fIgq`CX&e&8J^=Z4#%3_S$xgX4bSuoiqiK>d1-; z8t~)2jvZ4OitE}9<2h`Xo_6f5mf)2M*JsaJ8IRTKPh4k1es9Dn71y~~7x?|59oyt_ zQcr#|L(%0D)i`&to>KC?|Ya?<D9(moLQAU0pPp`7nvvMKuy7_bRXqFt*hT%TdyB^P=3!Ebj0n*qsGm-fupwhYZK?XTr(J*rb^ zPTwgAw(aQ7ES?R8UGcwahNivcGTj|&S8h}X`|lstn=~KdTJrnIuNUJ7j_uw6w0OY5 z>HWLM?8(sNgx6(())V&%8U%kt@C?m|hnv8E?#=&G$F&AEaYbRKYN-PxwAJzmBtM)! z97~CW7@>wtT^;I-$c|c6kddfBF~tCeq9L$EN-|a{Q<+Y+D$d%eT^^FQRvjX+X;GY3 zV~Q?KEJA`P+NF|UScrjSdp1AXU;f(NnLYRM-E+Qs?&BPjEs7B!0U07cNDO5Kl9Qnw z6Ov=(WI829dP*IQ07)Die+KoFYm>^n=-C81)1ZBX&c>b(%9g@#HRjc1&-s+k)e@fr z&F<=3$3}m>GeTER@FN+L&sdu;tbign?(;p9)|07}iFfmAQJGiV8(nbK?lPLk)~fV2 zKI1m{Rft?y#?g9RI?Mof@D>G?w@q~jd!*-3tlN*3ybZtzrPSP8!i5=f$`;A^@yQ9!Xu}Tt2%e7v4}Oo=s?Vuj zhBfy4opb8Rtx2Bii-YHTQz@gt{}`#6L#u@6gK7at+};h)2a!Mw61cO_9+{C!*`52X z*p@BSOR`9&1rPSqCU>apqvd}AdGQ%}9yr2xQA|xR-92T*5Ra+4d@%C?@WFl5nMMT+ zW-Aqf(6WJRwR->G-~1xtGnJ}VurXc4B}-PHukJIfD|hpI<)O~yOQ=$V`4a-nB1Q&! z4wq7Yk}c`r&0_+(KPquL0_mxW72Wd0a#LEEBOI1Z2meH!aw>BbO0!d_Q*%!Jvr+p5 zC3|q#IuajqS9jmyT;;HtL9{BCZX1-$j9k=?kC@x^nC_qA5Xim$)}Wa;{iRZ88uJ>= zM?-od&aDyElK4m}Wi!K4EqPVEpcMU0z_UwICtCyMM>laIXtOjHve;|;s=D= z7m1_ekibPeV>K0%?Lqvcgc`W4$9V?-ioV}kj{8my)-MUdO$2i4a4S0s+GRN&SviLb z(S)B9XxTCr42T|#Q;9Fx@d5LKj5?MAa5!WG#@uG_^j zY7rv;m|%A^{T5qCuZ<1hy)zqGQ9Qi~sbNd9-_@}wh7oYiGeBWmxPA!zN5#Ey~)bUqRo#5-3{w@1QnbvxjojpIP|nu*f7kEEWj+BubhiCt-Fcsz%} zJH*X8XMujhuK3smXrKT`_Pema-!cxR3k|eP-Nu0WMWlFj< zHC-%OAr_~L#j5Qea`f=OK&g6fNztJf3&bz-w1dDq|J9%=DJ?vpQI?jySSBlaKm#&i N8`f`H*SWUf@W1;ZeOCYg literal 0 HcmV?d00001 diff --git a/images/kitchen.png b/src/img/kitchen.png similarity index 100% rename from images/kitchen.png rename to src/img/kitchen.png diff --git a/src/img/left.png b/src/img/left.png new file mode 100644 index 0000000000000000000000000000000000000000..e1b0873e32a248a15e5ce29f83b67b909fffc346 GIT binary patch literal 22357 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�ETw!)6eQ?O;dKK5mNM20q18t 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

      (t*RGG0=?>M_!j+wPJ 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 literal 0 HcmV?d00001 diff --git a/images/table.png b/src/img/table.png similarity index 100% rename from images/table.png rename to src/img/table.png diff --git a/images/wait.png b/src/img/wait.png similarity index 100% rename from images/wait.png rename to src/img/wait.png diff --git a/images/waiter.png b/src/img/waiter.png similarity index 100% rename from images/waiter.png rename to src/img/waiter.png diff --git a/src/obj/Block.py b/src/obj/Block.py new file mode 100644 index 0000000..51df401 --- /dev/null +++ b/src/obj/Block.py @@ -0,0 +1,9 @@ +from src.obj.Object import Object + + +class Block(Object): + def __init__(self, position, orientation, square_size, square_count): + super().__init__("block", position, orientation, square_size, square_count) + + def collide_test(self, waiter: Object) -> bool: + return waiter.position == self.position diff --git a/src/obj/Kitchen.py b/src/obj/Kitchen.py new file mode 100644 index 0000000..a8063ad --- /dev/null +++ b/src/obj/Kitchen.py @@ -0,0 +1,20 @@ +from src.obj.Object import Object + + +class Kitchen(Object): + def __init__(self, position, orientation, square_size, square_count): + super().__init__("kitchen", position, orientation, square_size, square_count) + + def goal_test(self, waiter) -> bool: + conditions = [ + waiter.orders_in_basket(), + self.position == waiter.position + ] + + if all(conditions): + for table in waiter.basket: + if table.agent_role == "wait": + table.next_role(waiter) + return True + + return False diff --git a/src/obj/Object.py b/src/obj/Object.py new file mode 100644 index 0000000..958f70f --- /dev/null +++ b/src/obj/Object.py @@ -0,0 +1,47 @@ +import pygame + + +class Object: + def __init__(self, agent_role, position, orientation, square_size, square_count): + self.agent_role = agent_role + self.position = position + self.orientation = orientation % 4 + self.square_size = square_size + self.square_count = square_count + + self.image = pygame.image.load( + 'src/img/{0}.png'.format(self.agent_role)) + self.image = pygame.transform.scale( + self.image, (self.square_size, self.square_size)) + + self.rect = pygame.Rect(position[0] * square_size, + position[1] * square_size, + square_size, square_size) + + def change_role(self, new_role): + self.agent_role = new_role + self.image = pygame.image.load('src/img/{0}.png'.format(new_role)) + self.image = pygame.transform.scale( + self.image, (self.square_size, self.square_size)) + + def get_angle(self): + ''' + orientation = 0 -> up\n + orientation = 1 -> left\n + orientation = 2 -> down\n + orientation = 3 -> right\n + ''' + + return self.orientation * 90 + + def collide_test(self, obj) -> bool: + return False + + def goal_test(self, waiter) -> bool: + return False + + def blit(self, screen: pygame.Surface): + image = pygame.transform.rotate(self.image, self.get_angle()) + self.rect.x = self.position[0] * self.square_size + self.rect.y = self.position[1] * self.square_size + screen.blit(image, self.rect) diff --git a/src/obj/Table.py b/src/obj/Table.py new file mode 100644 index 0000000..6d21f19 --- /dev/null +++ b/src/obj/Table.py @@ -0,0 +1,24 @@ +from src.obj.Object import Object + + +class Table(Object): + def __init__(self, position, orientation, square_size, square_count, current_role=1): + super().__init__("table", position, orientation, square_size, square_count) + self.roles = ["table", "order", "wait", "done"] + self.current_role = current_role + self.change_role(self.roles[self.current_role]) + + def next_role(self, waiter): + if waiter.agent_role == "waiter": + self.current_role = (self.current_role + 1) % 4 + self.change_role(self.roles[self.current_role]) + + def goal_test(self, waiter) -> bool: + if self.position == waiter.position: + + if self.agent_role == "order": + return waiter.take_order(self) + elif self.agent_role == "done": + return waiter.drop_order(self) + + return False diff --git a/src/obj/TemporaryState.py b/src/obj/TemporaryState.py new file mode 100644 index 0000000..0dc666b --- /dev/null +++ b/src/obj/TemporaryState.py @@ -0,0 +1,51 @@ +from src.obj.Waiter import Waiter +import copy + + +class TemporaryState(Waiter): + def __init__(self, parent, action="blank"): + super().__init__(copy.deepcopy(parent.position), + copy.copy(parent.orientation), + copy.copy(parent.square_size), + copy.copy(parent.square_count), + copy.copy(parent.basket)) + self.parent = parent + self.change_role(action) + self.apply_transformation() + + def apply_transformation(self): + if self.agent_role == "left": + self.orientation = (self.orientation + 1) % 4 + elif self.agent_role == "right": + self.orientation = (self.orientation - 1) % 4 + elif self.agent_role == "front": + if self.orientation % 2: # x (1 or 3) + self.position[0] += self.orientation - 2 # x (-1 or +1) + else: # y (0 or 2) + self.position[1] += self.orientation - 1 # y (-1 or +1) + + def left(self): + return TemporaryState(self, "left") + + def right(self): + return TemporaryState(self, "right") + + def front(self): + return TemporaryState(self, "front") + + def collide_test(self) -> bool: + out_of_range = [ + self.position[0] >= self.square_count, + self.position[1] >= self.square_count, + self.position[0] < 0, + self.position[1] < 0 + ] + + return any(out_of_range) + + def compare(self, state) -> bool: + conditions = [ + self.position == state.position, + self.orientation == state.orientation + ] + return all(conditions) diff --git a/src/obj/Waiter.py b/src/obj/Waiter.py new file mode 100644 index 0000000..c266f76 --- /dev/null +++ b/src/obj/Waiter.py @@ -0,0 +1,62 @@ +import copy +from src.obj.Object import Object + + +class Waiter(Object): + def __init__(self, position, orientation, square_size, square_count, basket=[]): + super().__init__("waiter", position, orientation, square_size, square_count) + self.basket_size = 2 + self.basket = basket + self.prev_position = copy.deepcopy(self.position) + self.prev_orientation = copy.copy(self.orientation) + + def dampState(self): + self.prev_position = copy.deepcopy(self.position) + self.prev_orientation = copy.copy(self.orientation) + + def rollbackState(self): + self.position = copy.deepcopy(self.prev_position) + self.orientation = copy.copy(self.prev_orientation) + + def take_order(self, table) -> bool: + if table.agent_role == "order": + if len(self.basket) < self.basket_size: + table.next_role(self) + self.basket.append(table) + return True + return False + + def drop_order(self, table) -> bool: + if table.agent_role == "done": + self.basket.remove(table) + table.next_role(self) + return True + return False + + def orders_in_basket(self) -> bool: + return self.basket + + def left(self): + self.orientation = (self.orientation + 1) % 4 + + def right(self): + self.orientation = (self.orientation - 1) % 4 + + def front(self): + if self.orientation % 2: # x (1 or 3) + self.position[0] += self.orientation - 2 # x (-1 or +1) + else: # y (0 or 2) + self.position[1] += self.orientation - 1 # y (-1 or +1) + + def collide_test(self, obj) -> bool: + out_of_range = [ + self.position[0] >= self.square_count, + self.position[1] >= self.square_count, + self.position[0] < 0, + self.position[1] < 0 + ] + + return any(out_of_range) + + def goal_test(self, engine): + return any([o.goal_test(self) for o in engine.objects])