Merge branch 'mikolaj_branch' of s444417/ProjektAI into master
@ -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="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.7 (venv)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
|
@ -3,5 +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.8" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (venv)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
Before Width: | Height: | Size: 184 B |
BIN
kelner/images/kelner_full_D.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
kelner/images/kelner_full_L.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
kelner/images/kelner_full_LD.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
kelner/images/kelner_full_LU.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
kelner/images/kelner_full_R.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
kelner/images/kelner_full_RD.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
kelner/images/kelner_full_RU.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
kelner/images/kelner_full_U.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 155 KiB |
BIN
kelner/images/tooltip.png
Normal file
After Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 18 KiB |
@ -26,24 +26,39 @@ drawableManager = DrawableCollection()
|
|||||||
menuManager = MenuManager()
|
menuManager = MenuManager()
|
||||||
|
|
||||||
# initialize waiter component
|
# initialize waiter component
|
||||||
waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
waiter1 = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
|
waiter2 = Waiter(0, 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
|
waiter3 = Waiter(0, 2, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
|
waiter4 = Waiter(0, 3, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
|
|
||||||
# adds waiter to drawable collection
|
# adds waiter to drawable collection
|
||||||
drawableManager.add(waiter)
|
drawableManager.add(waiter1)
|
||||||
|
drawableManager.add(waiter2)
|
||||||
|
drawableManager.add(waiter3)
|
||||||
|
drawableManager.add(waiter4)
|
||||||
|
|
||||||
# initialize a number of tables given in range
|
# initialize a number of tables given in range
|
||||||
for i in range(1, 45):
|
for i in range(1, 40):
|
||||||
table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
table = Table(0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
drawableManager.generatePosition(table)
|
if drawableManager.generatePosition(table):
|
||||||
drawableManager.add(table)
|
drawableManager.add(table)
|
||||||
|
|
||||||
# new thread controlling tables
|
# new thread controlling tables
|
||||||
tableTask = TableManager(drawableManager, menuManager)
|
tableTask = TableManager(drawableManager, menuManager)
|
||||||
tableTask.start()
|
tableTask.start()
|
||||||
|
|
||||||
# new thread controlling waiter
|
# new thread controlling waiter
|
||||||
waiterTask = WaiterManager(drawableManager)
|
waiter1Task = WaiterManager(drawableManager, [waiter1])
|
||||||
waiterTask.start()
|
waiter1Task.start()
|
||||||
|
|
||||||
|
waiter2Task = WaiterManager(drawableManager, [waiter2])
|
||||||
|
waiter2Task.start()
|
||||||
|
|
||||||
|
waiter3Task = WaiterManager(drawableManager, [waiter3])
|
||||||
|
waiter3Task.start()
|
||||||
|
|
||||||
|
waiter4Task = WaiterManager(drawableManager, [waiter4])
|
||||||
|
waiter4Task.start()
|
||||||
|
|
||||||
# main loop
|
# main loop
|
||||||
running = True
|
running = True
|
||||||
@ -52,27 +67,51 @@ 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()
|
tableTask.stop()
|
||||||
waiterTask.stop()
|
waiter1Task.stop()
|
||||||
|
waiter2Task.stop()
|
||||||
|
waiter3Task.stop()
|
||||||
|
waiter4Task.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(waiter1.getX() - 1, waiter1.getY()):
|
||||||
waiter.moveLeft()
|
waiter1.moveLeft()
|
||||||
if event.key == pygame.K_RIGHT:
|
if event.key == pygame.K_RIGHT:
|
||||||
# checks if new waiter's position to the right is not occupied by other object
|
# checks if new waiter's position to the right is not occupied by other object
|
||||||
if drawableManager.isPositionAvailable(waiter.getX() + 1, waiter.getY()):
|
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY()):
|
||||||
waiter.moveRight()
|
waiter1.moveRight()
|
||||||
if event.key == pygame.K_UP:
|
if event.key == pygame.K_UP:
|
||||||
# checks if new waiter's position up is not occupied by other object
|
# checks if new waiter's position up is not occupied by other object
|
||||||
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() - 1):
|
if drawableManager.isPositionAvailable(waiter1.getX(), waiter1.getY() - 1):
|
||||||
waiter.moveUp()
|
waiter1.moveUp()
|
||||||
if event.key == pygame.K_DOWN:
|
if event.key == pygame.K_DOWN:
|
||||||
# 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(waiter1.getX(), waiter1.getY() + 1):
|
||||||
waiter.moveDown()
|
waiter1.moveDown()
|
||||||
|
|
||||||
|
if event.key == pygame.K_w:
|
||||||
|
# checks if new waiter's position to the left is not occupied by other object
|
||||||
|
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() - 1):
|
||||||
|
waiter1.moveLeft()
|
||||||
|
waiter1.moveUp()
|
||||||
|
if event.key == pygame.K_d:
|
||||||
|
# checks if new waiter's position to the right is not occupied by other object
|
||||||
|
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() - 1):
|
||||||
|
waiter1.moveRight()
|
||||||
|
waiter1.moveUp()
|
||||||
|
if event.key == pygame.K_s:
|
||||||
|
# checks if new waiter's position up is not occupied by other object
|
||||||
|
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() + 1):
|
||||||
|
waiter1.moveDown()
|
||||||
|
waiter1.moveRight()
|
||||||
|
if event.key == pygame.K_a:
|
||||||
|
# checks if new waiter's position down is not occupied by other object
|
||||||
|
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() + 1):
|
||||||
|
waiter1.moveDown()
|
||||||
|
waiter1.moveLeft()
|
||||||
drawableManager.forceRepaint()
|
drawableManager.forceRepaint()
|
||||||
|
|
||||||
# repaints all objects to the screen
|
# repaints all objects to the screen
|
||||||
|
@ -1,125 +1,140 @@
|
|||||||
from queue import PriorityQueue
|
from queue import PriorityQueue
|
||||||
from kelner.src.algorithms.AStar.Node import Node
|
from kelner.src.algorithms.AStar.Node import Node
|
||||||
|
|
||||||
|
|
||||||
class Finder:
|
class Finder:
|
||||||
|
|
||||||
def __init__(self, table):
|
def __init__(self, table):
|
||||||
self._table = table
|
self._table = table
|
||||||
self._xMin = 0
|
self._xMin = 0
|
||||||
self._yMin = 0
|
self._yMin = 0
|
||||||
self._xMax = len(table[0]) - 1
|
self._xMax = len(table[0]) - 1
|
||||||
self._yMax = len(table) - 1
|
self._yMax = len(table) - 1
|
||||||
self.__isDiagonal = False
|
|
||||||
|
def _set(self, x, y, v):
|
||||||
def _set(self, x, y, v):
|
self._table[y][x] = v
|
||||||
self._table[y][x] = v
|
|
||||||
|
def _get(self, x, y):
|
||||||
def _get(self, x, y):
|
return self._table[y][x]
|
||||||
return self._table[y][x]
|
|
||||||
|
# returns right position relative to the node
|
||||||
# returns right position relative to the node
|
def __incXnopY(self, node, direction, isDiagonal, neighbours):
|
||||||
def __incXnopY(self, node, neighbours):
|
if node.x < self._xMax and self._get(node.x + 1, node.y) == 0:
|
||||||
if node.x < self._xMax and self._get(node.x + 1, node.y) == 0:
|
turnsCount = self.getTurnsCount(direction, (1, 0), isDiagonal)
|
||||||
neighbours.append(Node(node, node.x + 1, node.y, node.distance + 1))
|
neighbours.append(Node(node, node.x + 1, node.y, node.distance + turnsCount + 1))
|
||||||
|
|
||||||
# returns left position relative to the node
|
# returns left position relative to the node
|
||||||
def __decXnopY(self, node, neighbours):
|
def __decXnopY(self, node, direction, isDiagonal, neighbours):
|
||||||
if self._xMin < node.x and self._get(node.x - 1, node.y) == 0:
|
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))
|
turnsCount = self.getTurnsCount(direction, (-1, 0), isDiagonal)
|
||||||
|
neighbours.append(Node(node, node.x - 1, node.y, node.distance + turnsCount + 1))
|
||||||
# returns top position relative to the node
|
|
||||||
def __nopXincY(self, node, neighbours):
|
# returns top position relative to the node
|
||||||
if node.y < self._yMax and self._get(node.x, node.y + 1) == 0:
|
def __nopXincY(self, node, direction, isDiagonal, neighbours):
|
||||||
neighbours.append(Node(node, node.x, node.y + 1, node.distance + 1))
|
if node.y < self._yMax and self._get(node.x, node.y + 1) == 0:
|
||||||
|
turnsCount = self.getTurnsCount(direction, (0, 1), isDiagonal)
|
||||||
# returns bottom position relative to the node
|
neighbours.append(Node(node, node.x, node.y + 1, node.distance + turnsCount + 1))
|
||||||
def __nopXdecY(self, node, neighbours):
|
|
||||||
if self._yMin < node.y and self._get(node.x, node.y - 1) == 0:
|
# returns bottom position relative to the node
|
||||||
neighbours.append(Node(node, node.x, node.y - 1, node.distance + 1))
|
def __nopXdecY(self, node, direction, isDiagonal, neighbours):
|
||||||
|
if self._yMin < node.y and self._get(node.x, node.y - 1) == 0:
|
||||||
# returns left top position relative to the node
|
turnsCount = self.getTurnsCount(direction, (0, -1), isDiagonal)
|
||||||
def __decXdecY(self, node, neighbours):
|
neighbours.append(Node(node, node.x, node.y - 1, node.distance + turnsCount + 1))
|
||||||
if (self._xMin < node.x and self._yMin < node.y and
|
|
||||||
self._get(node.x - 1, node.y - 1) == 0 and
|
# returns left top position relative to the node
|
||||||
self._get(node.x - 1, node.y) == 0 and
|
def __decXdecY(self, node, direction, isDiagonal, neighbours):
|
||||||
self._get(node.x, node.y - 1) == 0):
|
if (self._xMin < node.x and self._yMin < node.y and
|
||||||
neighbours.append(Node(node, node.x - 1, node.y - 1, node.distance + 2))
|
self._get(node.x - 1, node.y - 1) == 0 and
|
||||||
|
self._get(node.x - 1, node.y) == 0 and
|
||||||
# returns left bottom position relative to the node
|
self._get(node.x, node.y - 1) == 0):
|
||||||
def __decXincY(self, node, neighbours):
|
turnsCount = self.getTurnsCount(direction, (-1, -1), isDiagonal)
|
||||||
if (self._xMin < node.x and node.y < self._yMax and
|
neighbours.append(Node(node, node.x - 1, node.y - 1, node.distance + turnsCount + 2))
|
||||||
self._get(node.x - 1, node.y + 1) == 0 and
|
|
||||||
self._get(node.x - 1, node.y) == 0 and
|
# returns left bottom position relative to the node
|
||||||
self._get(node.x, node.y + 1) == 0):
|
def __decXincY(self, node, direction, isDiagonal, neighbours):
|
||||||
neighbours.append(Node(node, node.x - 1, node.y + 1, node.distance + 2))
|
if (self._xMin < node.x and node.y < self._yMax and
|
||||||
|
self._get(node.x - 1, node.y + 1) == 0 and
|
||||||
# returns right bottom position relative to the node
|
self._get(node.x - 1, node.y) == 0 and
|
||||||
def __incXincY(self, node, neighbours):
|
self._get(node.x, node.y + 1) == 0):
|
||||||
if (node.x < self._xMax and node.y < self._yMax and
|
turnsCount = self.getTurnsCount(direction, (-1, 1), isDiagonal)
|
||||||
self._get(node.x + 1, node.y + 1) == 0 and
|
neighbours.append(Node(node, node.x - 1, node.y + 1, node.distance + turnsCount + 2))
|
||||||
self._get(node.x + 1, node.y) == 0 and
|
|
||||||
self._get(node.x, node.y + 1) == 0):
|
# returns right bottom position relative to the node
|
||||||
neighbours.append(Node(node, node.x + 1, node.y + 1, node.distance + 2))
|
def __incXincY(self, node, direction, isDiagonal, neighbours):
|
||||||
|
if (node.x < self._xMax and node.y < self._yMax and
|
||||||
# returns right top position relative to the node
|
self._get(node.x + 1, node.y + 1) == 0 and
|
||||||
def __incXdecY(self, node, neighbours):
|
self._get(node.x + 1, node.y) == 0 and
|
||||||
if (node.x < self._xMax and self._yMin < node.y and
|
self._get(node.x, node.y + 1) == 0):
|
||||||
self._get(node.x + 1, node.y - 1) == 0 and
|
turnsCount = self.getTurnsCount(direction, (1, 1), isDiagonal)
|
||||||
self._get(node.x + 1, node.y) == 0 and
|
neighbours.append(Node(node, node.x + 1, node.y + 1, node.distance + turnsCount + 2))
|
||||||
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, direction, isDiagonal, neighbours):
|
||||||
# returns all plausible positions relative to the node
|
if (node.x < self._xMax and self._yMin < node.y and
|
||||||
def __getNeighbours(self, node):
|
self._get(node.x + 1, node.y - 1) == 0 and
|
||||||
neighbours = []
|
self._get(node.x + 1, node.y) == 0 and
|
||||||
self.__nopXincY(node, neighbours)
|
self._get(node.x, node.y - 1) == 0):
|
||||||
self.__incXnopY(node, neighbours)
|
turnsCount = self.getTurnsCount(direction, (1, -1), isDiagonal)
|
||||||
self.__decXnopY(node, neighbours)
|
neighbours.append(Node(node, node.x + 1, node.y - 1, node.distance + turnsCount + 2))
|
||||||
self.__nopXdecY(node, neighbours)
|
|
||||||
if self.__isDiagonal:
|
# returns all plausible positions relative to the node
|
||||||
self.__decXdecY(node, neighbours)
|
def __getNeighbours(self, node, isDiagonal):
|
||||||
self.__decXincY(node, neighbours)
|
direction = node.getDirection()
|
||||||
self.__incXincY(node, neighbours)
|
neighbours = []
|
||||||
self.__incXdecY(node, neighbours)
|
self.__nopXincY(node, direction, isDiagonal, neighbours)
|
||||||
return neighbours
|
self.__incXnopY(node, direction, isDiagonal, neighbours)
|
||||||
|
self.__decXnopY(node, direction, isDiagonal, neighbours)
|
||||||
# main algorithm - simplification of well known A*
|
self.__nopXdecY(node, direction, isDiagonal, neighbours)
|
||||||
def __getPath(self, origin, target):
|
if isDiagonal:
|
||||||
Q = PriorityQueue()
|
self.__decXdecY(node, direction, isDiagonal, neighbours)
|
||||||
V = set()
|
self.__decXincY(node, direction, isDiagonal, neighbours)
|
||||||
Q.put(origin)
|
self.__incXincY(node, direction, isDiagonal, neighbours)
|
||||||
while not Q.empty():
|
self.__incXdecY(node, direction, isDiagonal, neighbours)
|
||||||
head = Q.get()
|
return neighbours
|
||||||
if head == target:
|
|
||||||
return head
|
# main algorithm - simplification of well known A*
|
||||||
V.add(head)
|
def __getPath(self, origin, target, isDiagonal):
|
||||||
for node in self.__getNeighbours(head):
|
Q = PriorityQueue()
|
||||||
if node not in V:
|
V = set()
|
||||||
node.estimated = node.distance + node.getDistanceTo(target)
|
Q.put(origin)
|
||||||
Q.put(node)
|
while not Q.empty():
|
||||||
V.add(node)
|
head = Q.get()
|
||||||
return None
|
if head == target:
|
||||||
|
return head
|
||||||
# returns neighbours for locationXY-tuple as list of tuple(x,y)
|
V.add(head)
|
||||||
def getNeighbours(self, locationXY, isDiagonal):
|
for node in self.__getNeighbours(head, isDiagonal):
|
||||||
neighboursXY = []
|
if node not in V:
|
||||||
self.__isDiagonal = isDiagonal
|
node.estimated = node.distance + node.getDistanceTo(target)
|
||||||
location = Node(None, locationXY[0], locationXY[1], 0)
|
Q.put(node)
|
||||||
neighbours = self.__getNeighbours(location)
|
V.add(node)
|
||||||
for neighbour in neighbours:
|
return None
|
||||||
neighboursXY.append((neighbour.x, neighbour.y))
|
|
||||||
return neighboursXY
|
# returns the number of turns to change direction from old to new
|
||||||
|
@staticmethod
|
||||||
# returns the shortest path as list of tuple(x,y) from originXY-tuple to targetXY-tuple
|
def getTurnsCount(oldDirection, newDirection, isDiagonal):
|
||||||
def getPath(self, originXY, targetXY, isDiagonal):
|
if oldDirection == (0, 0) or oldDirection == newDirection:
|
||||||
self.__isDiagonal = isDiagonal
|
return 0
|
||||||
origin = Node(None, originXY[0], originXY[1], 0)
|
if 0 == oldDirection[0] + newDirection[0] and 0 == oldDirection[1] + newDirection[1]:
|
||||||
target = Node(None, targetXY[0], targetXY[1], 0)
|
return 4 if isDiagonal else 2
|
||||||
result = self.__getPath(origin, target)
|
return abs(newDirection[0] - oldDirection[0]) + abs(newDirection[1] - oldDirection[1]) if isDiagonal else 1
|
||||||
path = []
|
|
||||||
while result is not None:
|
# returns neighbours for locationXY-tuple as list of tuple(x,y)
|
||||||
if result.parent is not None:
|
def getNeighbours(self, locationXY, isDiagonal):
|
||||||
path.insert(0, (result.x, result.y))
|
neighboursXY = []
|
||||||
result = result.parent
|
location = Node(None, locationXY[0], locationXY[1], 0)
|
||||||
return path
|
neighbours = self.__getNeighbours(location, isDiagonal)
|
||||||
|
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):
|
||||||
|
origin = Node(None, originXY[0], originXY[1], 0)
|
||||||
|
target = Node(None, targetXY[0], targetXY[1], 0)
|
||||||
|
result = self.__getPath(origin, target, isDiagonal)
|
||||||
|
path = []
|
||||||
|
while result is not None:
|
||||||
|
if result.parent is not None:
|
||||||
|
path.insert(0, (result.x, result.y))
|
||||||
|
result = result.parent
|
||||||
|
return path
|
||||||
|
@ -1,60 +1,60 @@
|
|||||||
from random import randint
|
import random
|
||||||
from kelner.src.algorithms.AStar.Finder import Finder
|
from kelner.src.algorithms.AStar.Finder import Finder
|
||||||
|
|
||||||
|
|
||||||
class FinderTest(Finder):
|
class FinderTest(Finder):
|
||||||
|
|
||||||
def __init__(self, table):
|
def __init__(self, table):
|
||||||
super().__init__(table)
|
super().__init__(table)
|
||||||
|
|
||||||
def __setValues(self, xys, v):
|
def __setValues(self, xys, v):
|
||||||
if xys is not None:
|
if xys is not None:
|
||||||
for xy in xys:
|
for xy in xys:
|
||||||
self._set(xy[0], xy[1], v)
|
self._set(xy[0], xy[1], v)
|
||||||
|
|
||||||
def print(self, xys):
|
def print(self, xys):
|
||||||
self.__setValues(xys, 2)
|
self.__setValues(xys, 2)
|
||||||
for row in self._table:
|
for row in self._table:
|
||||||
for col in row:
|
for col in row:
|
||||||
v = ' ' if col == 0 else '#' if col == 1 else 'O'
|
v = ' ' if col == 0 else '#' if col == 1 else 'O'
|
||||||
print('|', v, sep='', end='')
|
print('|', v, sep='', end='')
|
||||||
print('|')
|
print('|')
|
||||||
self.__setValues(xys, 0)
|
self.__setValues(xys, 0)
|
||||||
|
|
||||||
def getRandomTuple(self):
|
def getRandomTuple(self):
|
||||||
while True:
|
while True:
|
||||||
x = randint(self._xMin, self._xMax)
|
x = random.randint(self._xMin, self._xMax)
|
||||||
y = randint(self._yMin, self._yMax)
|
y = random.randint(self._yMin, self._yMax)
|
||||||
if self._get(x, y) == 0:
|
if self._get(x, y) == 0:
|
||||||
break
|
break
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def getRandomBorderTuple(self):
|
def getRandomBorderTuple(self):
|
||||||
xSet = [self._xMin, self._xMax]
|
xSet = [self._xMin, self._xMax]
|
||||||
ySet = [self._yMin, self._yMax]
|
ySet = [self._yMin, self._yMax]
|
||||||
while True:
|
while True:
|
||||||
x = randint(self._xMin, self._xMax)
|
x = random.randint(self._xMin, self._xMax)
|
||||||
y = randint(self._yMin, self._yMax)
|
y = random.randint(self._yMin, self._yMax)
|
||||||
if (x in xSet or y in ySet) and self._get(x, y) == 0:
|
if (x in xSet or y in ySet) and self._get(x, y) == 0:
|
||||||
break
|
break
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def fillRandom(self):
|
def fillRandom(self):
|
||||||
for _ in range(120):
|
for _ in range(120):
|
||||||
while True:
|
while True:
|
||||||
x = randint(self._xMin, self._xMax)
|
x = random.randint(self._xMin, self._xMax)
|
||||||
y = randint(self._yMin, self._yMax)
|
y = random.randint(self._yMin, self._yMax)
|
||||||
if self._get(x, y) == 0:
|
if self._get(x, y) == 0:
|
||||||
break
|
break
|
||||||
self._set(x, y, 1)
|
self._set(x, y, 1)
|
||||||
|
|
||||||
|
|
||||||
cols = 20
|
cols = 20
|
||||||
rows = 20
|
rows = 20
|
||||||
table = [[0] * cols for i in range(rows)]
|
table = [[0] * cols for i in range(rows)]
|
||||||
finder = FinderTest(table)
|
finder = FinderTest(table)
|
||||||
finder.fillRandom()
|
finder.fillRandom()
|
||||||
originXY = finder.getRandomBorderTuple()
|
originXY = finder.getRandomBorderTuple()
|
||||||
targetXY = finder.getRandomBorderTuple()
|
targetXY = finder.getRandomBorderTuple()
|
||||||
result = finder.getPath(originXY, targetXY, True)
|
result = finder.getPath(originXY, targetXY, True)
|
||||||
finder.print(result)
|
finder.print(result)
|
||||||
|
@ -1,34 +1,40 @@
|
|||||||
from math import sqrt
|
from math import sqrt
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
|
|
||||||
def __init__(self, parent, x, y, distance):
|
def __init__(self, parent, x, y, distance):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.distance = distance
|
self.distance = distance
|
||||||
self.estimated = distance
|
self.estimated = distance
|
||||||
|
|
||||||
# returns distance from the object to other node
|
# returns distance from the object to other node
|
||||||
def getDistanceTo(self, other):
|
def getDistanceTo(self, other):
|
||||||
dx = self.x - other.x
|
dx = self.x - other.x
|
||||||
dy = self.y - other.y
|
dy = self.y - other.y
|
||||||
return sqrt(dx * dx + dy * dy)
|
return sqrt(dx * dx + dy * dy)
|
||||||
# abs(dx) + abs(dy)
|
# abs(dx) + abs(dy)
|
||||||
|
|
||||||
# used by str() method to represent the object
|
def getDirection(self):
|
||||||
def __repr__(self):
|
if self.parent is None:
|
||||||
return "%s:%s" % (self.x, self.y)
|
return 0, 0
|
||||||
|
else:
|
||||||
# generates hash key for Set
|
return self.x - self.parent.x, self.y - self.parent.y
|
||||||
def __hash__(self):
|
|
||||||
return hash(str(self))
|
# used by str() method to represent the object
|
||||||
|
def __repr__(self):
|
||||||
# operator (==) for Set (determines if the object equals other node)
|
return "%s:%s" % (self.x, self.y)
|
||||||
def __eq__(self, other):
|
|
||||||
return (self.x == other.x) and (self.y == other.y)
|
# generates hash key for Set
|
||||||
|
def __hash__(self):
|
||||||
# operator (>) for PriorityQueue comparison (determines the objects order)
|
return hash(str(self))
|
||||||
def __gt__(self, other):
|
|
||||||
return self.estimated > other.estimated
|
# 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
|
||||||
|
@ -10,10 +10,10 @@ class Drawable:
|
|||||||
self.__maxX = maxX
|
self.__maxX = maxX
|
||||||
self.__minY = minY
|
self.__minY = minY
|
||||||
self.__maxY = maxY
|
self.__maxY = maxY
|
||||||
self.setX(x)
|
self.__x = x
|
||||||
self.setY(y)
|
self.__y = y
|
||||||
self.__cellSize = cellSize # cell size in pixels
|
self.__cellSize = cellSize # cell size in pixels
|
||||||
self.__offset = offset # paint offset 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:
|
||||||
|
@ -1,18 +1,35 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
from kelner.src.components.Drawable import Drawable
|
from kelner.src.components.Drawable import Drawable
|
||||||
from kelner.src.managers.ImageCache import ImageCache, Images
|
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||||
|
|
||||||
|
class Direction:
|
||||||
|
LeftUp = (-1,-1)
|
||||||
|
Up = ( 0,-1)
|
||||||
|
RightUp = ( 1,-1)
|
||||||
|
Right = ( 1, 0)
|
||||||
|
RightDown = ( 1, 1)
|
||||||
|
Down = ( 0, 1)
|
||||||
|
LeftDown = (-1, 1)
|
||||||
|
Left = (-1, 0)
|
||||||
|
|
||||||
|
|
||||||
class Waiter(Drawable):
|
class Waiter(Drawable):
|
||||||
|
|
||||||
def __init__(self, x, y, minX, maxX, minY, maxY, ratio, offset):
|
def __init__(self, x, y, minX, maxX, minY, maxY, ratio, offset):
|
||||||
# call base class constructor
|
# call base class constructor
|
||||||
super().__init__(x, y, minX, maxX, minY, maxY, ratio, offset)
|
super().__init__(x, y, minX, maxX, minY, maxY, ratio, offset)
|
||||||
|
self.__dx = Direction.Down[0]
|
||||||
|
self.__dy = Direction.Down[1]
|
||||||
self.__acceptedOrders = []
|
self.__acceptedOrders = []
|
||||||
self.__currentPath = []
|
self.__currentPath = []
|
||||||
|
|
||||||
def moveUp(self):
|
def moveUp(self):
|
||||||
if self.getY() > self.getMinY():
|
if self.getY() > self.getMinY():
|
||||||
self.setY(self.getY() - 1)
|
self.setY(self.getY() - 1)
|
||||||
|
self.setX(self.getX())
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -20,6 +37,7 @@ class Waiter(Drawable):
|
|||||||
def moveDown(self):
|
def moveDown(self):
|
||||||
if self.getY() < self.getMaxY():
|
if self.getY() < self.getMaxY():
|
||||||
self.setY(self.getY() + 1)
|
self.setY(self.getY() + 1)
|
||||||
|
self.setX(self.getX())
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -27,6 +45,7 @@ class Waiter(Drawable):
|
|||||||
def moveLeft(self):
|
def moveLeft(self):
|
||||||
if self.getX() > self.getMinX():
|
if self.getX() > self.getMinX():
|
||||||
self.setX(self.getX() - 1)
|
self.setX(self.getX() - 1)
|
||||||
|
self.setY(self.getY())
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -34,10 +53,56 @@ class Waiter(Drawable):
|
|||||||
def moveRight(self):
|
def moveRight(self):
|
||||||
if self.getX() < self.getMaxX():
|
if self.getX() < self.getMaxX():
|
||||||
self.setX(self.getX() + 1)
|
self.setX(self.getX() + 1)
|
||||||
|
self.setY(self.getY())
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def setX(self, x):
|
||||||
|
oldX = self.getX()
|
||||||
|
if super().setX(x):
|
||||||
|
self.__dx = x - oldX
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def setY(self, y):
|
||||||
|
oldY = self.getY()
|
||||||
|
if super().setY(y):
|
||||||
|
self.__dy = y - oldY
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def getDirection(self):
|
||||||
|
return self.__dx, self.__dy
|
||||||
|
|
||||||
|
def setDirection(self, dx, dy):
|
||||||
|
self.__dx = dx
|
||||||
|
self.__dy = dy
|
||||||
|
|
||||||
|
def getNextDirection(self, oldDirectionXY, newDirectionXY, isDiagonal):
|
||||||
|
if oldDirectionXY == (0, 0) or oldDirectionXY == newDirectionXY:
|
||||||
|
return None
|
||||||
|
if 0 == oldDirectionXY[0]:
|
||||||
|
if 0 == newDirectionXY[0]:
|
||||||
|
return random.choice([-1, 1]), oldDirectionXY[1] if isDiagonal else 0
|
||||||
|
else:
|
||||||
|
dx = newDirectionXY[0] - oldDirectionXY[0]
|
||||||
|
return +1 if dx > 0 else -1, oldDirectionXY[1] if isDiagonal else 0
|
||||||
|
if 0 == oldDirectionXY[1]:
|
||||||
|
if 0 == newDirectionXY[1]:
|
||||||
|
return oldDirectionXY[0] if isDiagonal else 0, random.choice([-1, 1])
|
||||||
|
else:
|
||||||
|
dy = newDirectionXY[1] - oldDirectionXY[1]
|
||||||
|
return oldDirectionXY[0] if isDiagonal else 0, +1 if dy > 0 else -1
|
||||||
|
if 0 == oldDirectionXY[0] + newDirectionXY[0] and 0 == oldDirectionXY[1] + newDirectionXY[1]:
|
||||||
|
return random.choice([(oldDirectionXY[0], 0), (0, oldDirectionXY[1])])
|
||||||
|
else:
|
||||||
|
dx = newDirectionXY[0] - oldDirectionXY[0]
|
||||||
|
dy = newDirectionXY[1] - oldDirectionXY[1]
|
||||||
|
return (0, oldDirectionXY[1]) if abs(dx) > abs(dy) else (oldDirectionXY[0], 0)
|
||||||
|
|
||||||
# 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())]
|
||||||
@ -52,7 +117,47 @@ class Waiter(Drawable):
|
|||||||
return self.__currentPath.pop(0)
|
return self.__currentPath.pop(0)
|
||||||
|
|
||||||
def draw(self, screen):
|
def draw(self, screen):
|
||||||
imageWaiter = ImageCache.getInstance().getImage(Images.Waiter, self.getCellSize(), self.getCellSize())
|
direction = self.getDirection()
|
||||||
xBase = self.getX() * self.getCellSize() + self.getOffset()
|
imageKind = None
|
||||||
yBase = self.getY() * self.getCellSize() + self.getOffset()
|
if direction == Direction.LeftUp:
|
||||||
screen.blit(imageWaiter, (xBase, yBase))
|
imageKind = Images.WaiterLeftUp
|
||||||
|
elif direction == Direction.Up:
|
||||||
|
imageKind = Images.WaiterUp
|
||||||
|
elif direction == Direction.RightUp:
|
||||||
|
imageKind = Images.WaiterRightUp
|
||||||
|
elif direction == Direction.Right:
|
||||||
|
imageKind = Images.WaiterRight
|
||||||
|
elif direction == Direction.RightDown:
|
||||||
|
imageKind = Images.WaiterRightDown
|
||||||
|
elif direction == Direction.Down:
|
||||||
|
imageKind = Images.WaiterDown
|
||||||
|
elif direction == Direction.LeftDown:
|
||||||
|
imageKind = Images.WaiterLeftDown
|
||||||
|
elif direction == Direction.Left:
|
||||||
|
imageKind = Images.WaiterLeft
|
||||||
|
|
||||||
|
imageWaiter = ImageCache.getInstance().getImage(imageKind, self.getCellSize(), self.getCellSize())
|
||||||
|
self.__xBase = self.getX() * self.getCellSize() + self.getOffset()
|
||||||
|
self.__yBase = self.getY() * self.getCellSize() + self.getOffset()
|
||||||
|
screen.blit(imageWaiter, (self.__xBase, self.__yBase))
|
||||||
|
|
||||||
|
def drawAux(self, screen):
|
||||||
|
toolTipWidth = int(0.4 * self.getCellSize())
|
||||||
|
toolTipHeight = int(0.2 * self.getCellSize())
|
||||||
|
toolTipXOffset = int(0.6 * self.getCellSize())
|
||||||
|
toolTipYOffset = - int(0.1 * self.getCellSize())
|
||||||
|
|
||||||
|
imageToolTip = ImageCache.getInstance().getImage(Images.ToolTip, toolTipWidth, toolTipHeight)
|
||||||
|
screen.blit(imageToolTip, (self.__xBase + toolTipXOffset, self.__yBase + toolTipYOffset))
|
||||||
|
|
||||||
|
font = pygame.font.SysFont('comicsansms', 24, True)
|
||||||
|
imageText = font.render(str(len(self.__acceptedOrders)), True, (204, 0, 0))
|
||||||
|
size = imageText.get_size()
|
||||||
|
ratio = 0.9 * toolTipHeight
|
||||||
|
textWidth = int((ratio / size[1]) * size[0])
|
||||||
|
textHeight = int(ratio)
|
||||||
|
imageText = pygame.transform.scale(imageText, (textWidth, textHeight))
|
||||||
|
|
||||||
|
textXOffset = toolTipXOffset + int((toolTipWidth - textWidth) / 2)
|
||||||
|
textYOffset = toolTipYOffset + int(0.05 * toolTipHeight)
|
||||||
|
screen.blit(imageText, (self.__xBase + textXOffset, self.__yBase + textYOffset))
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
from kelner.src.components.Table import Table, Status
|
from kelner.src.components.Table import Table, Status
|
||||||
from kelner.src.components.Waiter import Waiter
|
from kelner.src.components.Waiter import Waiter
|
||||||
|
|
||||||
@ -6,13 +8,15 @@ from kelner.src.components.Waiter import Waiter
|
|||||||
# drawable objects manager
|
# drawable objects manager
|
||||||
class DrawableCollection:
|
class DrawableCollection:
|
||||||
# const, minimal distance between objects
|
# const, minimal distance between objects
|
||||||
__MinDistanceX = 0
|
__MinDistanceX = 1
|
||||||
__MinDistanceY = 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.__mustRepaint = True
|
||||||
self.__drawables = []
|
self.__drawables = []
|
||||||
|
self.__waiterLock = Lock()
|
||||||
|
self.__tableLock = Lock()
|
||||||
|
|
||||||
# adds drawable objects to the collection
|
# adds drawable objects to the collection
|
||||||
def add(self, drawable):
|
def add(self, drawable):
|
||||||
@ -21,6 +25,7 @@ class DrawableCollection:
|
|||||||
# 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
|
||||||
|
attempt = 0
|
||||||
while not isPositionUnique:
|
while not isPositionUnique:
|
||||||
x = random.randint(drawable.getMinX() + 1, drawable.getMaxX() - 1)
|
x = random.randint(drawable.getMinX() + 1, drawable.getMaxX() - 1)
|
||||||
y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1)
|
y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1)
|
||||||
@ -32,6 +37,11 @@ class DrawableCollection:
|
|||||||
if isPositionUnique:
|
if isPositionUnique:
|
||||||
drawable.setX(x)
|
drawable.setX(x)
|
||||||
drawable.setY(y)
|
drawable.setY(y)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
attempt += 1
|
||||||
|
if attempt > 40:
|
||||||
|
return False
|
||||||
|
|
||||||
# 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):
|
def isPositionAvailable(self, x, y):
|
||||||
@ -58,17 +68,6 @@ class DrawableCollection:
|
|||||||
result += [item]
|
result += [item]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# waiter collects orders from all nearest tables
|
|
||||||
def collectOrders(self):
|
|
||||||
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()
|
|
||||||
|
|
||||||
# returns table: 0 - position is available, 1 - position is occupied
|
# returns table: 0 - position is available, 1 - position is occupied
|
||||||
def getReservedPlaces(self, waiter):
|
def getReservedPlaces(self, waiter):
|
||||||
cols = waiter.getMaxX() - waiter.getMinX() + 1
|
cols = waiter.getMaxX() - waiter.getMinX() + 1
|
||||||
@ -78,8 +77,51 @@ class DrawableCollection:
|
|||||||
if tables:
|
if tables:
|
||||||
for table in tables:
|
for table in tables:
|
||||||
reservedPlaces[table.getY()][table.getX()] = 1
|
reservedPlaces[table.getY()][table.getX()] = 1
|
||||||
|
waiters = self.getWaiters()
|
||||||
|
if waiters:
|
||||||
|
for other in waiters:
|
||||||
|
if other is not waiter:
|
||||||
|
reservedPlaces[other.getY()][other.getX()] = 1
|
||||||
return reservedPlaces
|
return reservedPlaces
|
||||||
|
|
||||||
|
def getNearestTables(self, waiter, tableStatus):
|
||||||
|
nearestTables = []
|
||||||
|
tables = self.getTables(tableStatus)
|
||||||
|
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):
|
||||||
|
nearestTables.append(table)
|
||||||
|
return nearestTables
|
||||||
|
|
||||||
|
# waiter collects orders from table
|
||||||
|
def collectOrder(self, waiter, table):
|
||||||
|
result = False
|
||||||
|
self.__tableLock.acquire()
|
||||||
|
try:
|
||||||
|
if table.isStatus(Status.Ready) and table.getOrder() != []:
|
||||||
|
waiter.addOrder(table)
|
||||||
|
table.delOrder()
|
||||||
|
result = True
|
||||||
|
finally:
|
||||||
|
self.__tableLock.release()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def moveWaiter(self, someWaiter, x, y):
|
||||||
|
isPositionAvailable = True
|
||||||
|
waiters = self.getWaiters()
|
||||||
|
self.__waiterLock.acquire()
|
||||||
|
try:
|
||||||
|
for waiter in waiters:
|
||||||
|
if waiter is not someWaiter:
|
||||||
|
if waiter.getX() == x and waiter.getY() == y:
|
||||||
|
isPositionAvailable = False
|
||||||
|
break
|
||||||
|
if isPositionAvailable:
|
||||||
|
someWaiter.setX(x)
|
||||||
|
someWaiter.setY(y)
|
||||||
|
finally:
|
||||||
|
self.__waiterLock.release()
|
||||||
|
|
||||||
# the method is called externally and forces repainting
|
# the method is called externally and forces repainting
|
||||||
def forceRepaint(self):
|
def forceRepaint(self):
|
||||||
self.__mustRepaint = True
|
self.__mustRepaint = True
|
||||||
|
@ -1,50 +1,66 @@
|
|||||||
import pygame
|
import pygame
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
# images enum
|
# images enum
|
||||||
class Images(Enum):
|
class Images(Enum):
|
||||||
Background = 0
|
Background = 0
|
||||||
Waiter = 1
|
WaiterLeftUp = 1
|
||||||
Table = 2
|
WaiterUp = 2
|
||||||
Menu = 3
|
WaiterRightUp = 3
|
||||||
Check = 4
|
WaiterRight = 4
|
||||||
Plate = 5
|
WaiterRightDown = 5
|
||||||
Guest1 = 6
|
WaiterDown = 6
|
||||||
Guest2 = 7
|
WaiterLeftDown = 7
|
||||||
Guest3 = 8
|
WaiterLeft = 8
|
||||||
|
Table = 9
|
||||||
|
Menu = 10
|
||||||
class ImageCache:
|
Check = 11
|
||||||
__instance = None
|
Plate = 12
|
||||||
|
Guest1 = 13
|
||||||
@staticmethod
|
Guest2 = 14
|
||||||
def getInstance():
|
Guest3 = 15
|
||||||
if ImageCache.__instance is None:
|
ToolTip = 16
|
||||||
ImageCache()
|
|
||||||
return ImageCache.__instance
|
|
||||||
|
class ImageCache:
|
||||||
def __init__(self):
|
__instance = None
|
||||||
""" Virtually private constructor. """
|
|
||||||
if ImageCache.__instance is not None:
|
@staticmethod
|
||||||
raise Exception("This class is a singleton!")
|
def getInstance():
|
||||||
else:
|
if ImageCache.__instance is None:
|
||||||
ImageCache.__instance = self
|
ImageCache()
|
||||||
self.__images = {}
|
return ImageCache.__instance
|
||||||
self.__paths = {Images.Background: './images/Backgroud.png',
|
|
||||||
Images.Waiter: './images/kelner.png',
|
def __init__(self):
|
||||||
Images.Table: './images/stol.png',
|
""" Virtually private constructor. """
|
||||||
Images.Menu: './images/ksiazka.png',
|
if ImageCache.__instance is not None:
|
||||||
Images.Check: './images/check.png',
|
raise Exception("This class is a singleton!")
|
||||||
Images.Plate: './images/plate.png',
|
else:
|
||||||
Images.Guest1: './images/wiking_blond.png',
|
ImageCache.__instance = self
|
||||||
Images.Guest2: './images/wiking_rudy.png',
|
self.__images = {}
|
||||||
Images.Guest3: './images/wiking_rudy2.png'}
|
self.__paths = {Images.Background: './images/Backgroud.png',
|
||||||
|
Images.WaiterLeftUp: './images/kelner_full_LU.png',
|
||||||
def getImage(self, imageKind, width, height):
|
Images.WaiterUp: './images/kelner_full_U.png',
|
||||||
key = str(imageKind.value) + ':' + str(width) + ':' + str(height)
|
Images.WaiterRightUp: './images/kelner_full_RU.png',
|
||||||
image = self.__images.get(key, None)
|
Images.WaiterRight: './images/kelner_full_R.png',
|
||||||
if image is None:
|
Images.WaiterRightDown: './images/kelner_full_RD.png',
|
||||||
image = pygame.transform.scale((pygame.image.load(self.__paths[imageKind])), (width, height))
|
Images.WaiterDown: './images/kelner_full_D.png',
|
||||||
self.__images[key] = image
|
Images.WaiterLeftDown: './images/kelner_full_LD.png',
|
||||||
return image
|
Images.WaiterLeft: './images/kelner_full_L.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',
|
||||||
|
Images.ToolTip: './images/tooltip.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,29 +1,29 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import random
|
import random
|
||||||
from kelner.src.components.Table import Status
|
from kelner.src.components.Table import Status
|
||||||
|
|
||||||
|
|
||||||
# creates new thread
|
# creates new thread
|
||||||
class TableManager (threading.Thread):
|
class TableManager (threading.Thread):
|
||||||
|
|
||||||
def __init__(self, drawableManager, menuManager):
|
def __init__(self, drawableManager, menuManager):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__drawableManager = drawableManager
|
self.__drawableManager = drawableManager
|
||||||
self.__menuManager = menuManager
|
self.__menuManager = menuManager
|
||||||
self.__runThread = True
|
self.__runThread = True
|
||||||
|
|
||||||
# changes the status of a random table from NotReady to Ready
|
# changes the status of a random table from NotReady to Ready
|
||||||
def run(self):
|
def run(self):
|
||||||
while self.__runThread:
|
while self.__runThread:
|
||||||
tables = self.__drawableManager.getTables(Status.NotReady)
|
tables = self.__drawableManager.getTables(Status.NotReady)
|
||||||
if tables:
|
if tables:
|
||||||
tableIndex = random.randint(0, len(tables) - 1)
|
tableIndex = random.randint(0, len(tables) - 1)
|
||||||
table = tables[tableIndex]
|
table = tables[tableIndex]
|
||||||
time.sleep(3)
|
time.sleep(1)
|
||||||
table.setStatus(Status.Ready)
|
table.setStatus(Status.Ready)
|
||||||
table.setOrder(self.__menuManager.generateOrder())
|
table.setOrder(self.__menuManager.generateOrder())
|
||||||
self.__drawableManager.forceRepaint()
|
self.__drawableManager.forceRepaint()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.__runThread = False
|
self.__runThread = False
|
||||||
|
@ -1,60 +1,96 @@
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
from kelner.src.components.Table import Status
|
from kelner.src.components.Table import Status
|
||||||
from kelner.src.algorithms.AStar.Finder import Finder
|
from kelner.src.algorithms.AStar.Finder import Finder
|
||||||
from kelner.src.algorithms.BFS.BFS import BFS
|
from kelner.src.algorithms.BFS.BFS import BFS
|
||||||
|
|
||||||
|
|
||||||
# creates new thread
|
# creates new thread
|
||||||
class WaiterManager (threading.Thread):
|
class WaiterManager (threading.Thread):
|
||||||
|
|
||||||
def __init__(self, drawableManager):
|
def __init__(self, drawableManager, waiters):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.__drawableManager = drawableManager
|
self.__drawableManager = drawableManager
|
||||||
self.__runThread = True
|
self.__waiters = waiters
|
||||||
|
self.__runThread = True
|
||||||
def __getNearestTargetPath(self, waiter):
|
|
||||||
distance = sys.maxsize
|
def __getNearestTargetPath(self, waiter):
|
||||||
nearestTargetPath = None
|
distance = sys.maxsize
|
||||||
tables = self.__drawableManager.getTables(Status.Ready)
|
nearestTargetPath = None
|
||||||
if tables:
|
tables = self.__drawableManager.getTables(Status.Ready)
|
||||||
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
|
if tables:
|
||||||
finder = Finder(reservedPlaces)
|
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
|
||||||
# bfs = BFS(reservedPlaces)
|
finder = Finder(reservedPlaces)
|
||||||
origin = (waiter.getX(), waiter.getY())
|
# bfs = BFS(reservedPlaces)
|
||||||
for table in tables:
|
origin = (waiter.getX(), waiter.getY())
|
||||||
targets = finder.getNeighbours((table.getX(), table.getY()), False)
|
for table in tables:
|
||||||
for target in targets:
|
targets = finder.getNeighbours((table.getX(), table.getY()), False)
|
||||||
if target is not None:
|
for target in targets:
|
||||||
# path = bfs.find_path(origin, target)
|
if target is not None:
|
||||||
path = finder.getPath(origin, target, True)
|
# path = bfs.find_path(origin, target)
|
||||||
if path:
|
path = finder.getPath(origin, target, True)
|
||||||
result = len(path)
|
if path:
|
||||||
if result < distance:
|
result = len(path)
|
||||||
distance = result
|
if result < distance:
|
||||||
nearestTargetPath = path
|
distance = result
|
||||||
return nearestTargetPath
|
nearestTargetPath = path
|
||||||
|
return nearestTargetPath
|
||||||
# changes the status of a random table from NotReady to Ready
|
|
||||||
def run(self):
|
def __changeWaiterDirection(self, waiter, x, y):
|
||||||
while self.__runThread:
|
targetDirection = x - waiter.getX(), y - waiter.getY()
|
||||||
waiters = self.__drawableManager.getWaiters()
|
originDirection = waiter.getDirection()
|
||||||
if waiters:
|
while originDirection is not None:
|
||||||
for waiter in waiters:
|
originDirection = waiter.getNextDirection(originDirection, targetDirection, True)
|
||||||
path = self.__getNearestTargetPath(waiter)
|
if originDirection is not None:
|
||||||
if path is not None:
|
time.sleep(0.3)
|
||||||
waiter.setPath(path)
|
waiter.setDirection(originDirection[0], originDirection[1])
|
||||||
if not waiter.isPathEmpty():
|
self.__drawableManager.forceRepaint()
|
||||||
step = waiter.popStepFromPath()
|
|
||||||
time.sleep(0.4)
|
def __moveWaiter(self, waiter, x, y):
|
||||||
waiter.setX(step[0])
|
time.sleep(0.4)
|
||||||
waiter.setY(step[1])
|
self.__drawableManager.moveWaiter(waiter, x, y)
|
||||||
self.__drawableManager.forceRepaint()
|
self.__drawableManager.forceRepaint()
|
||||||
if waiter.isPathEmpty():
|
|
||||||
time.sleep(2)
|
def __collectOrder(self, waiter):
|
||||||
self.__drawableManager.collectOrders()
|
doCollectOrder = True
|
||||||
self.__drawableManager.forceRepaint()
|
while doCollectOrder:
|
||||||
|
tables = self.__drawableManager.getNearestTables(waiter, Status.Ready)
|
||||||
def stop(self):
|
turns = sys.maxsize
|
||||||
self.__runThread = False
|
lessTurnsTable = None
|
||||||
|
originDirection = waiter.getDirection()
|
||||||
|
|
||||||
|
for table in tables:
|
||||||
|
targetDirection = table.getX() - waiter.getX(), table.getY() - waiter.getY()
|
||||||
|
result = Finder.getTurnsCount(originDirection, targetDirection, True)
|
||||||
|
if result < turns:
|
||||||
|
turns = result
|
||||||
|
lessTurnsTable = table
|
||||||
|
|
||||||
|
if lessTurnsTable is not None:
|
||||||
|
tables.remove(lessTurnsTable)
|
||||||
|
self.__changeWaiterDirection(waiter, lessTurnsTable.getX(), lessTurnsTable.getY())
|
||||||
|
if self.__drawableManager.collectOrder(waiter, lessTurnsTable):
|
||||||
|
time.sleep(2)
|
||||||
|
lessTurnsTable.setStatus(Status.Waiting)
|
||||||
|
self.__drawableManager.forceRepaint()
|
||||||
|
doCollectOrder = len(tables) > 0
|
||||||
|
|
||||||
|
# changes the status of a random table from NotReady to Ready
|
||||||
|
def run(self):
|
||||||
|
while self.__runThread:
|
||||||
|
if self.__waiters:
|
||||||
|
for waiter in self.__waiters:
|
||||||
|
path = self.__getNearestTargetPath(waiter)
|
||||||
|
waiter.setPath([] if path is None else path)
|
||||||
|
|
||||||
|
if not waiter.isPathEmpty():
|
||||||
|
step = waiter.popStepFromPath()
|
||||||
|
self.__changeWaiterDirection(waiter, step[0], step[1])
|
||||||
|
self.__moveWaiter(waiter, step[0], step[1])
|
||||||
|
|
||||||
|
if waiter.isPathEmpty():
|
||||||
|
self.__collectOrder(waiter)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.__runThread = False
|
||||||
|