merged with master, conflicts resolved

This commit is contained in:
= 2020-04-27 10:46:59 +02:00
commit 914e9404f0
869 changed files with 1674 additions and 1083 deletions

1
.gitignore vendored
View File

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

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

11
.idea/ProjektAI.iml Normal file
View 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>

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

View File

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

Binary file not shown.

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

BIN
kelner/images/Backgroud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

BIN
kelner/images/Untitleda.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

BIN
kelner/images/check.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

BIN
kelner/images/kelner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
kelner/images/ksiazka.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

BIN
kelner/images/kurczak.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

BIN
kelner/images/piwo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

BIN
kelner/images/plate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

BIN
kelner/images/srcWaiter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
kelner/images/stol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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))

View File

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

View 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

View File

@ -0,0 +1,50 @@
import pygame
from enum import Enum
# images enum
class Images(Enum):
Background = 0
Waiter = 1
Table = 2
Menu = 3
Check = 4
Plate = 5
Guest1 = 6
Guest2 = 7
Guest3 = 8
class ImageCache:
__instance = None
@staticmethod
def getInstance():
if ImageCache.__instance is None:
ImageCache()
return ImageCache.__instance
def __init__(self):
""" Virtually private constructor. """
if ImageCache.__instance is not None:
raise Exception("This class is a singleton!")
else:
ImageCache.__instance = self
self.__images = {}
self.__paths = {Images.Background: './images/Backgroud.png',
Images.Waiter: './images/kelner.png',
Images.Table: './images/stol.png',
Images.Menu: './images/ksiazka.png',
Images.Check: './images/check.png',
Images.Plate: './images/plate.png',
Images.Guest1: './images/wiking_blond.png',
Images.Guest2: './images/wiking_rudy.png',
Images.Guest3: './images/wiking_rudy2.png'}
def getImage(self, imageKind, width, height):
key = str(imageKind.value) + ':' + str(width) + ':' + str(height)
image = self.__images.get(key, None)
if image is None:
image = pygame.transform.scale((pygame.image.load(self.__paths[imageKind])), (width, height))
self.__images[key] = image
return image

View File

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

View File

@ -0,0 +1,29 @@
import threading
import time
import random
from kelner.src.components.Table import Status
# creates new thread
class TableManager (threading.Thread):
def __init__(self, drawableManager, menuManager):
super().__init__()
self.__drawableManager = drawableManager
self.__menuManager = menuManager
self.__runThread = True
# changes the status of a random table from NotReady to Ready
def run(self):
while self.__runThread:
tables = self.__drawableManager.getTables(Status.NotReady)
if tables:
tableIndex = random.randint(0, len(tables) - 1)
table = tables[tableIndex]
time.sleep(3)
table.setStatus(Status.Ready)
table.setOrder(self.__menuManager.generateOrder())
self.__drawableManager.forceRepaint()
def stop(self):
self.__runThread = False

View File

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

Some files were not shown because too many files have changed in this diff Show More