Merge branch 'mikolaj_branch' of s444417/ProjektAI into master
@ -2,7 +2,7 @@
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.7 (WaiterMaster)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
|
@ -3,4 +3,5 @@
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (WaiterMaster)" project-jdk-type="Python SDK" />
|
||||
</project>
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 657 B |
Before Width: | Height: | Size: 988 B After Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 979 B After Width: | Height: | Size: 833 B |
Before Width: | Height: | Size: 977 B After Width: | Height: | Size: 832 B |
@ -1,60 +1,64 @@
|
||||
import pygame
|
||||
from src.components.GridBoard import GridBoard
|
||||
from src.managers.DrawableCollection import DrawableCollection
|
||||
from src.managers.MenuManager import MenuManager
|
||||
from src.components.Waiter import Waiter
|
||||
from src.components.Table import Table
|
||||
from src.managers.TaskManager import TaskManager
|
||||
from kelner.src.components.GridBoard import GridBoard
|
||||
from kelner.src.components.Waiter import Waiter
|
||||
from kelner.src.components.Table import Table
|
||||
from kelner.src.managers.DrawableCollection import DrawableCollection
|
||||
from kelner.src.managers.MenuManager import MenuManager
|
||||
from kelner.src.managers.TableManager import TableManager
|
||||
from kelner.src.managers.WaiterManager import WaiterManager
|
||||
|
||||
#create screen consts
|
||||
CellSize = 100 #pixel size of 1 square cell in the grid
|
||||
GridCountX = 15 #number of columns in grid
|
||||
GridCountY = 9 #number of rows in grid
|
||||
ScreenWidth = CellSize * GridCountX #screen width in pixels
|
||||
ScreenHeight = CellSize * GridCountY #screen height in pixels
|
||||
Offset = 50
|
||||
# create screen consts
|
||||
Scale = 2 # scale for all images used within project
|
||||
CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid
|
||||
PaintOffset = CellSize # pixel size of paint offset for all drawables
|
||||
GridCountX = 15 # number of columns in grid
|
||||
GridCountY = 9 # number of rows in grid
|
||||
ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
|
||||
ScreenHeight = CellSize * GridCountY + 2 * PaintOffset # screen height in pixels
|
||||
|
||||
#initialize background
|
||||
gridBoard = GridBoard(ScreenWidth+200, ScreenHeight+200, CellSize)
|
||||
# initialize background
|
||||
gridBoard = GridBoard(ScreenWidth, ScreenHeight)
|
||||
|
||||
#initialize drawable objects manager
|
||||
# initialize drawable objects manager
|
||||
drawableManager = DrawableCollection()
|
||||
|
||||
#initialize menu manager
|
||||
# initialize menu manager
|
||||
menuManager = MenuManager()
|
||||
|
||||
#initialize waiter component
|
||||
waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize)
|
||||
# initialize waiter component
|
||||
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)
|
||||
|
||||
#initialize a number of tables given in range
|
||||
for i in range(1, 20):
|
||||
table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize)
|
||||
# initialize a number of tables given in range
|
||||
for i in range(1, 45):
|
||||
table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||
drawableManager.generatePosition(table)
|
||||
drawableManager.add(table)
|
||||
|
||||
#main loop
|
||||
# new thread controlling tables
|
||||
tableTask = TableManager(drawableManager, menuManager)
|
||||
tableTask.start()
|
||||
|
||||
#object that controlls repainting of changed objects
|
||||
doRepaint = [True]
|
||||
|
||||
#new thread
|
||||
task = TaskManager(drawableManager, menuManager, doRepaint)
|
||||
task.start()
|
||||
# new thread controlling waiter
|
||||
waiterTask = WaiterManager(drawableManager)
|
||||
waiterTask.start()
|
||||
|
||||
# main loop
|
||||
running = True
|
||||
while running:
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
tableTask.stop()
|
||||
waiterTask.stop()
|
||||
running = False
|
||||
|
||||
#handles keyboard events
|
||||
# handles keyboard events
|
||||
if event.type == pygame.KEYDOWN:
|
||||
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()):
|
||||
waiter.moveLeft()
|
||||
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
|
||||
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() + 1):
|
||||
waiter.moveDown()
|
||||
doRepaint[0] = True
|
||||
drawableManager.forceRepaint()
|
||||
|
||||
# repaints all objects to the screen
|
||||
# is set only on initial paint or after keyboard event
|
||||
if doRepaint[0]:
|
||||
# is set only on initial paint or after keyboard event or call to forceRepaint()
|
||||
if drawableManager.mustRepaint():
|
||||
gridBoard.reinitialize()
|
||||
gridBoard.draw(drawableManager)
|
||||
gridBoard.udpdate()
|
||||
doRepaint[0] = False
|
||||
drawableManager.collectOrders()
|
125
kelner/src/algorithms/AStar/Finder.py
Normal 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
|
60
kelner/src/algorithms/AStar/FinderTest.py
Normal 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)
|
34
kelner/src/algorithms/AStar/Node.py
Normal 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
|
@ -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
|
||||
pass
|
||||
|
||||
def drawAux(self, screen):
|
||||
pass
|
||||
|
@ -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()
|
||||
pygame.display.update()
|
||||
|
@ -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
|
||||
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))
|
||||
|
@ -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))
|
||||
|
@ -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()
|
||||
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
|
||||
|
50
kelner/src/managers/ImageCache.py
Normal 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
|
@ -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
|
||||
return order
|
||||
|
29
kelner/src/managers/TableManager.py
Normal 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
|
@ -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
|
57
kelner/src/managers/WaiterManager.py
Normal 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
|