1
0
forked from s444417/ProjektAI

integracja projektu genetycznego generatora stolików

This commit is contained in:
s444417 2020-06-09 23:21:04 +02:00
parent 0bfeeb2486
commit f5e403b331
24 changed files with 807 additions and 154 deletions

View File

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$">
<orderEntry type="inheritedJdk" /> <excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.8 (ProjektAI) (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

View File

@ -3,5 +3,5 @@
<component name="JavaScriptSettings"> <component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" /> <option name="languageLevel" value="ES6" />
</component> </component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (ProjektAI)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (ProjektAI) (2)" project-jdk-type="Python SDK" />
</project> </project>

View File

@ -0,0 +1,104 @@
class CrossingOverMethod:
FixedQuadrant = 0
SingleHorizontalDiv = 1
SingleVerticalDiv = 2
DoubleHorizontalDiv = 3
DoubleVerticalDiv = 4
RandomChoice = 5
class SelectionMethod:
Roulette = 0
Tournament = 1
class MutationMethod:
Flip = 0
Swap = 1
class GADefaults:
def __init__(self):
self.defSelectionMethods = [("ruletka", SelectionMethod.Roulette),
("turniej", SelectionMethod.Tournament)]
self.defCrossingOverMethods = [("pojedynczy poziomy", CrossingOverMethod.SingleHorizontalDiv),
("pojedynczy pionowy", CrossingOverMethod.SingleVerticalDiv),
("podwójny poziomy", CrossingOverMethod.DoubleHorizontalDiv),
("podwójny pionowy", CrossingOverMethod.DoubleVerticalDiv),
("ćwiartki", CrossingOverMethod.FixedQuadrant),
("losowe", CrossingOverMethod.RandomChoice)]
self.defMutationMethods = [("inwersja", MutationMethod.Flip),
("wymiana", MutationMethod.Swap)]
self.windowName = "Algorytm genetyczny - parametry"
self.windowGeometry = "400x400"
self.minTablesCount = 1
self.maxTablesCount = 100
self.defTablesCount = 20
self.runTablesCount = self.defTablesCount
self.sliderNameTablesCount = "stoliki"
self.minPopulationSize = 4
self.maxPopulationSize = 30
self.defPopulationSize = 5
self.runPopulationSize = self.defPopulationSize
self.sliderNamePopulationSize = "populacja"
self.minMutation = 0
self.maxMutation = 10
self.defMutation = 1
self.runMutation = self.defMutation
self.sliderNameMutation = "mutacje"
self.minGenerationsNumber = 1
self.maxGenerationsNumber = 1000
self.defGenerationsNumber = 20
self.runGenerationsNumber = self.defGenerationsNumber
self.sliderNameGenerationsNumber = "pokolenia"
self.defInfoFold = 5
self.runInfoFold = self.defInfoFold
self.sliderInfoFold = "co ile"
self.defSelectionMethod = SelectionMethod.Tournament
self.runSelectionMethod = self.defSelectionMethod
self.radioSelectionMethodName = "metoda selekcji"
self.defCrossingOverMethod = CrossingOverMethod.SingleHorizontalDiv
self.runCrossingOverMethod = self.defCrossingOverMethod
self.radioCrossingOverMethodName = "metoda krzyżowania"
self.defMutationMethod = MutationMethod.Swap
self.runMutationMethod = self.defMutationMethod
self.radioMutationMethodName = "metoda mutacji"
self.minElitism = 0
self.maxElitism = 50
self.defElitism = 0
self.runElitism = self.defElitism
self.sliderElitismName = "elitarność [%]"
self.buttonStartName = "generuj"
self.buttonDefaultsName = "przywróć"
self.__forbiddenPlaces = None
self.waiterPosition = None
self.kitchenPosition = None
def getForbiddenPlaces(self):
if self.__forbiddenPlaces is None:
self.__forbiddenPlaces = [self.waiterPosition, self.kitchenPosition]
return self.__forbiddenPlaces
def getInfo(self):
return "populacja: " + str(self.runPopulationSize) \
+ ", pokolenia: " + str(self.runGenerationsNumber) \
+ ", stoliki: " + str(self.runTablesCount) \
+ ", mutacje: " + str(self.runMutation)

View File

@ -0,0 +1,82 @@
import tkinter
from tkinter import *
from kelner.gui.GAdialog.GADefaults import CrossingOverMethod
class GADialog:
def __init__(self, defaults):
self.__defaults = defaults
self.window = tkinter.Tk()
self.window.attributes('-topmost', 'true')
self.window.title(defaults.windowName)
self.__sliderTablesCount = self.__getSlider(0, defaults.minTablesCount, defaults.maxTablesCount, defaults.runTablesCount, defaults.sliderNameTablesCount)
self.__sliderPopulationSize = self.__getSlider(1, defaults.minPopulationSize, defaults.maxPopulationSize, defaults.runPopulationSize, defaults.sliderNamePopulationSize)
self.__sliderMutation = self.__getSlider(2, defaults.minMutation, defaults.maxMutation, defaults.runMutation, defaults.sliderNameMutation)
self.__sliderGenerationsNumber = self.__getSlider(3, defaults.minGenerationsNumber, defaults.maxGenerationsNumber, defaults.runGenerationsNumber, defaults.sliderNameGenerationsNumber)
self.__sliderInfoFold = self.__getSlider(4, defaults.minGenerationsNumber, defaults.maxGenerationsNumber, defaults.runInfoFold, defaults.sliderInfoFold)
self.__sliderElitism = self.__getSlider(5, defaults.minElitism, defaults.maxElitism, defaults.runElitism, defaults.sliderElitismName)
self.__radioSelectionMethodValue = IntVar()
self.__radioSelectionMethodValue.set(self.__defaults.runSelectionMethod)
self.__getRadioButton(6, defaults.defSelectionMethods, self.__radioSelectionMethodValue, defaults.radioSelectionMethodName)
self.__radioCrossingOverMethodValue = IntVar()
self.__radioCrossingOverMethodValue.set(self.__defaults.runCrossingOverMethod)
self.__getRadioButton(8, defaults.defCrossingOverMethods, self.__radioCrossingOverMethodValue, defaults.radioCrossingOverMethodName)
self.__radioMutationMethodValue = IntVar()
self.__radioMutationMethodValue.set(self.__defaults.runMutationMethod)
self.__getRadioButton(12, defaults.defMutationMethods, self.__radioMutationMethodValue, defaults.radioMutationMethodName)
self.__buttonDefaults = self.__getButton(15, 0, W, defaults.buttonDefaultsName, self.__setDefaults)
self.__buttonStart = self.__getButton(15, 1, E, defaults.buttonStartName, self.__getAllValues)
self.window.mainloop()
def __getSlider(self, rowNum, minVal, maxVal, runVal, labText):
label = Label(self.window, text = labText)
label.grid(row = rowNum, column = 0, sticky = S + W, padx = 5, pady = 5)
slider = Scale(self.window, variable = IntVar(), from_ = minVal, to = maxVal, orient=HORIZONTAL, length = 200)
slider.grid(row = rowNum, column = 1, sticky = E, padx = 5, pady = 3)
slider.set(runVal)
return slider
def __getButton(self, rowNum, colNum, stickPos, btnText, action):
button = Button(self.window, text = btnText, command = action)
button.grid(row = rowNum, column = colNum, stick = stickPos, columnspan = 2, padx=60, pady=5)
return button
def __getRadioButton(self, rowNum, methods, variable, labText):
label = LabelFrame(self.window, text = labText)
label.grid(row=rowNum, column=0, columnspan=2, padx=5, pady=5, sticky=W)
rowNum += 1
iteration = 0
for text, mode in methods:
radio = Radiobutton(label, text = text, variable = variable, value = mode)
radio.grid(row = rowNum, column = iteration % 2, sticky = W, padx = 5, pady = 3)
rowNum += iteration % 2
iteration += 1
def __setDefaults(self):
self.__sliderTablesCount.set(self.__defaults.defTablesCount)
self.__sliderPopulationSize.set(self.__defaults.defPopulationSize)
self.__sliderMutation.set(self.__defaults.defMutation)
self.__sliderGenerationsNumber.set(self.__defaults.defGenerationsNumber)
self.__sliderInfoFold.set(self.__defaults.defInfoFold)
self.__sliderElitism.set(self.__defaults.defElitism)
self.__radioSelectionMethodValue.set(self.__defaults.defSelectionMethod)
self.__radioCrossingOverMethodValue.set(self.__defaults.defCrossingOverMethod)
self.__radioMutationMethodValue.set(self.__defaults.defMutationMethod)
def __getAllValues(self):
self.__defaults.runTablesCount = self.__sliderTablesCount.get()
self.__defaults.runPopulationSize = self.__sliderPopulationSize.get()
self.__defaults.runMutation = self.__sliderMutation.get()
self.__defaults.runGenerationsNumber = self.__sliderGenerationsNumber.get()
self.__defaults.runInfoFold = self.__sliderInfoFold.get()
self.__defaults.runElitism = self.__sliderElitism.get()
self.__defaults.runSelectionMethod = self.__radioSelectionMethodValue.get()
self.__defaults.runCrossingOverMethod = self.__radioCrossingOverMethodValue.get()
self.__defaults.runMutationMethod = self.__radioMutationMethodValue.get()
self.window.destroy()

22
kelner/gui/chart/Plots.py Normal file
View File

@ -0,0 +1,22 @@
import matplotlib.pyplot as plt
class Plots:
def __init__(self, generationNumber, bestFitnesses, bestTabless, worstFitnesses, worstTables, title):
self.__generationsNumber = generationNumber
self.__bestFitnesses = bestFitnesses
self.__bestTables = bestTabless
self.__worstTables = worstTables
self.__worstFitnesses = worstFitnesses
self.__title = title
def draw(self):
generations = [i for i in range(self.__generationsNumber + 1)]
plt.figure(num = self.__title)
plt.plot(generations, self.__bestTables, label = "stoliki najlepszego")
plt.plot(generations, self.__bestFitnesses, label="fitness najlepszego")
plt.plot(generations, self.__worstTables, label = "stoliki najgorszego")
plt.plot(generations, self.__worstFitnesses, label = "fitness najgorszego")
plt.legend()
plt.show()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 B

After

Width:  |  Height:  |  Size: 820 B

View File

@ -1,25 +1,24 @@
import pygame import pygame
from kelner.src.components.GridBoard import GridBoard from kelner.src.components.GridBoard import GridBoard
from kelner.src.components.Waiter import Waiter from kelner.src.components.Waiter import Waiter
from kelner.src.components.Table import Table
from kelner.src.components.Kitchen import Kitchen from kelner.src.components.Kitchen import Kitchen
from kelner.src.managers.DrawableCollection import DrawableCollection from kelner.src.managers.DrawableCollection import DrawableCollection
# create screen consts
from kelner.src.managers.MenuManager import MenuManager from kelner.src.managers.MenuManager import MenuManager
from kelner.src.managers.TableManager import TableManager from kelner.src.managers.TableGenerator import TableGenerator
from kelner.src.managers.WaiterManager import WaiterManager
from kelner.src.algorithms.DecisionTree import Tree_Builder from kelner.src.algorithms.DecisionTree import Tree_Builder
from kelner.src.managers.KitchenManager import KitchenManager from kelner.src.managers.KitchenManager import KitchenManager
from kelner.src.algorithms.CNN.PrepareData import LoadModelThread from kelner.src.algorithms.CNN.PrepareData import LoadModelThread
import kelner.src.settings as settings import kelner.src.settings as settings
import time
# create screen consts Scale = 1.5 # scale for all images used within project
Scale = 2 # scale for all images used within project CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid
CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid PaintOffset = CellSize # pixel size of paint offset for all drawables
PaintOffset = CellSize # pixel size of paint offset for all drawables GridCountX = 15 # number of columns in grid
GridCountX = 15 # number of columns in grid GridCountY = 9 # number of rows in grid
GridCountY = 9 # number of rows in grid ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
ScreenHeight = CellSize * GridCountY + 2 * PaintOffset # screen height in pixels ScreenHeight = CellSize * GridCountY + 2 * PaintOffset # screen height in pixels
running_tasks = {'table': [], 'waiter': []} running_tasks = {'table': [], 'waiter': []}
@ -34,8 +33,10 @@ load_model_thread.start()
# joining this thread to main thread. Man thread will be started after this finish # joining this thread to main thread. Man thread will be started after this finish
load_model_thread.join() load_model_thread.join()
kitchenManager = KitchenManager(gridBoard)
# initialize drawable objects manager # initialize drawable objects manager
drawableManager = DrawableCollection() drawableManager = DrawableCollection(kitchenManager)
# initialize menu manager # initialize menu manager
menuManager = MenuManager() menuManager = MenuManager()
@ -75,48 +76,16 @@ else:
print("test4: fail") print("test4: fail")
# initialize waiter component # initialize waiter component
waiter1 = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset) waiter1 = Waiter(7, 4, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter2 = Waiter(0, GridCountY - 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter3 = Waiter(GridCountX - 1, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter4 = Waiter(GridCountX - 1, GridCountY - 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# adds waiter to drawable collection # adds waiter to drawable collection
drawableManager.add(waiter1) drawableManager.add(waiter1)
# drawableManager.add(waiter2)
# drawableManager.add(waiter3)
# drawableManager.add(waiter4)
kitchen = Kitchen(14, 0, 5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
kitchen = Kitchen(5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
drawableManager.add(kitchen) drawableManager.add(kitchen)
kitchenManager = KitchenManager(drawableManager, gridBoard)
# My comment tableGenerator = TableGenerator(GridCountX, GridCountY, 1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset, drawableManager)
# initialize a number of tables given in range tableGenerator.start()
for i in range(0, 40):
table = Table(1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset)
if drawableManager.generatePosition(table):
drawableManager.add(table)
# new thread controlling tables
tableTask = TableManager(drawableManager, menuManager)
tableTask.start()
running_tasks['table'].append(tableTask)
# new thread controlling waiter
waiter1Task = WaiterManager(drawableManager, [waiter1], kitchenManager, menuManager, tableTask)
waiter1Task.start()
running_tasks['waiter'].append(tableTask)
# waiter2Task = WaiterManager(drawableManager, [waiter2])
# waiter2Task.start()
#
# waiter3Task = WaiterManager(drawableManager, [waiter3])
# waiter3Task.start()
#
# waiter4Task = WaiterManager(drawableManager, [waiter4])
# waiter4Task.start()
# main loop # main loop
running = True running = True
@ -124,56 +93,12 @@ 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() tableGenerator.stop()
waiter1Task.stop() drawableManager.stop()
# waiter2Task.stop()
# waiter3Task.stop()
# waiter4Task.stop()
running = False 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(waiter1.getX() - 1, waiter1.getY()):
waiter1.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(waiter1.getX() + 1, waiter1.getY()):
waiter1.moveRight()
if event.key == pygame.K_UP:
# checks if new waiter's position up is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX(), waiter1.getY() - 1):
waiter1.moveUp()
if event.key == pygame.K_DOWN:
# checks if new waiter's position down is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX(), waiter1.getY() + 1):
waiter1.moveDown()
if event.key == pygame.K_w:
# checks if new waiter's position to the left is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() - 1):
waiter1.moveLeft()
waiter1.moveUp()
if event.key == pygame.K_d:
# checks if new waiter's position to the right is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() - 1):
waiter1.moveRight()
waiter1.moveUp()
if event.key == pygame.K_s:
# checks if new waiter's position up is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() + 1):
waiter1.moveDown()
waiter1.moveRight()
if event.key == pygame.K_a:
# checks if new waiter's position down is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() + 1):
waiter1.moveDown()
waiter1.moveLeft()
drawableManager.forceRepaint()
# repaints all objects to the screen # repaints all objects to the screen
# is set only on initial paint or after keyboard event or call to forceRepaint() # is set only on initial paint or call to forceRepaint()
if drawableManager.mustRepaint(): if drawableManager.mustRepaint():
if not kitchenManager.is_running(): if not kitchenManager.is_running():
gridBoard.reinitialize() gridBoard.reinitialize()

View File

@ -8,9 +8,9 @@ from tensorflow.keras.models import load_model
import kelner.src.settings as settings import kelner.src.settings as settings
# currently all images are not stored in repo because of big weight (5 GB) # currently all images are not stored in repo because of big weight (5 GB)
data_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101\\images' #data_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101\\images'
folder_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101' #folder_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101'
foods_sorted = sorted(os.listdir(data_dir)) #foods_sorted = sorted(os.listdir(data_dir))
food_id = 0 food_id = 0

View File

@ -0,0 +1,304 @@
import random
import math
from queue import PriorityQueue
from kelner.src.algorithms.GATableGenerator.Individual import Individual
from kelner.src.algorithms.AStar.Finder import Finder
from kelner.gui.GAdialog.GADefaults import GADefaults, CrossingOverMethod, MutationMethod, SelectionMethod
class GATableGenerator:
def __init__(self, gridCols, gridRows, params):
self.gridCols = gridCols
self.gridRows = gridRows
self.params = params
self.currentGenerationNumber = 0
self.population = None
self.bestFitnessScores = []
self.worstFitnessScores = []
self.bestTables = []
self.worstTables = []
def generateTables(self):
table = [[0] * self.gridCols for i in range(self.gridRows)]
for _ in range(self.params.runTablesCount):
isPositionUnique = False
while not isPositionUnique:
x = random.randint(0, self.gridCols - 1)
y = random.randint(0, self.gridRows - 1)
if (x, y) not in self.params.getForbiddenPlaces() and table[y][x] == 0:
isPositionUnique = True
table[y][x] = 1
table[self.params.kitchenPosition[1]][self.params.kitchenPosition[0]] = 1
return table
def getIndividual(self, table):
origin = self.params.waiterPosition
finder = Finder(table)
fitnessScore = 0
tablesCount = 0
for y in range(self.gridRows):
for x in range(self.gridCols):
if table[y][x] == 1:
tablesCount += 1
targets = finder.getNeighbours((x, y), False)
for target in targets:
if origin == target:
fitnessScore += 1
break
else:
path = finder.getPath(origin, target, True)
if path:
fitnessScore += 1
break
individual = Individual(table, fitnessScore - (tablesCount - fitnessScore), tablesCount)
return individual
def updateStats(self):
bestIndividual = self.getBestIndividual()
worstIndividual = self.getWorstIndividual()
self.bestFitnessScores.append(bestIndividual.getFitness())
self.bestTables.append(bestIndividual.getTablesCount())
self.worstFitnessScores.append(worstIndividual.getFitness())
self.worstTables.append(worstIndividual.getTablesCount())
def firstPopulation(self):
self.population = PriorityQueue()
for _ in range(self.params.runPopulationSize):
self.population.put(self.getIndividual(self.generateTables()))
self.currentGenerationNumber = 0
self.bestFitnessScores = []
self.worstFitnessScores = []
self.bestTables = []
self.worstTables = []
self.updateStats()
def getPopulationQueue(self):
queue = PriorityQueue()
for item in self.population.queue:
queue.put(item)
return queue
def getPopulationSortedArray(self):
queue = self.getPopulationQueue()
array = []
while not queue.empty():
array.append(queue.get())
return array
def arrayToQueue(self, array):
queue = PriorityQueue()
for item in array:
queue.put(item)
return queue
def selectParentsByRoulette(self):
populationArray = self.getPopulationSortedArray()
parents = []
delta = populationArray[len(populationArray) - 1].getFitness()
if delta > 0:
delta = 0
else:
delta = abs(delta) + 1
fitnessSum = 0
for individual in populationArray:
fitnessSum += individual.getFitness() + delta
for _ in range(2):
draw = random.uniform(0, 1)
accumulated = 0
for individual in populationArray:
probability = float(individual.getFitness() + delta) / fitnessSum
accumulated += probability
if draw <= accumulated:
parents.append(individual)
fitnessSum -= (individual.getFitness() + delta)
populationArray.remove(individual)
break
return parents
def selectParentsByTournament(self):
parents = []
competitorsNum = math.ceil(0.25 * self.params.runPopulationSize)
if competitorsNum < self.params.minPopulationSize:
competitorsNum = self.params.minPopulationSize - 1
population = self.getPopulationSortedArray()
parent = self.arrayToQueue(random.sample(population, competitorsNum)).get()
population.remove(parent)
parents.append(parent)
parents.append(self.arrayToQueue(random.sample(population, competitorsNum)).get())
return parents
def quadrant(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
for row in range(self.gridRows):
for col in range(self.gridCols):
if (row <= math.floor((self.gridRows - 1) / 2.0)) and (col <= math.ceil((self.gridCols - 1) / 2.0)) or \
(row > math.floor((self.gridRows - 1) / 2.0)) and (col > math.ceil((self.gridCols - 1) / 2.0)):
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def singleVerticalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divX = random.randint(1, self.gridCols - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if col <= divX:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def singleHorizontalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divY = random.randint(1, self.gridRows - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if row <= divY:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def doubleVerticalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divC = math.ceil((self.gridCols - 1) / 2)
divX1 = random.randint(1, divC - 1)
divX2 = random.randint(divC + 1, self.gridCols - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if divX1 <= col < divX2:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def doubleHorizontalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divC = math.ceil((self.gridRows - 1) / 2)
divY1 = random.randint(1, divC - 1)
divY2 = random.randint(divC + 1, self.gridRows - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if divY1 <= row < divY2:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def randomChoice(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
parents = [parentL.getTables(), parentR.getTables()]
for row in range(self.gridRows):
for col in range(self.gridCols):
childTables[row][col] = random.choice(parents)[row][col]
return childTables
def procreate(self):
if self.params.runSelectionMethod == SelectionMethod.Roulette:
parentLeft, parentRight = self.selectParentsByRoulette()
elif self.params.runSelectionMethod == SelectionMethod.Tournament:
parentLeft, parentRight = self.selectParentsByTournament()
child = None
if self.params.runCrossingOverMethod == CrossingOverMethod.FixedQuadrant:
child = self.quadrant(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.SingleVerticalDiv:
child = self.singleVerticalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.SingleHorizontalDiv:
child = self.singleHorizontalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.DoubleVerticalDiv:
child = self.doubleVerticalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.DoubleHorizontalDiv:
child = self.doubleHorizontalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.RandomChoice:
child = self.randomChoice(parentLeft, parentRight)
return child
def getRandTuple(self):
isPlaceAvailable = False
while not isPlaceAvailable:
randX = random.randint(0, self.gridCols - 1)
randY = random.randint(0, self.gridRows - 1)
isPlaceAvailable = (randX, randY) not in self.params.getForbiddenPlaces()
return randX, randY
def mutateFlip(self, tables):
mutatedTables = tables
numberOfMutation = random.randint(0, self.params.runMutation)
for _ in range(numberOfMutation):
randX, randY = self.getRandTuple()
if mutatedTables[randY][randX] == 1:
mutatedTables[randY][randX] = 0
else:
mutatedTables[randY][randX] = 1
return mutatedTables
def mutateSwap(self, tables):
mutatedTables = tables
numberOfMutation = random.randint(0, self.params.runMutation)
for _ in range(numberOfMutation):
randX1, randY1 = self.getRandTuple()
randX2, randY2 = self.getRandTuple()
value = mutatedTables[randY1][randX1]
mutatedTables[randY1][randX1] = mutatedTables[randY2][randX2]
mutatedTables[randY2][randX2] = value
return mutatedTables
def makeNextGeneration(self):
tablesArray = []
eliteSize = math.ceil((self.params.runPopulationSize * self.params.runElitism) / 100.0)
for _ in range(self.params.runPopulationSize - eliteSize):
if self.params.runMutationMethod == MutationMethod.Flip:
mutated = self.mutateFlip(self.procreate())
elif self.params.runMutationMethod == MutationMethod.Swap:
mutated = self.mutateSwap(self.procreate())
tablesArray.append(mutated)
eliteArray = []
for _ in range(eliteSize):
eliteArray.append(self.population.get())
self.population = PriorityQueue()
for individual in eliteArray:
self.population.put(individual)
for table in tablesArray:
self.population.put(self.getIndividual(table))
self.currentGenerationNumber += 1
self.updateStats()
def canGenerate(self):
return self.currentGenerationNumber < self.params.runGenerationsNumber
def getBestIndividual(self):
population = self.getPopulationQueue()
return population.get()
def getWorstIndividual(self):
population = self.getPopulationSortedArray()
return population[len(population) - 1]
def printBest(self):
populationBest = self.getBestIndividual()
populationBest.print(self.currentGenerationNumber)
def printPopulation(self):
queue = self.getPopulationQueue()
while not queue.empty():
individual = queue.get()
individual.print(self.currentGenerationNumber)
print('---------------------------------------')
def makeAllGenerations(self):
self.printBest()
while self.canGenerate():
self.makeNextGeneration()
self.printBest()
"""
params = GADefaults()
generator = GATableGenerator(15, 9, params)
generator.firstPopulation()
generator.printPopulation()
while generator.canGenerate():
generator.makeNextGeneration()
generator.printPopulation()
"""

View File

@ -0,0 +1,33 @@
class Individual:
def __init__(self, table, fitnessScore, tablesCount):
self.__table = table
self.__fitnessScore = fitnessScore
self.__tablesCount = tablesCount
# operator (>) for PriorityQueue comparison (determines the objects order)
def __gt__(self, other):
return self.__fitnessScore < other.__fitnessScore
def getTables(self):
return self.__table
def getTablesCount(self):
return self.__tablesCount
def getFitness(self):
return self.__fitnessScore
def getInfo(self, generation):
return f"GENERATION: {generation}, FITNESS: {self.__fitnessScore}, TABLES: {self.__tablesCount}"
def print(self, generation):
print(self.getInfo(generation))
cols = len(self.__table[0])
rows = len(self.__table)
for row in range(rows):
for col in range(cols):
v = self.__table[row][col]
v = ' ' if v == 0 else '#' if v == 1 else 'O'
print('|', v, sep='', end='')
print('|')

View File

@ -1,5 +1,3 @@
from kelner.src.managers.ImageCache import ImageCache, Images
class Drawable: class Drawable:
@ -62,15 +60,3 @@ class Drawable:
def drawAux(self, screen): def drawAux(self, screen):
pass pass
def getImage(self, imageKind, img_path=None):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
size = int(self.getCellSize() / 3)
elif imageKind in [Images.Kitchen, Images.Dishes]:
size = int(self.getCellSize())
else:
size = int(1.4 * self.getCellSize())
if img_path:
return ImageCache.getInstance().getImage(imageKind, size, size, img_path)
else:
return ImageCache.getInstance().getImage(imageKind, size, size)

View File

@ -1,18 +1,15 @@
import random import random
from enum import Enum
from threading import Lock
from kelner.src.components.Drawable import Drawable from kelner.src.components.Drawable import Drawable
from kelner.src.managers.ImageCache import ImageCache, Images from kelner.src.managers.ImageCache import ImageCache, Images
from kelner.src.algorithms.DecisionTree import Tree_Builder from kelner.src.algorithms.DecisionTree import Tree_Builder
import os import os
import copy
import time
import pygame import pygame
class Kitchen(Drawable): class Kitchen(Drawable):
def __init__(self, minX, maxX, minY, maxY, cellSize, offset): def __init__(self, x, y, minX, maxX, minY, maxY, cellSize, offset):
# call base class constructor # call base class constructor
super().__init__(14, 0, minX, maxX, minY, maxY, cellSize, offset) super().__init__(x, y, minX, maxX, minY, maxY, cellSize, offset)
self._preparing_orders = None self._preparing_orders = None
self._ready_orders = None self._ready_orders = None
self._photos_path = os.path.join(os.getcwd(), 'foodImages') self._photos_path = os.path.join(os.getcwd(), 'foodImages')
@ -92,7 +89,17 @@ class Kitchen(Drawable):
# print("Image drawing: {}".format(img_path)) # print("Image drawing: {}".format(img_path))
return img_paths return img_paths
def getImage(self, imageKind, img_path=None):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
size = int(self.getCellSize() / 3)
elif imageKind in [Images.Kitchen, Images.Dishes]:
size = int(self.getCellSize())
else:
size = int(1.4 * self.getCellSize())
if img_path:
return ImageCache.getInstance().getImage(imageKind, size, size, img_path)
else:
return ImageCache.getInstance().getImage(imageKind, size, size)
def draw(self, screen): def draw(self, screen):
xBase = self.getX() * self.getCellSize() + self.getOffset() xBase = self.getX() * self.getCellSize() + self.getOffset()

View File

@ -111,7 +111,7 @@ class Table(Drawable):
self.__status = status self.__status = status
def __getImage(self, imageKind): def __getImage(self, imageKind):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]: if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate, Images.Chicken]:
size = int(self.getCellSize() / 3) size = int(self.getCellSize() / 3)
else: else:
size = int(1.4 * self.getCellSize()) size = int(1.4 * self.getCellSize())
@ -164,3 +164,15 @@ class Table(Drawable):
screen.blit(imagePlate, (xBase + guest1XOffset, yBase + platesYOffset)) screen.blit(imagePlate, (xBase + guest1XOffset, yBase + platesYOffset))
screen.blit(imagePlate, (xBase + guest2XOffset, yBase + platesYOffset)) screen.blit(imagePlate, (xBase + guest2XOffset, yBase + platesYOffset))
screen.blit(imagePlate, (xBase + guest3XOffset, yBase + platesYOffset)) screen.blit(imagePlate, (xBase + guest3XOffset, yBase + platesYOffset))
elif self.isStatus(Status.Served):
platesYOffset = int(0.3 * self.getCellSize())
imageChicken = self.__getImage(Images.Chicken)
if len(self.__guests) == 1:
screen.blit(imageChicken, (xBase + guest2XOffset, yBase + platesYOffset))
elif len(self.__guests) == 2:
screen.blit(imageChicken, (xBase + guest4XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest5XOffset, yBase + platesYOffset))
elif len(self.__guests) == 3:
screen.blit(imageChicken, (xBase + guest1XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest2XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest3XOffset, yBase + platesYOffset))

View File

@ -7,16 +7,43 @@ from kelner.src.components.Kitchen import Kitchen
# drawable objects manager # drawable objects manager
from kelner.src.managers.MenuManager import MenuManager
from kelner.src.managers.TableManager import TableManager
from kelner.src.managers.WaiterManager import WaiterManager
class DrawableCollection: class DrawableCollection:
# const, minimal distance between objects # const, minimal distance between objects
__MinDistanceX = 1 __MinDistanceX = 1
__MinDistanceY = 0 __MinDistanceY = 0
def __init__(self): def __init__(self, kitchenManager):
# collection that holds all drawable objects # collection that holds all drawable objects
self.__mustRepaint = True self.__mustRepaint = True
self.__drawables = [] self.__drawables = []
self.__waiterLock = Lock() self.__waiterLock = Lock()
self.__tasks = []
self.__kitchenManager = kitchenManager
def start(self):
# initialize menu manager
menuManager = MenuManager()
# new thread controlling tables
tableTask = TableManager(self, menuManager)
self.__tasks.append(tableTask)
waiters = self.getWaiters()
for waiter in waiters:
# new thread controlling waiter
waiterTask = WaiterManager(self, [waiter], self.__kitchenManager, menuManager, tableTask)
self.__tasks.append(waiterTask)
for task in self.__tasks:
task.start()
def stop(self):
for task in self.__tasks:
task.stop()
# adds drawable objects to the collection # adds drawable objects to the collection
def add(self, drawable): def add(self, drawable):
@ -52,6 +79,10 @@ class DrawableCollection:
break break
return isPositionAvailable return isPositionAvailable
# deletes all tables
def delTables(self):
self.__drawables = [drawable for drawable in self.__drawables if not isinstance(drawable, Table)]
# gets all tables by status from collection # gets all tables by status from collection
def getTables(self, status): def getTables(self, status):
result = [] result = []
@ -61,11 +92,10 @@ class DrawableCollection:
return result return result
def get_kitchen(self): def get_kitchen(self):
kitchen = None
for item in self.__drawables: for item in self.__drawables:
if isinstance(item, Kitchen): if isinstance(item, Kitchen):
kitchen = item return item
return kitchen return None
def lock(self): def lock(self):
self.__waiterLock.acquire() self.__waiterLock.acquire()
@ -101,8 +131,8 @@ class DrawableCollection:
nearestTables = [] nearestTables = []
tables = self.getTables(tableStatus) tables = self.getTables(tableStatus)
for table in tables: for table in tables:
if (table.getX() == waiter.getX() and abs(table.getY() - waiter.getY()) == 1) or \ 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.getY() == waiter.getY() and abs(table.getX() - waiter.getX()) == 1):
nearestTables.append(table) nearestTables.append(table)
return nearestTables return nearestTables

View File

@ -23,6 +23,7 @@ class Images(Enum):
ToolTip = 16 ToolTip = 16
Kitchen = 17 Kitchen = 17
Dishes = 18 Dishes = 18
Chicken = 19
class ImageCache: class ImageCache:
@ -60,7 +61,8 @@ class ImageCache:
Images.Guest3: './images/wiking_rudy2.png', Images.Guest3: './images/wiking_rudy2.png',
Images.ToolTip: './images/tooltip.png', Images.ToolTip: './images/tooltip.png',
Images.Kitchen: './images/kitchen.png', Images.Kitchen: './images/kitchen.png',
Images.Dishes: './images/testDishes/' Images.Dishes: './images/testDishes/',
Images.Chicken: './images/kurczak.png'
} }
def __getFont(self): def __getFont(self):

View File

@ -6,9 +6,8 @@ import sys
# creates new thread # creates new thread
class KitchenManager(threading.Thread): class KitchenManager(threading.Thread):
def __init__(self, drawable_manager, gridboard): def __init__(self, gridboard):
super().__init__() super().__init__()
self._drawable_manager = drawable_manager
self._gridboard = gridboard self._gridboard = gridboard
self.__runThread = False self.__runThread = False

View File

@ -0,0 +1,120 @@
import threading
from tkinter import messagebox, Tk
from kelner.src.components.Table import Table
from kelner.src.algorithms.GATableGenerator.GATableGenerator import GATableGenerator
from kelner.gui.GAdialog.GADialog import GADialog
from kelner.gui.GAdialog.GADefaults import GADefaults
from kelner.gui.chart.Plots import Plots
# creates new thread
class TableGenerator (threading.Thread):
def __init__(self, gridCols, gridRows, minX, maxX, minY, maxY, cellSize, paintOffset, drawableManager):
super().__init__()
self.__minX = minX
self.__maxX = maxX
self.__minY = minY
self.__maxY = maxY
self.__cellSize = cellSize
self.__paintOffset = paintOffset
self.__drawableManager = drawableManager
self.__runThread = True
self.__defaults = GADefaults()
self.__defaults.waiterPosition = self.__getDefaultWaiterPosition()
self.__defaults.kitchenPosition = self.__getDefaultKitchenPosition()
self.__gaTableGenerator = GATableGenerator(gridCols, gridRows, self.__defaults)
def __getDefaultWaiterPosition(self):
waiters = self.__drawableManager.getWaiters()
if waiters:
return waiters[0].getX(), waiters[0].getY()
return None
def __getDefaultKitchenPosition(self):
kitchen = self.__drawableManager.get_kitchen()
if kitchen is not None:
return kitchen.getX(), kitchen.getY()
return None
def __randomTables(self):
# initialize a number of tables given in range
for i in range(0, 40):
table = Table(self.__minX, self.__maxX, self.__minY, self.__maxY, self.__cellSize, self.__paintOffset)
if self.__drawableManager.generatePosition(table):
self.__drawableManager.add(table)
def __geneticTables(self):
bestIndividual = self.__gaTableGenerator.getBestIndividual()
for row in range(self.__gaTableGenerator.gridRows):
for col in range(self.__gaTableGenerator.gridCols):
if bestIndividual.getTables()[row][col] == 1 and \
(row != self.__defaults.kitchenPosition[1] or col != self.__defaults.kitchenPosition[0]):
table = Table(0, self.__gaTableGenerator.gridCols - 1, 0, self.__gaTableGenerator.gridRows - 1, self.__cellSize, self.__paintOffset)
table.setX(col)
table.setY(row)
self.__drawableManager.add(table)
def __askIfGA(self):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion("Rodzaj algorytmu", "Czy uruchomić algorytm genetyczny?", parent=window)
window.destroy()
return result == 'yes'
def __ask(self, info):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion(info + '\n', "Czy nowa generacja?", parent=window)
window.destroy()
return result == 'yes'
def __askIfAgain(self):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion("Potwierdź", "Czy powtórzyć proces?", parent=window)
window.destroy()
return result == 'yes'
def __plot(self):
plot = Plots(self.__gaTableGenerator.currentGenerationNumber,
self.__gaTableGenerator.bestFitnessScores, self.__gaTableGenerator.bestTables,
self.__gaTableGenerator.worstFitnessScores, self.__gaTableGenerator.worstTables,
self.__defaults.getInfo())
plot.draw()
def run(self):
if self.__askIfGA():
while self.__runThread:
again = True
GADialog(self.__defaults)
self.__gaTableGenerator.firstPopulation()
while again:
self.__drawableManager.delTables()
self.__geneticTables()
self.__drawableManager.forceRepaint()
if self.__gaTableGenerator.canGenerate():
if self.__gaTableGenerator.currentGenerationNumber % self.__defaults.runInfoFold != 0 or\
self.__ask(self.__gaTableGenerator.getBestIndividual().getInfo(self.__gaTableGenerator.currentGenerationNumber)):
self.__gaTableGenerator.makeNextGeneration()
else:
self.__drawableManager.start()
self.stop()
again = False
self.__plot()
else:
self.__plot()
if not self.__askIfAgain():
self.__drawableManager.start()
self.stop()
again = False
else:
self.__randomTables()
self.__drawableManager.forceRepaint()
self.__drawableManager.start()
def stop(self):
self.__runThread = False

View File

@ -1,6 +1,7 @@
import threading import threading
import time import time
import sys import sys
from math import sqrt
from kelner.src.components.Table import Status from kelner.src.components.Table import Status
from kelner.src.algorithms.AStar.Finder import Finder from kelner.src.algorithms.AStar.Finder import Finder
from kelner.src.algorithms.BFS.BFS import BFS from kelner.src.algorithms.BFS.BFS import BFS
@ -20,43 +21,65 @@ class WaiterManager(threading.Thread):
self._menu_manager = menu_manager self._menu_manager = menu_manager
self._table_manager = table_manager self._table_manager = table_manager
def __getNearestTargetPath(self, waiter, target): def __getDistance(self, waiter, tupleXY):
distance = sys.maxsize dx = waiter.getX() - tupleXY[0]
nearestTargetPath = None dy = waiter.getY() - tupleXY[1]
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter) return sqrt(dx * dx + dy * dy)
def __sortTargets(self, waiter, targets):
return sorted(targets, key=lambda target: self.__getDistance(waiter, (target[0], target[1])))
def __getTargets(self, waiter, finder):
found = []
tables = self.__drawableManager.getTables(Status.Ready) tables = self.__drawableManager.getTables(Status.Ready)
finder = Finder(reservedPlaces)
origin = (waiter.getX(), waiter.getY())
if target == 'kitchen':
path = finder.getPath(origin, (14, 1), True)
path2 = finder.getPath(origin, (13, 0), True)
path = path2 if len(path) > len(path2) else path
return path
if tables: if tables:
origin = (waiter.getX(), waiter.getY())
for table in tables: for table in tables:
if table.hasOrder(): if table.hasOrder():
targets = finder.getNeighbours((table.getX(), table.getY()), False) targets = finder.getNeighbours((table.getX(), table.getY()), False)
for target in targets: for target in targets:
if target is not None: if target == origin:
path = finder.getPath(origin, target, True) return []
if path: else:
result = len(path) found.append(target)
if result < distance: return self.__sortTargets(waiter, found)
distance = result
nearestTargetPath = path def __getNearestTargetPath(self, waiter, targets=None):
distance = sys.maxsize
nearestTargetPath = None
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
finder = Finder(reservedPlaces)
origin = (waiter.getX(), waiter.getY())
if targets is None:
targets = self.__getTargets(waiter, finder)
for target in targets:
if distance > self.__getDistance(waiter, target):
path = finder.getPath(origin, target, True)
if path:
result = len(path)
if result < distance:
distance = result
nearestTargetPath = path
return nearestTargetPath return nearestTargetPath
def get_specified_path(self, waiter, table): def get_specified_path(self, waiter, table):
distance = sys.maxsize
nearestTargetPath = None
reserved_places = self.__drawableManager.getReservedPlaces(waiter) reserved_places = self.__drawableManager.getReservedPlaces(waiter)
finder = Finder(reserved_places) finder = Finder(reserved_places)
origin = (waiter.getX(), waiter.getY()) origin = (waiter.getX(), waiter.getY())
targets = finder.getNeighbours((table[0], table[1]), False) targets = finder.getNeighbours((table[0], table[1]), False)
for target in targets: for target in targets:
if target is not None: if distance > self.__getDistance(waiter, target):
path = finder.getPath(origin, target, True) path = finder.getPath(origin, target, True)
if path: if path:
return path result = len(path)
if result < distance:
distance = result
nearestTargetPath = path
return nearestTargetPath
def __changeWaiterDirection(self, waiter, x, y): def __changeWaiterDirection(self, waiter, x, y):
targetDirection = x - waiter.getX(), y - waiter.getY() targetDirection = x - waiter.getX(), y - waiter.getY()
@ -172,13 +195,14 @@ class WaiterManager(threading.Thread):
if len(waiter.getAcceptedOrders()) > 1: if len(waiter.getAcceptedOrders()) > 1:
waiter.set_target('kitchen') waiter.set_target('kitchen')
path = self.__getNearestTargetPath(waiter, target=waiter.get_target()) path = self.__getNearestTargetPath(waiter, [(14, 1), (13, 0)])
waiter.make_busy() waiter.make_busy()
else: else:
if waiter.get_target() == 'return_order' and waiter.isPathEmpty(): if waiter.get_target() == 'return_order' and waiter.isPathEmpty():
print("Order returned") print("Order returned")
table = self._table_manager.get_table(waiter.get_remaining_positions()[0]) table = self._table_manager.get_table(waiter.get_remaining_positions()[0])
table.setStatus(Status.Served) table.setStatus(Status.Served)
self.__changeWaiterDirection(waiter, table.getX(), table.getY())
waiter.get_remaining_positions().pop(0) waiter.get_remaining_positions().pop(0)
time.sleep(2) time.sleep(2)
@ -187,7 +211,7 @@ class WaiterManager(threading.Thread):
path = self.get_specified_path(waiter, waiter.get_remaining_positions()[0]) path = self.get_specified_path(waiter, waiter.get_remaining_positions()[0])
else: else:
waiter.set_target('table') waiter.set_target('table')
path = self.__getNearestTargetPath(waiter, target='table') path = self.__getNearestTargetPath(waiter)
waiter.setPath([] if path is None else path) waiter.setPath([] if path is None else path)
@ -201,6 +225,7 @@ class WaiterManager(threading.Thread):
if waiter.get_target() == 'kitchen': if waiter.get_target() == 'kitchen':
self._table_manager.pause() self._table_manager.pause()
kitchen = self.__drawableManager.get_kitchen() kitchen = self.__drawableManager.get_kitchen()
self.__changeWaiterDirection(waiter, kitchen.getX(), kitchen.getY())
waiter_orders = waiter.getAcceptedOrders() waiter_orders = waiter.getAcceptedOrders()
# print("Waiter near kitchen. Collected orders: {}".format(waiter_orders)) # print("Waiter near kitchen. Collected orders: {}".format(waiter_orders))
kitchen.add_orders(waiter_orders) kitchen.add_orders(waiter_orders)