merged with master, conflicts resolved
1
.gitignore
vendored
@ -30,6 +30,7 @@ share/python-wheels/
|
|||||||
*.egg-info/
|
*.egg-info/
|
||||||
.installed.cfg
|
.installed.cfg
|
||||||
*.egg
|
*.egg
|
||||||
|
.idea
|
||||||
|
|
||||||
/idea/workspace.xml
|
/idea/workspace.xml
|
||||||
MANIFEST
|
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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</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
|
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
|
# create screen consts
|
||||||
from src.components.Waiter import Waiter
|
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
|
# initialize drawable objects manager
|
||||||
CellSize = 50 #pixel size of 1 square cell in the grid
|
drawableManager = DrawableCollection()
|
||||||
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 background
|
# initialize menu manager
|
||||||
gridBoard = GridBoard(ScreenWidth, ScreenHeight, CellSize)
|
menuManager = MenuManager()
|
||||||
|
|
||||||
#initialize waiter component
|
# initialize waiter component
|
||||||
waiter = Waiter(1, 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize)
|
waiter = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||||
#
|
|
||||||
#loop
|
# adds waiter to drawable collection
|
||||||
doRepaint = True
|
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
|
running = True
|
||||||
while running:
|
while running:
|
||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
|
tableTask.stop()
|
||||||
|
waiterTask.stop()
|
||||||
running = False
|
running = False
|
||||||
|
|
||||||
|
# handles keyboard events
|
||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.KEYDOWN:
|
||||||
if event.key == pygame.K_LEFT:
|
if event.key == pygame.K_LEFT:
|
||||||
waiter.moveLeft()
|
# 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:
|
if event.key == pygame.K_RIGHT:
|
||||||
waiter.moveRight()
|
# 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:
|
if event.key == pygame.K_UP:
|
||||||
waiter.moveUp()
|
# 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:
|
if event.key == pygame.K_DOWN:
|
||||||
waiter.moveDown()
|
# checks if new waiter's position down is not occupied by other object
|
||||||
doRepaint = True
|
if drawableManager.isPositionAvailable(waiter.getX(), waiter.getY() + 1):
|
||||||
|
waiter.moveDown()
|
||||||
|
drawableManager.forceRepaint()
|
||||||
|
|
||||||
if doRepaint:
|
# repaints all objects to the screen
|
||||||
gridBoard.reinitialize()
|
# is set only on initial paint or after keyboard event or call to forceRepaint()
|
||||||
gridBoard.draw(waiter)
|
if drawableManager.mustRepaint():
|
||||||
gridBoard.udpdate()
|
gridBoard.reinitialize()
|
||||||
doRepaint = False
|
gridBoard.draw(drawableManager)
|
||||||
|
gridBoard.udpdate()
|
||||||
|
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
|
import pygame
|
||||||
|
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||||
|
|
||||||
|
|
||||||
class GridBoard:
|
class GridBoard:
|
||||||
|
|
||||||
def __init__(self, width, height, cellSize):
|
def __init__(self, width, height):
|
||||||
pygame.init() #initialize the pygame
|
pygame.init() # initialize the pygame
|
||||||
pygame.display.set_caption("Bardzo mądry kelner") #window caption
|
pygame.display.set_caption("Bardzo mądry kelner") # window caption
|
||||||
self.__width = width
|
self.__width = width
|
||||||
self.__height = height
|
self.__height = height
|
||||||
self.__cellSize = cellSize
|
self.__screen = pygame.display.set_mode((width, height)) # initialize screen
|
||||||
self.__screen = pygame.display.set_mode((width, height)) #initialize screen
|
|
||||||
|
|
||||||
|
# draws the background
|
||||||
def reinitialize(self):
|
def reinitialize(self):
|
||||||
|
imageBackground = ImageCache.getInstance().getImage(Images.Background, self.__width, self.__height)
|
||||||
|
self.__screen.blit(imageBackground, (0, 0))
|
||||||
|
""" # code below fills the screen with white and draws grid
|
||||||
self.__screen.fill((255, 255, 255))
|
self.__screen.fill((255, 255, 255))
|
||||||
for x in range(0, self.__width, self.__cellSize):
|
for x in range(0, self.__width, self.__cellSize):
|
||||||
pygame.draw.line(self.__screen, (0,0,0), (x,0), (x,(self.__height - 1)))
|
pygame.draw.line(self.__screen, (0,0,0), (x,0), (x,(self.__height - 1)))
|
||||||
for y in range(0, self.__height, self.__cellSize):
|
for y in range(0, self.__height, self.__cellSize):
|
||||||
pygame.draw.line(self.__screen, (0,0,0), (0,y), ((self.__width - 1),y))
|
pygame.draw.line(self.__screen, (0,0,0), (0,y), ((self.__width - 1),y))
|
||||||
|
"""
|
||||||
|
|
||||||
|
# draws object on screen
|
||||||
def draw(self, component):
|
def draw(self, component):
|
||||||
component.draw(self.__screen)
|
component.draw(self.__screen)
|
||||||
|
|
||||||
|
# updates screen
|
||||||
def udpdate(self):
|
def udpdate(self):
|
||||||
pygame.display.update()
|
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):
|
def __init__(self, x, y, minX, maxX, minY, maxY, ratio, offset):
|
||||||
self.__minX = minX
|
# call base class constructor
|
||||||
self.__maxX = maxX
|
super().__init__(x, y, minX, maxX, minY, maxY, ratio, offset)
|
||||||
self.__minY = minY
|
self.__acceptedOrders = []
|
||||||
self.__maxY = maxY
|
self.__currentPath = []
|
||||||
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 moveUp(self):
|
def moveUp(self):
|
||||||
if self.__y > self.__minY:
|
if self.getY() > self.getMinY():
|
||||||
self.__y -= 1
|
self.setY(self.getY() - 1)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def moveDown(self):
|
def moveDown(self):
|
||||||
if self.__y < self.__maxY:
|
if self.getY() < self.getMaxY():
|
||||||
self.__y += 1
|
self.setY(self.getY() + 1)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def moveLeft(self):
|
def moveLeft(self):
|
||||||
if self.__x > self.__minX:
|
if self.getX() > self.getMinX():
|
||||||
self.__x -= 1
|
self.setX(self.getX() - 1)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def moveRight(self):
|
def moveRight(self):
|
||||||
if self.__x < self.__maxX:
|
if self.getX() < self.getMaxX():
|
||||||
self.__x += 1
|
self.setX(self.getX() + 1)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __loadImg(self, filePath):
|
# accepts orders from the table and stores them in queue
|
||||||
return pygame.image.load(filePath)
|
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):
|
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
|