From 8b396251374576f0471234b7734866d4bbd2695a Mon Sep 17 00:00:00 2001 From: s444417 Date: Mon, 20 Apr 2020 23:19:13 +0200 Subject: [PATCH] =?UTF-8?q?Automatyczne=20poruszanie,=20porz=C4=85dki,=20c?= =?UTF-8?q?ache=20do=20dodawania=20obrazk=C3=B3w.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 112 ---------------- .idea/ProjektAI.iml | 2 +- .idea/misc.xml | 1 + kelner/images/kelner.png | Bin 1876 -> 1657 bytes kelner/images/plate.png | Bin 706 -> 657 bytes kelner/images/wiking_blond.png | Bin 988 -> 832 bytes kelner/images/wiking_rudy.png | Bin 979 -> 833 bytes kelner/images/wiking_rudy2.png | Bin 977 -> 832 bytes kelner/main.py | 76 +++++------ kelner/src/algorithms/AStar/Finder.py | 125 ++++++++++++++++++ kelner/src/algorithms/AStar/FinderTest.py | 60 +++++++++ kelner/src/algorithms/AStar/Node.py | 34 +++++ kelner/src/components/Drawable.py | 24 +++- kelner/src/components/GridBoard.py | 22 ++-- kelner/src/components/Table.py | 154 +++++++++++----------- kelner/src/components/Waiter.py | 32 +++-- kelner/src/managers/DrawableCollection.py | 73 ++++++---- kelner/src/managers/ImageCache.py | 50 +++++++ kelner/src/managers/MenuManager.py | 10 +- kelner/src/managers/TableManager.py | 29 ++++ kelner/src/managers/WaiterManager.py | 57 ++++++++ 21 files changed, 578 insertions(+), 283 deletions(-) delete mode 100644 .gitignore create mode 100644 kelner/src/algorithms/AStar/Finder.py create mode 100644 kelner/src/algorithms/AStar/FinderTest.py create mode 100644 kelner/src/algorithms/AStar/Node.py create mode 100644 kelner/src/managers/ImageCache.py create mode 100644 kelner/src/managers/TableManager.py create mode 100644 kelner/src/managers/WaiterManager.py diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 73ffb59..0000000 --- a/.gitignore +++ /dev/null @@ -1,112 +0,0 @@ - -# Created by https://www.gitignore.io/api/python -# Edit at https://www.gitignore.io/?templates=python - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg - -/idea/workspace.xml -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# End of https://www.gitignore.io/api/python \ No newline at end of file diff --git a/.idea/ProjektAI.iml b/.idea/ProjektAI.iml index 9c88284..341f107 100644 --- a/.idea/ProjektAI.iml +++ b/.idea/ProjektAI.iml @@ -2,7 +2,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index ef004d1..8e241c5 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,4 +3,5 @@ + \ No newline at end of file diff --git a/kelner/images/kelner.png b/kelner/images/kelner.png index 6e0d499869b10ed863beace755b9818c283c23a4..c4bbba763a26b42193e129fe4c3b7f91969de227 100644 GIT binary patch delta 1655 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 literal 706 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT1|$ph9<=}|&H|6fVg`m7phS!tqsSCzM+OF_ z5>FS$kcv5PubD@({qcxV6FFc*AJ>S4B=tBL_RX= z?8ZMnyeADn8WG2CIjxZf98YW^}X&-cRR%g*ufG7VW<-2_N4wKOprs}8M$GA_MN5J-4;d`6zu5oS;>W)8*RF|m zx-5zm?{(RboNgkqrpn@Hjob?V?dI!agd5tmxu-nbHF%v3mj-BYZ zIeopLUPpywWK50P=FOXP4@V_W_+5Ld)X_;_nfr795!RjN#m8?fNPp6KvZ3^3S!(5T z-d3lNH}3!ckuEsrUDfQ#lf|vBJziPlI8X1+|JA$SHBI3&JHmQXcip_Z#g{$#TGz6l kI#+@m>##)db^mY96*GBQ3}O!&0uv>Jr>mdKI;Vst07bAp9RL6T diff --git a/kelner/images/wiking_blond.png b/kelner/images/wiking_blond.png index ebc4b63c6b9166d7cc2630f88055963907b05b54..9d8499702661288c2cdb2aa69da3bf0b1e4004d1 100644 GIT binary patch delta 823 zcmV-71IYZ`2fzk1iBL{Q4GJ0x0000DNk~Le0000J0000J2m$~A0R1wdn*aa+26R$R zQvd(}0001PrU#LcAs2rF;7LS5R5*=wQ(J5dQ5gPacDJ+LOWUn&x}sE3Dl#FK-~~m+zeK{QrM|(O>}<<6t8HNLcMXD+Erl|M@vzi}Zi3b$l`lh@sP=&Px;B z8ToKI^6F?lO6LRZzAHkyw3z1e+6or{266t6^T_4xS<{?9RaUezYeE9r-<=4QY_*u_ z;gnKYVNWEbXpCQFdqRlecBBTKPK;qnvL?w609~e~b>+o`=!s#eub)dxnP@b6*X&(D zUW%!ds;Z;Z`hkBfE1Chk$#|`ddD_78NxsEC-=|=AcpWxvt7sMk;nCo9UDsO=wD|!5 z)R;0H?0CLmQWGeVh-O9RWyNeZDO_9v$vmcRJ=nR`|1Wtg6Tt1ZT1_JwA%=mT-hQ1J znhMWkSMyOJt1b&uA#L|MM^&jB=qvrLxIc$U&73uM*Mfh6AsfZa`uH$7+k+w*lnkzr z$pX99*a7?`(Swo*GHDZSD=GpEiNDk=p=GFl)4C5Ei zUv0E5nLn-L#W^-NLl*kCAPfz~&mX@B-0|G^1L%8fVLNm0*jIbsA6NMgtt%7jTT>|| z()%N)Hpxp2!?@k!MfF#q3Y&A)LvP-q@-bJqX>002ovPDHLkV1k&J Bep3Jd literal 988 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 Bf$snS literal 977 zcmV;?11|iDP)z>)gGod|RCt{2*iC30WgN%x?{0UKO}cs8Y)xZZLvpH31~m~9FXBs3 zFG@jrk$_Sqq$LOyszQTcZ78W0g`y(lW_`npr>H#ygGz1fp(Ji%)Go1IJK5c=*-d6M zJG(RUcnC%)fr5u8V*Vf4!#un2|ILqKcIE*ggb+dqA%qY@2qA5P)z_8%+v)97jsa?QepJn0eCM`TO!CS(mHhtIEh#6cbC>~Y z;_ACBuQgB;%x$b~_5r9SORiYQE9ag?cR3-Q!vIQ-OJgLD4NP2qjYRzb;ZTqj%b{i0 zPVxmCb1_GM?N@l7A|AE4Sy!h!rv75=l8ar60x-R!kNvS4JkKY;V)Og;3~P27(=_=c z)Wf~rx2#$gl}bf-Oai(G8lXO!I?E5`9%79(JpIc6E9oL{HJ%|52ry#3Ooa$1!zZvT ziwC3AoEjQuMsrr}#lU(w!xz3`Fn=7}0=^ZZWG!L4A;OeM=Za8q_^|6dUmPCLUJ7hs zF#unVbm6)#uIr+Jz#29k1qjik75i^FFX+?lPy9^J1y;T@`VEZ{g2?f zE{Vh(RaI5|`t>9L3k#6Q>n}&^&DQ|+{9`+DU7tHTJ6W9hiDym>(>(Jw6?>AxQi@o> zCeVAFw}#i;Ms{wN(ZPK*XFh{qkZ@HMjZIC&Vll$s zjRCNuwS#CBJYRRpEhxtG6@^uY;O=$;^%2M};*~vaBz?@A^^}XdXz$p=k)9irt|zH! zYiDnFRCi2$#TcN@j=#jiM~@MH@+6DhN16u1Q&W?!sCwP9rEu!j z_1hh9n++==gb+dqA%qY@2qA) for PriorityQueue comparison (determines the objects order) + def __gt__(self, other): + return self.estimated > other.estimated diff --git a/kelner/src/components/Drawable.py b/kelner/src/components/Drawable.py index 6af5eb9..6fd347b 100644 --- a/kelner/src/components/Drawable.py +++ b/kelner/src/components/Drawable.py @@ -5,29 +5,33 @@ class Drawable: RED = (255, 0, 0) GREEN = (0, 255, 0) - def __init__(self, x, y, minX, maxX, minY, maxY, ratio): + def __init__(self, x, y, minX, maxX, minY, maxY, cellSize, offset): self.__minX = minX self.__maxX = maxX self.__minY = minY self.__maxY = maxY self.setX(x) self.setY(y) - self.__ratio = ratio #cell size + self.__cellSize = cellSize # cell size in pixels + self.__offset = offset # paint offset in pixels def setX(self, x): - if (x < self.__minX or self.__maxX < x): + if x < self.__minX or self.__maxX < x: return False else: self.__x = x return True def setY(self, y): - if (y < self.__minY or self.__maxY < y): + if y < self.__minY or self.__maxY < y: return False else: self.__y = y return True + def isPositionCorrect(self, x, y): + return self.__minX <= x <= self.__maxX and self.__minY <= y <= self.__maxY + def getX(self): return self.__x @@ -46,8 +50,14 @@ class Drawable: def getMaxY(self): return self.__maxY - def getRatio(self): - return self.__ratio + def getCellSize(self): + return self.__cellSize + + def getOffset(self): + return self.__offset def draw(self, screen): - pass \ No newline at end of file + pass + + def drawAux(self, screen): + pass diff --git a/kelner/src/components/GridBoard.py b/kelner/src/components/GridBoard.py index 8f848fc..334aa9c 100644 --- a/kelner/src/components/GridBoard.py +++ b/kelner/src/components/GridBoard.py @@ -1,28 +1,32 @@ import pygame +from kelner.src.managers.ImageCache import ImageCache, Images + class GridBoard: - def __init__(self, width, height, cellSize): - pygame.init() #initialize the pygame - pygame.display.set_caption("Bardzo mądry kelner") #window caption + def __init__(self, width, height): + pygame.init() # initialize the pygame + pygame.display.set_caption("Bardzo mądry kelner") # window caption self.__width = width self.__height = height - self.__cellSize = cellSize self.__screen = pygame.display.set_mode((width, height)) # initialize screen - self.Offset = 50 - #fills the screen with white and draws grid + # draws the background def reinitialize(self): + imageBackground = ImageCache.getInstance().getImage(Images.Background, self.__width, self.__height) + self.__screen.blit(imageBackground, (0, 0)) + """ # code below fills the screen with white and draws grid self.__screen.fill((255, 255, 255)) for x in range(0, self.__width, self.__cellSize): pygame.draw.line(self.__screen, (0,0,0), (x,0), (x,(self.__height - 1))) for y in range(0, self.__height, self.__cellSize): pygame.draw.line(self.__screen, (0,0,0), (0,y), ((self.__width - 1),y)) + """ - #draws object on screen + # draws object on screen def draw(self, component): component.draw(self.__screen) - #updates screen + # updates screen def udpdate(self): - pygame.display.update() \ No newline at end of file + pygame.display.update() diff --git a/kelner/src/components/Table.py b/kelner/src/components/Table.py index 0b6de38..da5d328 100644 --- a/kelner/src/components/Table.py +++ b/kelner/src/components/Table.py @@ -1,79 +1,33 @@ -import pygame -from enum import Enum -from .Drawable import Drawable import random +from enum import Enum +from kelner.src.components.Drawable import Drawable +from kelner.src.managers.ImageCache import ImageCache, Images + + +# status of the table +class Status(Enum): + NotReady = 0 + Ready = 1 + Waiting = 2 + Served = 3 + class Table(Drawable): - def __init__(self, minX, maxX, minY, maxY, ratio): - #call base class constructor - Drawable.__init__(self, 0, 0, minX, maxX, minY, maxY, ratio) - self.__order = [] + def __init__(self, minX, maxX, minY, maxY, ratio, offset): + # call base class constructor + super().__init__(0, 0, minX, maxX, minY, maxY, ratio, offset) self.__status = Status.NotReady - self.ilosc_klientow = random.randint(1,3) - self.guest1 = self.getGuest() - self.guest2 = self.getGuest() - self.guest3 = self.getGuest() - self.ksiazka = self.__loadImg('./images/ksiazka.png') - self.stol = self.__loadImg('./images/stol.png') - self.check = self.__loadImg('./images/check.png') - self.plate = self.__loadImg('./images/plate.png') - self.Offset = 100 - - #sets table color based on it's status - def getColor(self): - color = None - if self.__status == Status.NotReady: - color = self.__loadImg('./images/stol.png') - elif self.__status == Status.Ready: - color = self.__loadImg('./images/kelner.png') - elif self.__status == Status.Waiting: - color = self.__loadImg('./images/kelner.png') - elif self.__status == Status.Served: - color = self.__loadImg('./images/kelner.png') - return color - - def getGuest(self): - guest = None - i = random.randint(1,3) - if i == 1: - guest = self.__loadImg('./images/wiking_blond.png') - elif i == 2: - guest = self.__loadImg('./images/wiking_rudy.png') - elif i == 3: - guest = self.__loadImg('./images/wiking_rudy2.png') - return guest - - def __loadImg(self, filePath): - return pygame.transform.scale((pygame.image.load(filePath)),(140,140)) - - def draw(self, screen): - screen.blit(self.stol, (self.getX() * 100-20+self.Offset, self.getY() * 100-20+self.Offset)) - if self.ilosc_klientow == 1: - screen.blit(self.guest1, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 60+self.Offset)) - elif self.ilosc_klientow == 2: - screen.blit(self.guest1, (self.getX() * 100 - 62+self.Offset, self.getY() * 100 - 60+self.Offset)) - screen.blit(self.guest2, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 60+self.Offset)) - elif self.ilosc_klientow == 3: - screen.blit(self.guest1, (self.getX() * 100 - 62+self.Offset, self.getY() * 100 - 60+self.Offset)) - screen.blit(self.guest2, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 60+self.Offset)) - screen.blit(self.guest3, (self.getX() * 100 + 22+self.Offset, self.getY() * 100 - 60+self.Offset)) - - if self.__status == Status.NotReady: - screen.blit(self.ksiazka, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 20+self.Offset)) - elif self.__status == Status.Ready: - screen.blit(self.check, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 20+self.Offset)) - elif self.__status == Status.Waiting: - if self.ilosc_klientow == 1: - screen.blit(self.plate, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 20+self.Offset)) - elif self.ilosc_klientow == 2: - screen.blit(self.plate, (self.getX() * 100 - 62+self.Offset, self.getY() * 100 - 20+self.Offset)) - screen.blit(self.plate, (self.getX() * 100 - 20+self.Offset, self.getY() * 100 - 20+self.Offset)) - elif self.ilosc_klientow == 3: - screen.blit(self.plate, (self.getX() * 100 - 62+self.Offset, self.getY() * 100 - 20+self.Offset)) - screen.blit(self.plate, (self.getX() * 100- 20+self.Offset, self.getY() * 100 - 20+self.Offset)) - screen.blit(self.plate, (self.getX() * 100+ 22+self.Offset, self.getY() * 100 - 20+self.Offset)) + self.__order = [] + self.__guests = self.__getRandomGuests() + def __getRandomGuests(self): + possibleGuests = [Images.Guest1, Images.Guest2, Images.Guest3] + guests = [] + guestCount = random.randint(1, len(possibleGuests)) + for _ in range(guestCount): + guests.insert(0, possibleGuests[random.randint(0, len(possibleGuests) - 1)]) + return guests def setOrder(self, order): self.__order = order @@ -90,9 +44,57 @@ class Table(Drawable): def setStatus(self, status): self.__status = status -#status of the table -class Status(Enum): - NotReady = 0 - Ready = 1 - Waiting = 2 - Served = 3 \ No newline at end of file + def __getImage(self, imageKind): + if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]: + size = int(self.getCellSize() / 3) + else: + size = int(1.4 * self.getCellSize()) + return ImageCache.getInstance().getImage(imageKind, size, size) + + # draws only table + def draw(self, screen): + xBase = self.getX() * self.getCellSize() + self.getOffset() + yBase = self.getY() * self.getCellSize() + self.getOffset() + tableXYOffset = int(0.2 * self.getCellSize()) + screen.blit(self.__getImage(Images.Table), (xBase - tableXYOffset, yBase - tableXYOffset)) + + # draws images related to the status of a table + # the method is called in the second turn when all tables are already painted + def drawAux(self, screen): + xBase = self.getX() * self.getCellSize() + self.getOffset() + yBase = self.getY() * self.getCellSize() + self.getOffset() + + guest1XOffset = 0 + guest2XOffset = int((1 / 3) * self.getCellSize()) + guest3XOffset = int((2 / 3) * self.getCellSize()) + guest4XOffset = int((1 / 9) * self.getCellSize()) + guest5XOffset = int((5 / 9) * self.getCellSize()) + guestsYOffset = int(0.1 * self.getCellSize()) + tableXYOffset = int(0.2 * self.getCellSize()) + + if len(self.__guests) == 1: + screen.blit(self.__getImage(self.__guests[0]), (xBase + guest2XOffset, yBase - guestsYOffset)) + elif len(self.__guests) == 2: + screen.blit(self.__getImage(self.__guests[0]), (xBase + guest4XOffset, yBase - guestsYOffset)) + screen.blit(self.__getImage(self.__guests[1]), (xBase + guest5XOffset, yBase - guestsYOffset)) + elif len(self.__guests) == 3: + screen.blit(self.__getImage(self.__guests[0]), (xBase + guest1XOffset, yBase - guestsYOffset)) + screen.blit(self.__getImage(self.__guests[1]), (xBase + guest2XOffset, yBase - guestsYOffset)) + screen.blit(self.__getImage(self.__guests[2]), (xBase + guest3XOffset, yBase - guestsYOffset)) + + if self.isStatus(Status.NotReady): + screen.blit(self.__getImage(Images.Menu), (xBase - tableXYOffset, yBase - tableXYOffset)) + elif self.isStatus(Status.Ready): + screen.blit(self.__getImage(Images.Check), (xBase - tableXYOffset, yBase - tableXYOffset)) + elif self.isStatus(Status.Waiting): + platesYOffset = int(0.3 * self.getCellSize()) + imagePlate = self.__getImage(Images.Plate) + if len(self.__guests) == 1: + screen.blit(imagePlate, (xBase + guest2XOffset, yBase + platesYOffset)) + elif len(self.__guests) == 2: + screen.blit(imagePlate, (xBase + guest4XOffset, yBase + platesYOffset)) + screen.blit(imagePlate, (xBase + guest5XOffset, yBase + platesYOffset)) + elif len(self.__guests) == 3: + screen.blit(imagePlate, (xBase + guest1XOffset, yBase + platesYOffset)) + screen.blit(imagePlate, (xBase + guest2XOffset, yBase + platesYOffset)) + screen.blit(imagePlate, (xBase + guest3XOffset, yBase + platesYOffset)) diff --git a/kelner/src/components/Waiter.py b/kelner/src/components/Waiter.py index 9b64ed0..1f57b71 100644 --- a/kelner/src/components/Waiter.py +++ b/kelner/src/components/Waiter.py @@ -1,15 +1,14 @@ -import pygame -from .Drawable import Drawable +from kelner.src.components.Drawable import Drawable +from kelner.src.managers.ImageCache import ImageCache, Images + class Waiter(Drawable): - def __init__(self, x, y, minX, maxX, minY, maxY, ratio): - #call base class constructor - Drawable.__init__(self, x, y, minX, maxX, minY, maxY, ratio) - self.__image = self.__loadImg('./images/kelner.png') + def __init__(self, x, y, minX, maxX, minY, maxY, ratio, offset): + # call base class constructor + super().__init__(x, y, minX, maxX, minY, maxY, ratio, offset) self.__acceptedOrders = [] - self.Offset = 100 - + self.__currentPath = [] def moveUp(self): if self.getY() > self.getMinY(): @@ -39,12 +38,21 @@ class Waiter(Drawable): else: return False - #accepts orders from the table and stores them in queue + # accepts orders from the table and stores them in queue def addOrder(self, table): self.__acceptedOrders += [(table, table.getOrder())] - def __loadImg(self, filePath): - return pygame.transform.scale((pygame.image.load(filePath)),(140,140)) + def isPathEmpty(self): + return self.__currentPath == [] + + def setPath(self, path): + self.__currentPath = path + + def popStepFromPath(self): + return self.__currentPath.pop(0) def draw(self, screen): - screen.blit(self.__image, (self.getX()*100-20+self.Offset, self.getY()*100-20+self.Offset)) + imageWaiter = ImageCache.getInstance().getImage(Images.Waiter, self.getCellSize(), self.getCellSize()) + xBase = self.getX() * self.getCellSize() + self.getOffset() + yBase = self.getY() * self.getCellSize() + self.getOffset() + screen.blit(imageWaiter, (xBase, yBase)) diff --git a/kelner/src/managers/DrawableCollection.py b/kelner/src/managers/DrawableCollection.py index 9848c68..cb17915 100644 --- a/kelner/src/managers/DrawableCollection.py +++ b/kelner/src/managers/DrawableCollection.py @@ -1,22 +1,24 @@ import random -from src.components.Table import Table, Status -from src.components.Waiter import Waiter -import pygame -#drawable objects manager +from kelner.src.components.Table import Table, Status +from kelner.src.components.Waiter import Waiter + + +# drawable objects manager class DrawableCollection: - #const, minimal distance between objects - __MinDistance = 0 + # const, minimal distance between objects + __MinDistanceX = 0 + __MinDistanceY = 0 def __init__(self): - #collection that holds all drawable objects + # collection that holds all drawable objects + self.__mustRepaint = True self.__drawables = [] - self.image = pygame.transform.scale((pygame.image.load('./images/Backgroud.png')),(1700,1100)) - #adds drawable objects to the collection + # adds drawable objects to the collection def add(self, drawable): self.__drawables.append(drawable) - #generates and sets random (x, y) and cheks if it's not occupied by other object + # generates and sets random (x, y) and cheks if it's not occupied by other object def generatePosition(self, drawable): isPositionUnique = False while not isPositionUnique: @@ -24,20 +26,14 @@ class DrawableCollection: y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1) isPositionUnique = True for item in self.__drawables: - if abs(item.getX() - x) <= self.__MinDistance and abs(item.getY() - y) <= self.__MinDistance: + if abs(item.getX() - x) <= self.__MinDistanceX and abs(item.getY() - y) <= self.__MinDistanceY: isPositionUnique = False break if isPositionUnique: drawable.setX(x) drawable.setY(y) - #draws all objects stored in collection - def draw(self, screen): - screen.blit(self.image, (0, 0)) - for item in self.__drawables: - item.draw(screen) - - #checks if position (x,y) is not occupied by other object + # checks if position (x,y) is not occupied by other object def isPositionAvailable(self, x, y): isPositionAvailable = True for item in self.__drawables: @@ -46,29 +42,56 @@ class DrawableCollection: break return isPositionAvailable - #gets all tables by status from collection + # gets all tables by status from collection def getTables(self, status): result = [] for item in self.__drawables: - if isinstance(item, Table) and item.isStatus(status): + if status is None or isinstance(item, Table) and item.isStatus(status): result += [item] return result - #gets all waiters from collection - def getWaites(self): + # gets all waiters from collection + def getWaiters(self): result = [] for item in self.__drawables: if isinstance(item, Waiter): result += [item] return result - #waiter collects order from the nearest table + # waiter collects orders from all nearest tables def collectOrders(self): - waiters = self.getWaites() + waiters = self.getWaiters() for waiter in waiters: tables = self.getTables(Status.Ready) for table in tables: if (table.getX() == waiter.getX() and abs(table.getY() - waiter.getY()) == 1) or (table.getY() == waiter.getY() and abs(table.getX() - waiter.getX()) == 1): table.setStatus(Status.Waiting) waiter.addOrder(table) - table.delOrder() \ No newline at end of file + table.delOrder() + + # returns table: 0 - position is available, 1 - position is occupied + def getReservedPlaces(self, waiter): + cols = waiter.getMaxX() - waiter.getMinX() + 1 + rows = waiter.getMaxY() - waiter.getMinY() + 1 + reservedPlaces = [[0] * cols for i in range(rows)] + tables = self.getTables(None) + if tables: + for table in tables: + reservedPlaces[table.getY()][table.getX()] = 1 + return reservedPlaces + + # the method is called externally and forces repainting + def forceRepaint(self): + self.__mustRepaint = True + + # returns boolean value: True if objects should be repainted otherwise False + def mustRepaint(self): + return self.__mustRepaint + + # draws all objects stored in collection + def draw(self, screen): + for item in self.__drawables: + item.draw(screen) + for item in self.__drawables: + item.drawAux(screen) + self.__mustRepaint = False diff --git a/kelner/src/managers/ImageCache.py b/kelner/src/managers/ImageCache.py new file mode 100644 index 0000000..4fa85f8 --- /dev/null +++ b/kelner/src/managers/ImageCache.py @@ -0,0 +1,50 @@ +import pygame +from enum import Enum + + +# images enum +class Images(Enum): + Background = 0 + Waiter = 1 + Table = 2 + Menu = 3 + Check = 4 + Plate = 5 + Guest1 = 6 + Guest2 = 7 + Guest3 = 8 + + +class ImageCache: + __instance = None + + @staticmethod + def getInstance(): + if ImageCache.__instance is None: + ImageCache() + return ImageCache.__instance + + def __init__(self): + """ Virtually private constructor. """ + if ImageCache.__instance is not None: + raise Exception("This class is a singleton!") + else: + ImageCache.__instance = self + self.__images = {} + self.__paths = {Images.Background: './images/Backgroud.png', + Images.Waiter: './images/kelner.png', + Images.Table: './images/stol.png', + Images.Menu: './images/ksiazka.png', + Images.Check: './images/check.png', + Images.Plate: './images/plate.png', + Images.Guest1: './images/wiking_blond.png', + Images.Guest2: './images/wiking_rudy.png', + Images.Guest3: './images/wiking_rudy2.png'} + + def getImage(self, imageKind, width, height): + key = str(imageKind.value) + ':' + str(width) + ':' + str(height) + image = self.__images.get(key, None) + if image is None: + image = pygame.transform.scale((pygame.image.load(self.__paths[imageKind])), (width, height)) + self.__images[key] = image + return image diff --git a/kelner/src/managers/MenuManager.py b/kelner/src/managers/MenuManager.py index 7b9222b..47b34d5 100644 --- a/kelner/src/managers/MenuManager.py +++ b/kelner/src/managers/MenuManager.py @@ -1,9 +1,10 @@ import random -#contains all dishes and generates random order for the table + +# contains all dishes and generates random order for the table class MenuManager: - #consts, min and max dishes oredered by the people sitting by the same table + # consts, min and max dishes ordered by the people sitting by the same table __MinDishes = 1 __MaxDishes = 3 @@ -24,10 +25,11 @@ class MenuManager: "EMPTY PLATE", "BEER", "CAKE"] - #generator + + # generator def generateOrder(self): count = random.randint(self.__MinDishes, self.__MaxDishes) order = [] for i in range(0, count): order += [(self.__menuCard[random.randint(0, len(self.__menuCard) - 1)])] - return order \ No newline at end of file + return order diff --git a/kelner/src/managers/TableManager.py b/kelner/src/managers/TableManager.py new file mode 100644 index 0000000..4ea524a --- /dev/null +++ b/kelner/src/managers/TableManager.py @@ -0,0 +1,29 @@ +import threading +import time +import random +from kelner.src.components.Table import Status + + +# creates new thread +class TableManager (threading.Thread): + + def __init__(self, drawableManager, menuManager): + super().__init__() + self.__drawableManager = drawableManager + self.__menuManager = menuManager + self.__runThread = True + + # changes the status of a random table from NotReady to Ready + def run(self): + while self.__runThread: + tables = self.__drawableManager.getTables(Status.NotReady) + if tables: + tableIndex = random.randint(0, len(tables) - 1) + table = tables[tableIndex] + time.sleep(3) + table.setStatus(Status.Ready) + table.setOrder(self.__menuManager.generateOrder()) + self.__drawableManager.forceRepaint() + + def stop(self): + self.__runThread = False diff --git a/kelner/src/managers/WaiterManager.py b/kelner/src/managers/WaiterManager.py new file mode 100644 index 0000000..2240637 --- /dev/null +++ b/kelner/src/managers/WaiterManager.py @@ -0,0 +1,57 @@ +import threading +import time +import sys +from kelner.src.components.Table import Status +from kelner.src.algorithms.AStar.Finder import Finder + + +# creates new thread +class WaiterManager (threading.Thread): + + def __init__(self, drawableManager): + super().__init__() + self.__drawableManager = drawableManager + self.__runThread = True + + def __getNearestTargetPath(self, waiter): + distance = sys.maxsize + nearestTargetPath = None + tables = self.__drawableManager.getTables(Status.Ready) + if tables: + reservedPlaces = self.__drawableManager.getReservedPlaces(waiter) + finder = Finder(reservedPlaces) + origin = (waiter.getX(), waiter.getY()) + for table in tables: + targets = finder.getNeighbours((table.getX(), table.getY()), False) + for target in targets: + if target is not None: + path = finder.getPath(origin, target, True) + if path: + result = len(path) + if result < distance: + distance = result + nearestTargetPath = path + return nearestTargetPath + + # changes the status of a random table from NotReady to Ready + def run(self): + while self.__runThread: + waiters = self.__drawableManager.getWaiters() + if waiters: + for waiter in waiters: + path = self.__getNearestTargetPath(waiter) + if path is not None: + waiter.setPath(path) + if not waiter.isPathEmpty(): + step = waiter.popStepFromPath() + time.sleep(0.4) + waiter.setX(step[0]) + waiter.setY(step[1]) + self.__drawableManager.forceRepaint() + if waiter.isPathEmpty(): + time.sleep(2) + self.__drawableManager.collectOrders() + self.__drawableManager.forceRepaint() + + def stop(self): + self.__runThread = False