merged with master, conflicts resolved
1
.gitignore
vendored
@ -30,6 +30,7 @@ share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
.idea
|
||||
|
||||
/idea/workspace.xml
|
||||
MANIFEST
|
||||
|
2
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
11
.idea/ProjektAI.iml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
|
||||
</component>
|
||||
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
7
.idea/misc.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
|
||||
</project>
|
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/ProjektAI.iml" filepath="$PROJECT_DIR$/.idea/ProjektAI.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
BIN
Raport - _Automatyczny kelner_.pdf
Normal file
@ -1,131 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="4be2149b-d9bc-4e21-8365-293320ae7f92" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Python Script" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
|
||||
</component>
|
||||
<component name="ProjectId" id="1ZSC25l5bE6jvUIMcW31QzsqTTN" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="PropertiesComponent">
|
||||
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="settings.editor.selected.configurable" value="settings.github" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="J:\PycharmProjects\kelner\src\components" />
|
||||
<recent name="J:\PycharmProjects\kelner\images" />
|
||||
<recent name="J:\PycharmProjects\kelner" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="main" type="PythonConfigurationType" factoryName="Python" temporary="true">
|
||||
<module name="kelner" />
|
||||
<option name="INTERPRETER_OPTIONS" value="" />
|
||||
<option name="PARENT_ENVS" value="true" />
|
||||
<envs>
|
||||
<env name="PYTHONUNBUFFERED" value="1" />
|
||||
</envs>
|
||||
<option name="SDK_HOME" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="IS_MODULE_SDK" value="true" />
|
||||
<option name="ADD_CONTENT_ROOTS" value="true" />
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="SHOW_COMMAND_LINE" value="false" />
|
||||
<option name="EMULATE_TERMINAL" value="false" />
|
||||
<option name="MODULE_MODE" value="false" />
|
||||
<option name="REDIRECT_INPUT" value="false" />
|
||||
<option name="INPUT_FILE" value="" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Python.main" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="4be2149b-d9bc-4e21-8365-293320ae7f92" name="Default Changelist" comment="" />
|
||||
<created>1584822897275</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1584822897275</updated>
|
||||
<workItem from="1584822899496" duration="10270000" />
|
||||
<workItem from="1584835781926" duration="189000" />
|
||||
<workItem from="1584889217128" duration="20738000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="klasa kelner">
|
||||
<created>1584889744892</created>
|
||||
<option name="number" value="00001" />
|
||||
<option name="presentableId" value="LOCAL-00001" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1584889744892</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00002" summary="klasa kelner">
|
||||
<created>1584910332507</created>
|
||||
<option name="number" value="00002" />
|
||||
<option name="presentableId" value="LOCAL-00002" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1584910332507</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="3" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="klasa kelner" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="klasa kelner" />
|
||||
</component>
|
||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||
<SUITE FILE_PATH="coverage/kelner$main.coverage" NAME="main Coverage Results" MODIFIED="1584910144126" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||
</component>
|
||||
</project>
|
Before Width: | Height: | Size: 88 KiB |
BIN
kelner/images/Backgroud.png
Normal file
After Width: | Height: | Size: 258 KiB |
BIN
kelner/images/Untitleda.png
Normal file
After Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 156 KiB |
BIN
kelner/images/check.png
Normal file
After Width: | Height: | Size: 359 B |
BIN
kelner/images/drive-download-20200405T181945Z-001.zip
Normal file
BIN
kelner/images/kelner.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
kelner/images/ksiazka.png
Normal file
After Width: | Height: | Size: 428 B |
BIN
kelner/images/kurczak.png
Normal file
After Width: | Height: | Size: 850 B |
BIN
kelner/images/piwo.png
Normal file
After Width: | Height: | Size: 426 B |
BIN
kelner/images/plate.png
Normal file
After Width: | Height: | Size: 657 B |
BIN
kelner/images/srcWaiter.png
Normal file
After Width: | Height: | Size: 155 KiB |
BIN
kelner/images/stol.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 18 KiB |
BIN
kelner/images/wiking_blond.png
Normal file
After Width: | Height: | Size: 832 B |
BIN
kelner/images/wiking_rudy.png
Normal file
After Width: | Height: | Size: 833 B |
BIN
kelner/images/wiking_rudy2.png
Normal file
After Width: | Height: | Size: 832 B |
@ -1,44 +1,83 @@
|
||||
import pygame
|
||||
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
|
||||
|
||||
from src.components.GridBoard import GridBoard
|
||||
from src.components.Waiter import Waiter
|
||||
# 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, ScreenHeight)
|
||||
|
||||
#create screen consts
|
||||
CellSize = 50 #pixel size of 1 square cell in the grid
|
||||
GridCountX = 15 #number of columns in grid
|
||||
GridCountY = 11 #number of rows in grid
|
||||
ScreenWidth = CellSize * GridCountX #screen width in pixels
|
||||
ScreenHeight = CellSize * GridCountY #screen height in pixels
|
||||
# initialize drawable objects manager
|
||||
drawableManager = DrawableCollection()
|
||||
|
||||
#initialize background
|
||||
gridBoard = GridBoard(ScreenWidth, ScreenHeight, CellSize)
|
||||
# initialize menu manager
|
||||
menuManager = MenuManager()
|
||||
|
||||
#initialize waiter component
|
||||
waiter = Waiter(1, 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize)
|
||||
#
|
||||
#loop
|
||||
doRepaint = True
|
||||
# initialize waiter component
|
||||
waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||
|
||||
# adds waiter to drawable collection
|
||||
drawableManager.add(waiter)
|
||||
|
||||
# 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)
|
||||
|
||||
# new thread controlling tables
|
||||
tableTask = TableManager(drawableManager, menuManager)
|
||||
tableTask.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
|
||||
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
|
||||
if drawableManager.isPositionAvailable(waiter.getX() - 1, waiter.getY()):
|
||||
waiter.moveLeft()
|
||||
if event.key == pygame.K_RIGHT:
|
||||
# checks if new waiter's position to the right is not occupied by other object
|
||||
if drawableManager.isPositionAvailable(waiter.getX() + 1, waiter.getY()):
|
||||
waiter.moveRight()
|
||||
if event.key == pygame.K_UP:
|
||||
# checks if new waiter's position up is not occupied by other object
|
||||
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() - 1):
|
||||
waiter.moveUp()
|
||||
if event.key == pygame.K_DOWN:
|
||||
# checks if new waiter's position down is not occupied by other object
|
||||
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() + 1):
|
||||
waiter.moveDown()
|
||||
doRepaint = True
|
||||
drawableManager.forceRepaint()
|
||||
|
||||
if doRepaint:
|
||||
# repaints all objects to the screen
|
||||
# is set only on initial paint or after keyboard event or call to forceRepaint()
|
||||
if drawableManager.mustRepaint():
|
||||
gridBoard.reinitialize()
|
||||
gridBoard.draw(waiter)
|
||||
gridBoard.draw(drawableManager)
|
||||
gridBoard.udpdate()
|
||||
doRepaint = False
|
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
|
63
kelner/src/components/Drawable.py
Normal file
@ -0,0 +1,63 @@
|
||||
class Drawable:
|
||||
|
||||
GREY = (128, 128, 128)
|
||||
YELLOW = (255, 255, 0)
|
||||
RED = (255, 0, 0)
|
||||
GREEN = (0, 255, 0)
|
||||
|
||||
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.__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:
|
||||
return False
|
||||
else:
|
||||
self.__x = x
|
||||
return True
|
||||
|
||||
def setY(self, 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
|
||||
|
||||
def getY(self):
|
||||
return self.__y
|
||||
|
||||
def getMinX(self):
|
||||
return self.__minX
|
||||
|
||||
def getMaxX(self):
|
||||
return self.__maxX
|
||||
|
||||
def getMinY(self):
|
||||
return self.__minY
|
||||
|
||||
def getMaxY(self):
|
||||
return self.__maxY
|
||||
|
||||
def getCellSize(self):
|
||||
return self.__cellSize
|
||||
|
||||
def getOffset(self):
|
||||
return self.__offset
|
||||
|
||||
def draw(self, screen):
|
||||
pass
|
||||
|
||||
def drawAux(self, screen):
|
||||
pass
|
@ -1,24 +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.__screen = pygame.display.set_mode((width, height)) # initialize screen
|
||||
|
||||
# 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
|
||||
def draw(self, component):
|
||||
component.draw(self.__screen)
|
||||
|
||||
# updates screen
|
||||
def udpdate(self):
|
||||
pygame.display.update()
|
100
kelner/src/components/Table.py
Normal file
@ -0,0 +1,100 @@
|
||||
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, offset):
|
||||
# call base class constructor
|
||||
super().__init__(0, 0, minX, maxX, minY, maxY, ratio, offset)
|
||||
self.__status = Status.NotReady
|
||||
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
|
||||
|
||||
def getOrder(self):
|
||||
return self.__order
|
||||
|
||||
def delOrder(self):
|
||||
self.setOrder([])
|
||||
|
||||
def isStatus(self, status):
|
||||
return status == self.__status
|
||||
|
||||
def setStatus(self, status):
|
||||
self.__status = status
|
||||
|
||||
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,68 +1,58 @@
|
||||
import pygame
|
||||
from kelner.src.components.Drawable import Drawable
|
||||
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||
|
||||
|
||||
class Waiter:
|
||||
class Waiter(Drawable):
|
||||
|
||||
def __init__(self, x, y, minX, maxX, minY, maxY, ratio):
|
||||
self.__minX = minX
|
||||
self.__maxX = maxX
|
||||
self.__minY = minY
|
||||
self.__maxY = maxY
|
||||
self.setX(x)
|
||||
self.setY(y)
|
||||
self.__ratio = ratio #cell size
|
||||
self.__image = self.__loadImg('./images/waiter.png')
|
||||
|
||||
def setX(self, 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):
|
||||
return False
|
||||
else:
|
||||
self.__y = y
|
||||
return True
|
||||
|
||||
def getX(self):
|
||||
return self.__x
|
||||
|
||||
def getY(self):
|
||||
return self.__y
|
||||
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.__currentPath = []
|
||||
|
||||
def moveUp(self):
|
||||
if self.__y > self.__minY:
|
||||
self.__y -= 1
|
||||
if self.getY() > self.getMinY():
|
||||
self.setY(self.getY() - 1)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def moveDown(self):
|
||||
if self.__y < self.__maxY:
|
||||
self.__y += 1
|
||||
if self.getY() < self.getMaxY():
|
||||
self.setY(self.getY() + 1)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def moveLeft(self):
|
||||
if self.__x > self.__minX:
|
||||
self.__x -= 1
|
||||
if self.getX() > self.getMinX():
|
||||
self.setX(self.getX() - 1)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def moveRight(self):
|
||||
if self.__x < self.__maxX:
|
||||
self.__x += 1
|
||||
if self.getX() < self.getMaxX():
|
||||
self.setX(self.getX() + 1)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __loadImg(self, filePath):
|
||||
return pygame.image.load(filePath)
|
||||
# accepts orders from the table and stores them in queue
|
||||
def addOrder(self, table):
|
||||
self.__acceptedOrders += [(table, table.getOrder())]
|
||||
|
||||
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.__x * self.__ratio, self.__y * self.__ratio))
|
||||
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))
|
||||
|
97
kelner/src/managers/DrawableCollection.py
Normal file
@ -0,0 +1,97 @@
|
||||
import random
|
||||
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
|
||||
__MinDistanceX = 0
|
||||
__MinDistanceY = 0
|
||||
|
||||
def __init__(self):
|
||||
# collection that holds all drawable objects
|
||||
self.__mustRepaint = True
|
||||
self.__drawables = []
|
||||
|
||||
# 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
|
||||
def generatePosition(self, drawable):
|
||||
isPositionUnique = False
|
||||
while not isPositionUnique:
|
||||
x = random.randint(drawable.getMinX() + 1, drawable.getMaxX() - 1)
|
||||
y = random.randint(drawable.getMinY() + 1, drawable.getMaxY() - 1)
|
||||
isPositionUnique = True
|
||||
for item in self.__drawables:
|
||||
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)
|
||||
|
||||
# checks if position (x,y) is not occupied by other object
|
||||
def isPositionAvailable(self, x, y):
|
||||
isPositionAvailable = True
|
||||
for item in self.__drawables:
|
||||
if item.getX() == x and item.getY() == y:
|
||||
isPositionAvailable = False
|
||||
break
|
||||
return isPositionAvailable
|
||||
|
||||
# gets all tables by status from collection
|
||||
def getTables(self, status):
|
||||
result = []
|
||||
for item in self.__drawables:
|
||||
if status is None or isinstance(item, Table) and item.isStatus(status):
|
||||
result += [item]
|
||||
return result
|
||||
|
||||
# gets all waiters from collection
|
||||
def getWaiters(self):
|
||||
result = []
|
||||
for item in self.__drawables:
|
||||
if isinstance(item, Waiter):
|
||||
result += [item]
|
||||
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
|
||||
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
|
35
kelner/src/managers/MenuManager.py
Normal file
@ -0,0 +1,35 @@
|
||||
import random
|
||||
|
||||
|
||||
# contains all dishes and generates random order for the table
|
||||
class MenuManager:
|
||||
|
||||
# consts, min and max dishes ordered by the people sitting by the same table
|
||||
__MinDishes = 1
|
||||
__MaxDishes = 3
|
||||
|
||||
def __init__(self):
|
||||
self.__menuCard = ["PORK",
|
||||
"FRENCH FRIES",
|
||||
"PIZZA",
|
||||
"CHICKEN",
|
||||
"RIBS",
|
||||
"FISH",
|
||||
"SPAGHETTI",
|
||||
"BEEF",
|
||||
"STEAK",
|
||||
"SALAD",
|
||||
"GRILLED VEGETABLES",
|
||||
"VEAL",
|
||||
"CHOPS",
|
||||
"EMPTY PLATE",
|
||||
"BEER",
|
||||
"CAKE"]
|
||||
|
||||
# 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
|
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
|
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
|