Merge branch 'mikolaj_branch' of s444417/ProjektAI into master

This commit is contained in:
Mikołaj Krzymiński 2020-04-21 19:15:08 +00:00 committed by Gogs
commit 2ded95f69c
21 changed files with 578 additions and 196 deletions

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.7 (WaiterMaster)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="TestRunnerService"> <component name="TestRunnerService">

View File

@ -3,4 +3,5 @@
<component name="JavaScriptSettings"> <component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" /> <option name="languageLevel" value="ES6" />
</component> </component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (WaiterMaster)" project-jdk-type="Python SDK" />
</project> </project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 979 B

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 832 B

View File

@ -1,60 +1,64 @@
import pygame import pygame
from src.components.GridBoard import GridBoard from kelner.src.components.GridBoard import GridBoard
from src.managers.DrawableCollection import DrawableCollection from kelner.src.components.Waiter import Waiter
from src.managers.MenuManager import MenuManager from kelner.src.components.Table import Table
from src.components.Waiter import Waiter from kelner.src.managers.DrawableCollection import DrawableCollection
from src.components.Table import Table from kelner.src.managers.MenuManager import MenuManager
from src.managers.TaskManager import TaskManager from kelner.src.managers.TableManager import TableManager
from kelner.src.managers.WaiterManager import WaiterManager
#create screen consts # create screen consts
CellSize = 100 #pixel size of 1 square cell in the grid Scale = 2 # scale for all images used within project
GridCountX = 15 #number of columns in grid CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid
GridCountY = 9 #number of rows in grid PaintOffset = CellSize # pixel size of paint offset for all drawables
ScreenWidth = CellSize * GridCountX #screen width in pixels GridCountX = 15 # number of columns in grid
ScreenHeight = CellSize * GridCountY #screen height in pixels GridCountY = 9 # number of rows in grid
Offset = 50 ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
ScreenHeight = CellSize * GridCountY + 2 * PaintOffset # screen height in pixels
#initialize background # initialize background
gridBoard = GridBoard(ScreenWidth+200, ScreenHeight+200, CellSize) gridBoard = GridBoard(ScreenWidth, ScreenHeight)
#initialize drawable objects manager # initialize drawable objects manager
drawableManager = DrawableCollection() drawableManager = DrawableCollection()
#initialize menu manager # initialize menu manager
menuManager = MenuManager() menuManager = MenuManager()
#initialize waiter component # initialize waiter component
waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize) waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
#adds waiter to drawable collection # adds waiter to drawable collection
drawableManager.add(waiter) drawableManager.add(waiter)
#initialize a number of tables given in range # initialize a number of tables given in range
for i in range(1, 20): for i in range(1, 45):
table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize) table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
drawableManager.generatePosition(table) drawableManager.generatePosition(table)
drawableManager.add(table) drawableManager.add(table)
#main loop # new thread controlling tables
tableTask = TableManager(drawableManager, menuManager)
tableTask.start()
#object that controlls repainting of changed objects # new thread controlling waiter
doRepaint = [True] waiterTask = WaiterManager(drawableManager)
waiterTask.start()
#new thread
task = TaskManager(drawableManager, menuManager, doRepaint)
task.start()
# main loop
running = True running = True
while running: while running:
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
tableTask.stop()
waiterTask.stop()
running = False running = False
#handles keyboard events # handles keyboard events
if event.type == pygame.KEYDOWN: if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT: if event.key == pygame.K_LEFT:
#checks if new waiter's position to the left is not occupied by other object # checks if new waiter's position to the left is not occupied by other object
if drawableManager.isPositionAvailable(waiter.getX() - 1, waiter.getY()): if drawableManager.isPositionAvailable(waiter.getX() - 1, waiter.getY()):
waiter.moveLeft() waiter.moveLeft()
if event.key == pygame.K_RIGHT: if event.key == pygame.K_RIGHT:
@ -69,13 +73,11 @@ while running:
# checks if new waiter's position down is not occupied by other object # checks if new waiter's position down is not occupied by other object
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() + 1): if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() + 1):
waiter.moveDown() waiter.moveDown()
doRepaint[0] = True drawableManager.forceRepaint()
# repaints all objects to the screen # repaints all objects to the screen
# is set only on initial paint or after keyboard event # is set only on initial paint or after keyboard event or call to forceRepaint()
if doRepaint[0]: if drawableManager.mustRepaint():
gridBoard.reinitialize() gridBoard.reinitialize()
gridBoard.draw(drawableManager) gridBoard.draw(drawableManager)
gridBoard.udpdate() gridBoard.udpdate()
doRepaint[0] = False
drawableManager.collectOrders()

View File

@ -0,0 +1,125 @@
from queue import PriorityQueue
from kelner.src.algorithms.AStar.Node import Node
class Finder:
def __init__(self, table):
self._table = table
self._xMin = 0
self._yMin = 0
self._xMax = len(table[0]) - 1
self._yMax = len(table) - 1
self.__isDiagonal = False
def _set(self, x, y, v):
self._table[y][x] = v
def _get(self, x, y):
return self._table[y][x]
# returns right position relative to the node
def __incXnopY(self, node, neighbours):
if node.x < self._xMax and self._get(node.x + 1, node.y) == 0:
neighbours.append(Node(node, node.x + 1, node.y, node.distance + 1))
# returns left position relative to the node
def __decXnopY(self, node, neighbours):
if self._xMin < node.x and self._get(node.x - 1, node.y) == 0:
neighbours.append(Node(node, node.x - 1, node.y, node.distance + 1))
# returns top position relative to the node
def __nopXincY(self, node, neighbours):
if node.y < self._yMax and self._get(node.x, node.y + 1) == 0:
neighbours.append(Node(node, node.x, node.y + 1, node.distance + 1))
# returns bottom position relative to the node
def __nopXdecY(self, node, neighbours):
if self._yMin < node.y and self._get(node.x, node.y - 1) == 0:
neighbours.append(Node(node, node.x, node.y - 1, node.distance + 1))
# returns left top position relative to the node
def __decXdecY(self, node, neighbours):
if (self._xMin < node.x and self._yMin < node.y and
self._get(node.x - 1, node.y - 1) == 0 and
self._get(node.x - 1, node.y) == 0 and
self._get(node.x, node.y - 1) == 0):
neighbours.append(Node(node, node.x - 1, node.y - 1, node.distance + 2))
# returns left bottom position relative to the node
def __decXincY(self, node, neighbours):
if (self._xMin < node.x and node.y < self._yMax and
self._get(node.x - 1, node.y + 1) == 0 and
self._get(node.x - 1, node.y) == 0 and
self._get(node.x, node.y + 1) == 0):
neighbours.append(Node(node, node.x - 1, node.y + 1, node.distance + 2))
# returns right bottom position relative to the node
def __incXincY(self, node, neighbours):
if (node.x < self._xMax and node.y < self._yMax and
self._get(node.x + 1, node.y + 1) == 0 and
self._get(node.x + 1, node.y) == 0 and
self._get(node.x, node.y + 1) == 0):
neighbours.append(Node(node, node.x + 1, node.y + 1, node.distance + 2))
# returns right top position relative to the node
def __incXdecY(self, node, neighbours):
if (node.x < self._xMax and self._yMin < node.y and
self._get(node.x + 1, node.y - 1) == 0 and
self._get(node.x + 1, node.y) == 0 and
self._get(node.x, node.y - 1) == 0):
neighbours.append(Node(node, node.x + 1, node.y - 1, node.distance + 2))
# returns all plausible positions relative to the node
def __getNeighbours(self, node):
neighbours = []
self.__nopXincY(node, neighbours)
self.__incXnopY(node, neighbours)
self.__decXnopY(node, neighbours)
self.__nopXdecY(node, neighbours)
if self.__isDiagonal:
self.__decXdecY(node, neighbours)
self.__decXincY(node, neighbours)
self.__incXincY(node, neighbours)
self.__incXdecY(node, neighbours)
return neighbours
# main algorithm - simplification of well known A*
def __getPath(self, origin, target):
Q = PriorityQueue()
V = set()
Q.put(origin)
while not Q.empty():
head = Q.get()
if head == target:
return head
V.add(head)
for node in self.__getNeighbours(head):
if node not in V:
node.estimated = node.distance + node.getDistanceTo(target)
Q.put(node)
V.add(node)
return None
# returns neighbours for locationXY-tuple as list of tuple(x,y)
def getNeighbours(self, locationXY, isDiagonal):
neighboursXY = []
self.__isDiagonal = isDiagonal
location = Node(None, locationXY[0], locationXY[1], 0)
neighbours = self.__getNeighbours(location)
for neighbour in neighbours:
neighboursXY.append((neighbour.x, neighbour.y))
return neighboursXY
# returns the shortest path as list of tuple(x,y) from originXY-tuple to targetXY-tuple
def getPath(self, originXY, targetXY, isDiagonal):
self.__isDiagonal = isDiagonal
origin = Node(None, originXY[0], originXY[1], 0)
target = Node(None, targetXY[0], targetXY[1], 0)
result = self.__getPath(origin, target)
path = []
while result is not None:
if result.parent is not None:
path.insert(0, (result.x, result.y))
result = result.parent
return path

View File

@ -0,0 +1,60 @@
from random import randint
from kelner.src.algorithms.AStar.Finder import Finder
class FinderTest(Finder):
def __init__(self, table):
super().__init__(table)
def __setValues(self, xys, v):
if xys is not None:
for xy in xys:
self._set(xy[0], xy[1], v)
def print(self, xys):
self.__setValues(xys, 2)
for row in self._table:
for col in row:
v = ' ' if col == 0 else '#' if col == 1 else 'O'
print('|', v, sep='', end='')
print('|')
self.__setValues(xys, 0)
def getRandomTuple(self):
while True:
x = randint(self._xMin, self._xMax)
y = randint(self._yMin, self._yMax)
if self._get(x, y) == 0:
break
return x, y
def getRandomBorderTuple(self):
xSet = [self._xMin, self._xMax]
ySet = [self._yMin, self._yMax]
while True:
x = randint(self._xMin, self._xMax)
y = randint(self._yMin, self._yMax)
if (x in xSet or y in ySet) and self._get(x, y) == 0:
break
return x, y
def fillRandom(self):
for _ in range(120):
while True:
x = randint(self._xMin, self._xMax)
y = randint(self._yMin, self._yMax)
if self._get(x, y) == 0:
break
self._set(x, y, 1)
cols = 20
rows = 20
table = [[0] * cols for i in range(rows)]
finder = FinderTest(table)
finder.fillRandom()
originXY = finder.getRandomBorderTuple()
targetXY = finder.getRandomBorderTuple()
result = finder.getPath(originXY, targetXY, True)
finder.print(result)

View File

@ -0,0 +1,34 @@
from math import sqrt
class Node:
def __init__(self, parent, x, y, distance):
self.parent = parent
self.x = x
self.y = y
self.distance = distance
self.estimated = distance
# returns distance from the object to other node
def getDistanceTo(self, other):
dx = self.x - other.x
dy = self.y - other.y
return sqrt(dx * dx + dy * dy)
# abs(dx) + abs(dy)
# used by str() method to represent the object
def __repr__(self):
return "%s:%s" % (self.x, self.y)
# generates hash key for Set
def __hash__(self):
return hash(str(self))
# operator (==) for Set (determines if the object equals other node)
def __eq__(self, other):
return (self.x == other.x) and (self.y == other.y)
# operator (>) for PriorityQueue comparison (determines the objects order)
def __gt__(self, other):
return self.estimated > other.estimated

View File

@ -5,29 +5,33 @@ class Drawable:
RED = (255, 0, 0) RED = (255, 0, 0)
GREEN = (0, 255, 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.__minX = minX
self.__maxX = maxX self.__maxX = maxX
self.__minY = minY self.__minY = minY
self.__maxY = maxY self.__maxY = maxY
self.setX(x) self.setX(x)
self.setY(y) 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): def setX(self, x):
if (x < self.__minX or self.__maxX < x): if x < self.__minX or self.__maxX < x:
return False return False
else: else:
self.__x = x self.__x = x
return True return True
def setY(self, y): def setY(self, y):
if (y < self.__minY or self.__maxY < y): if y < self.__minY or self.__maxY < y:
return False return False
else: else:
self.__y = y self.__y = y
return True return True
def isPositionCorrect(self, x, y):
return self.__minX <= x <= self.__maxX and self.__minY <= y <= self.__maxY
def getX(self): def getX(self):
return self.__x return self.__x
@ -46,8 +50,14 @@ class Drawable:
def getMaxY(self): def getMaxY(self):
return self.__maxY return self.__maxY
def getRatio(self): def getCellSize(self):
return self.__ratio return self.__cellSize
def getOffset(self):
return self.__offset
def draw(self, screen): def draw(self, screen):
pass pass
def drawAux(self, screen):
pass

View File

@ -1,28 +1,32 @@
import pygame import pygame
from kelner.src.managers.ImageCache import ImageCache, Images
class GridBoard: class GridBoard:
def __init__(self, width, height, cellSize): def __init__(self, width, height):
pygame.init() #initialize the pygame pygame.init() # initialize the pygame
pygame.display.set_caption("Bardzo mądry kelner") #window caption pygame.display.set_caption("Bardzo mądry kelner") # window caption
self.__width = width self.__width = width
self.__height = height self.__height = height
self.__cellSize = cellSize
self.__screen = pygame.display.set_mode((width, height)) # initialize screen 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): 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)) self.__screen.fill((255, 255, 255))
for x in range(0, self.__width, self.__cellSize): for x in range(0, self.__width, self.__cellSize):
pygame.draw.line(self.__screen, (0,0,0), (x,0), (x,(self.__height - 1))) pygame.draw.line(self.__screen, (0,0,0), (x,0), (x,(self.__height - 1)))
for y in range(0, self.__height, self.__cellSize): for y in range(0, self.__height, self.__cellSize):
pygame.draw.line(self.__screen, (0,0,0), (0,y), ((self.__width - 1),y)) 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): def draw(self, component):
component.draw(self.__screen) component.draw(self.__screen)
#updates screen # updates screen
def udpdate(self): def udpdate(self):
pygame.display.update() pygame.display.update()

View File

@ -1,79 +1,33 @@
import pygame
from enum import Enum
from .Drawable import Drawable
import random 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): class Table(Drawable):
def __init__(self, minX, maxX, minY, maxY, ratio): def __init__(self, minX, maxX, minY, maxY, ratio, offset):
#call base class constructor # call base class constructor
Drawable.__init__(self, 0, 0, minX, maxX, minY, maxY, ratio) super().__init__(0, 0, minX, maxX, minY, maxY, ratio, offset)
self.__order = []
self.__status = Status.NotReady self.__status = Status.NotReady
self.ilosc_klientow = random.randint(1,3) self.__order = []
self.guest1 = self.getGuest() self.__guests = self.__getRandomGuests()
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))
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): def setOrder(self, order):
self.__order = order self.__order = order
@ -90,9 +44,57 @@ class Table(Drawable):
def setStatus(self, status): def setStatus(self, status):
self.__status = status self.__status = status
#status of the table def __getImage(self, imageKind):
class Status(Enum): if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
NotReady = 0 size = int(self.getCellSize() / 3)
Ready = 1 else:
Waiting = 2 size = int(1.4 * self.getCellSize())
Served = 3 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))

View File

@ -1,15 +1,14 @@
import pygame from kelner.src.components.Drawable import Drawable
from .Drawable import Drawable from kelner.src.managers.ImageCache import ImageCache, Images
class Waiter(Drawable): class Waiter(Drawable):
def __init__(self, x, y, minX, maxX, minY, maxY, ratio): def __init__(self, x, y, minX, maxX, minY, maxY, ratio, offset):
#call base class constructor # call base class constructor
Drawable.__init__(self, x, y, minX, maxX, minY, maxY, ratio) super().__init__(x, y, minX, maxX, minY, maxY, ratio, offset)
self.__image = self.__loadImg('./images/kelner.png')
self.__acceptedOrders = [] self.__acceptedOrders = []
self.Offset = 100 self.__currentPath = []
def moveUp(self): def moveUp(self):
if self.getY() > self.getMinY(): if self.getY() > self.getMinY():
@ -39,12 +38,21 @@ class Waiter(Drawable):
else: else:
return False 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): def addOrder(self, table):
self.__acceptedOrders += [(table, table.getOrder())] self.__acceptedOrders += [(table, table.getOrder())]
def __loadImg(self, filePath): def isPathEmpty(self):
return pygame.transform.scale((pygame.image.load(filePath)),(140,140)) return self.__currentPath == []
def setPath(self, path):
self.__currentPath = path
def popStepFromPath(self):
return self.__currentPath.pop(0)
def draw(self, screen): 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))

View File

@ -1,22 +1,24 @@
import random import random
from src.components.Table import Table, Status from kelner.src.components.Table import Table, Status
from src.components.Waiter import Waiter from kelner.src.components.Waiter import Waiter
import pygame
#drawable objects manager
# drawable objects manager
class DrawableCollection: class DrawableCollection:
#const, minimal distance between objects # const, minimal distance between objects
__MinDistance = 0 __MinDistanceX = 0
__MinDistanceY = 0
def __init__(self): def __init__(self):
#collection that holds all drawable objects # collection that holds all drawable objects
self.__mustRepaint = True
self.__drawables = [] 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): def add(self, drawable):
self.__drawables.append(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): def generatePosition(self, drawable):
isPositionUnique = False isPositionUnique = False
while not isPositionUnique: while not isPositionUnique:
@ -24,20 +26,14 @@ class DrawableCollection:
y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1) y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1)
isPositionUnique = True isPositionUnique = True
for item in self.__drawables: 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 isPositionUnique = False
break break
if isPositionUnique: if isPositionUnique:
drawable.setX(x) drawable.setX(x)
drawable.setY(y) drawable.setY(y)
#draws all objects stored in collection # checks if position (x,y) is not occupied by other object
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
def isPositionAvailable(self, x, y): def isPositionAvailable(self, x, y):
isPositionAvailable = True isPositionAvailable = True
for item in self.__drawables: for item in self.__drawables:
@ -46,25 +42,25 @@ class DrawableCollection:
break break
return isPositionAvailable return isPositionAvailable
#gets all tables by status from collection # gets all tables by status from collection
def getTables(self, status): def getTables(self, status):
result = [] result = []
for item in self.__drawables: 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] result += [item]
return result return result
#gets all waiters from collection # gets all waiters from collection
def getWaites(self): def getWaiters(self):
result = [] result = []
for item in self.__drawables: for item in self.__drawables:
if isinstance(item, Waiter): if isinstance(item, Waiter):
result += [item] result += [item]
return result return result
#waiter collects order from the nearest table # waiter collects orders from all nearest tables
def collectOrders(self): def collectOrders(self):
waiters = self.getWaites() waiters = self.getWaiters()
for waiter in waiters: for waiter in waiters:
tables = self.getTables(Status.Ready) tables = self.getTables(Status.Ready)
for table in tables: for table in tables:
@ -72,3 +68,30 @@ class DrawableCollection:
table.setStatus(Status.Waiting) table.setStatus(Status.Waiting)
waiter.addOrder(table) waiter.addOrder(table)
table.delOrder() 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

View File

@ -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

View File

@ -1,9 +1,10 @@
import random import random
#contains all dishes and generates random order for the table
# contains all dishes and generates random order for the table
class MenuManager: 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 __MinDishes = 1
__MaxDishes = 3 __MaxDishes = 3
@ -24,7 +25,8 @@ class MenuManager:
"EMPTY PLATE", "EMPTY PLATE",
"BEER", "BEER",
"CAKE"] "CAKE"]
#generator
# generator
def generateOrder(self): def generateOrder(self):
count = random.randint(self.__MinDishes, self.__MaxDishes) count = random.randint(self.__MinDishes, self.__MaxDishes)
order = [] order = []

View File

@ -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

View File

@ -1,25 +0,0 @@
import threading
import time
import random
from src.components.Table import Status
#creates new threads
class TaskManager (threading.Thread):
def __init__(self, drawableManager, menuManager, doRepaintObject):
threading.Thread.__init__(self)
self.__drawableManager = drawableManager
self.__menuManager = menuManager
self.__doRepaintObject = doRepaintObject
#changes the status of a random table from NotReady to Ready
def run(self):
while True:
time.sleep(3)
tables = self.__drawableManager.getTables(Status.NotReady)
if tables != []:
tableIndex = random.randint(0, len(tables) - 1)
table = tables[tableIndex]
table.setStatus(Status.Ready)
table.setOrder(self.__menuManager.generateOrder())
self.__doRepaintObject[0] = True

View File

@ -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