forked from s444417/ProjektAI
integracja projektu genetycznego generatora stolików
This commit is contained in:
parent
0bfeeb2486
commit
f5e403b331
@ -1,8 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.8 (ProjektAI) (2)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@ -3,5 +3,5 @@
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</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>
|
104
kelner/gui/GAdialog/GADefaults.py
Normal file
104
kelner/gui/GAdialog/GADefaults.py
Normal 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)
|
82
kelner/gui/GAdialog/GADialog.py
Normal file
82
kelner/gui/GAdialog/GADialog.py
Normal 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
22
kelner/gui/chart/Plots.py
Normal 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 |
105
kelner/main.py
105
kelner/main.py
@ -1,20 +1,19 @@
|
||||
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.components.Kitchen import Kitchen
|
||||
from kelner.src.managers.DrawableCollection import DrawableCollection
|
||||
|
||||
# create screen consts
|
||||
from kelner.src.managers.MenuManager import MenuManager
|
||||
from kelner.src.managers.TableManager import TableManager
|
||||
from kelner.src.managers.WaiterManager import WaiterManager
|
||||
from kelner.src.managers.TableGenerator import TableGenerator
|
||||
from kelner.src.algorithms.DecisionTree import Tree_Builder
|
||||
from kelner.src.managers.KitchenManager import KitchenManager
|
||||
from kelner.src.algorithms.CNN.PrepareData import LoadModelThread
|
||||
import kelner.src.settings as settings
|
||||
import time
|
||||
|
||||
# create screen consts
|
||||
Scale = 2 # scale for all images used within project
|
||||
Scale = 1.5 # 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
|
||||
@ -34,8 +33,10 @@ load_model_thread.start()
|
||||
# joining this thread to main thread. Man thread will be started after this finish
|
||||
load_model_thread.join()
|
||||
|
||||
kitchenManager = KitchenManager(gridBoard)
|
||||
|
||||
# initialize drawable objects manager
|
||||
drawableManager = DrawableCollection()
|
||||
drawableManager = DrawableCollection(kitchenManager)
|
||||
|
||||
# initialize menu manager
|
||||
menuManager = MenuManager()
|
||||
@ -75,48 +76,16 @@ else:
|
||||
print("test4: fail")
|
||||
|
||||
# initialize waiter component
|
||||
waiter1 = Waiter(0, 0, 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)
|
||||
|
||||
waiter1 = Waiter(7, 4, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
||||
|
||||
# adds waiter to drawable collection
|
||||
drawableManager.add(waiter1)
|
||||
# drawableManager.add(waiter2)
|
||||
# drawableManager.add(waiter3)
|
||||
# drawableManager.add(waiter4)
|
||||
|
||||
|
||||
kitchen = Kitchen(5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
|
||||
kitchen = Kitchen(14, 0, 5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
|
||||
drawableManager.add(kitchen)
|
||||
kitchenManager = KitchenManager(drawableManager, gridBoard)
|
||||
|
||||
# My comment
|
||||
# initialize a number of tables given in range
|
||||
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()
|
||||
tableGenerator = TableGenerator(GridCountX, GridCountY, 1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset, drawableManager)
|
||||
tableGenerator.start()
|
||||
|
||||
# main loop
|
||||
running = True
|
||||
@ -124,56 +93,12 @@ while running:
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
tableTask.stop()
|
||||
waiter1Task.stop()
|
||||
# waiter2Task.stop()
|
||||
# waiter3Task.stop()
|
||||
# waiter4Task.stop()
|
||||
tableGenerator.stop()
|
||||
drawableManager.stop()
|
||||
running = False
|
||||
|
||||
# handles keyboard events
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT:
|
||||
# checks if new waiter's position to the left is not occupied by other object
|
||||
if drawableManager.isPositionAvailable(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
|
||||
# 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 not kitchenManager.is_running():
|
||||
gridBoard.reinitialize()
|
||||
|
@ -8,9 +8,9 @@ from tensorflow.keras.models import load_model
|
||||
import kelner.src.settings as settings
|
||||
|
||||
# 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'
|
||||
folder_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101'
|
||||
foods_sorted = sorted(os.listdir(data_dir))
|
||||
#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'
|
||||
#foods_sorted = sorted(os.listdir(data_dir))
|
||||
food_id = 0
|
||||
|
||||
|
||||
|
304
kelner/src/algorithms/GATableGenerator/GATableGenerator.py
Normal file
304
kelner/src/algorithms/GATableGenerator/GATableGenerator.py
Normal 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()
|
||||
"""
|
33
kelner/src/algorithms/GATableGenerator/Individual.py
Normal file
33
kelner/src/algorithms/GATableGenerator/Individual.py
Normal 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('|')
|
@ -1,5 +1,3 @@
|
||||
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||
|
||||
|
||||
class Drawable:
|
||||
|
||||
@ -62,15 +60,3 @@ class Drawable:
|
||||
|
||||
def drawAux(self, screen):
|
||||
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)
|
||||
|
@ -1,18 +1,15 @@
|
||||
import random
|
||||
from enum import Enum
|
||||
from threading import Lock
|
||||
from kelner.src.components.Drawable import Drawable
|
||||
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||
from kelner.src.algorithms.DecisionTree import Tree_Builder
|
||||
import os
|
||||
import copy
|
||||
import time
|
||||
import pygame
|
||||
|
||||
|
||||
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
|
||||
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._ready_orders = None
|
||||
self._photos_path = os.path.join(os.getcwd(), 'foodImages')
|
||||
@ -92,7 +89,17 @@ class Kitchen(Drawable):
|
||||
# print("Image drawing: {}".format(img_path))
|
||||
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):
|
||||
xBase = self.getX() * self.getCellSize() + self.getOffset()
|
||||
|
@ -111,7 +111,7 @@ class Table(Drawable):
|
||||
self.__status = status
|
||||
|
||||
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)
|
||||
else:
|
||||
size = int(1.4 * self.getCellSize())
|
||||
@ -164,3 +164,15 @@ class Table(Drawable):
|
||||
screen.blit(imagePlate, (xBase + guest1XOffset, yBase + platesYOffset))
|
||||
screen.blit(imagePlate, (xBase + guest2XOffset, 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))
|
||||
|
@ -7,16 +7,43 @@ from kelner.src.components.Kitchen import Kitchen
|
||||
|
||||
|
||||
# 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:
|
||||
# const, minimal distance between objects
|
||||
__MinDistanceX = 1
|
||||
__MinDistanceY = 0
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, kitchenManager):
|
||||
# collection that holds all drawable objects
|
||||
self.__mustRepaint = True
|
||||
self.__drawables = []
|
||||
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
|
||||
def add(self, drawable):
|
||||
@ -52,6 +79,10 @@ class DrawableCollection:
|
||||
break
|
||||
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
|
||||
def getTables(self, status):
|
||||
result = []
|
||||
@ -61,11 +92,10 @@ class DrawableCollection:
|
||||
return result
|
||||
|
||||
def get_kitchen(self):
|
||||
kitchen = None
|
||||
for item in self.__drawables:
|
||||
if isinstance(item, Kitchen):
|
||||
kitchen = item
|
||||
return kitchen
|
||||
return item
|
||||
return None
|
||||
|
||||
def lock(self):
|
||||
self.__waiterLock.acquire()
|
||||
|
@ -23,6 +23,7 @@ class Images(Enum):
|
||||
ToolTip = 16
|
||||
Kitchen = 17
|
||||
Dishes = 18
|
||||
Chicken = 19
|
||||
|
||||
|
||||
class ImageCache:
|
||||
@ -60,7 +61,8 @@ class ImageCache:
|
||||
Images.Guest3: './images/wiking_rudy2.png',
|
||||
Images.ToolTip: './images/tooltip.png',
|
||||
Images.Kitchen: './images/kitchen.png',
|
||||
Images.Dishes: './images/testDishes/'
|
||||
Images.Dishes: './images/testDishes/',
|
||||
Images.Chicken: './images/kurczak.png'
|
||||
}
|
||||
|
||||
def __getFont(self):
|
||||
|
@ -6,9 +6,8 @@ import sys
|
||||
# creates new thread
|
||||
class KitchenManager(threading.Thread):
|
||||
|
||||
def __init__(self, drawable_manager, gridboard):
|
||||
def __init__(self, gridboard):
|
||||
super().__init__()
|
||||
self._drawable_manager = drawable_manager
|
||||
self._gridboard = gridboard
|
||||
self.__runThread = False
|
||||
|
||||
|
120
kelner/src/managers/TableGenerator.py
Normal file
120
kelner/src/managers/TableGenerator.py
Normal 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
|
@ -1,6 +1,7 @@
|
||||
import threading
|
||||
import time
|
||||
import sys
|
||||
from math import sqrt
|
||||
from kelner.src.components.Table import Status
|
||||
from kelner.src.algorithms.AStar.Finder import Finder
|
||||
from kelner.src.algorithms.BFS.BFS import BFS
|
||||
@ -20,24 +21,39 @@ class WaiterManager(threading.Thread):
|
||||
self._menu_manager = menu_manager
|
||||
self._table_manager = table_manager
|
||||
|
||||
def __getNearestTargetPath(self, waiter, target):
|
||||
distance = sys.maxsize
|
||||
nearestTargetPath = None
|
||||
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
|
||||
def __getDistance(self, waiter, tupleXY):
|
||||
dx = waiter.getX() - tupleXY[0]
|
||||
dy = waiter.getY() - tupleXY[1]
|
||||
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)
|
||||
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:
|
||||
origin = (waiter.getX(), waiter.getY())
|
||||
for table in tables:
|
||||
if table.hasOrder():
|
||||
targets = finder.getNeighbours((table.getX(), table.getY()), False)
|
||||
for target in targets:
|
||||
if target is not None:
|
||||
if target == origin:
|
||||
return []
|
||||
else:
|
||||
found.append(target)
|
||||
return self.__sortTargets(waiter, found)
|
||||
|
||||
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)
|
||||
@ -48,15 +64,22 @@ class WaiterManager(threading.Thread):
|
||||
return nearestTargetPath
|
||||
|
||||
def get_specified_path(self, waiter, table):
|
||||
distance = sys.maxsize
|
||||
nearestTargetPath = None
|
||||
reserved_places = self.__drawableManager.getReservedPlaces(waiter)
|
||||
finder = Finder(reserved_places)
|
||||
origin = (waiter.getX(), waiter.getY())
|
||||
targets = finder.getNeighbours((table[0], table[1]), False)
|
||||
for target in targets:
|
||||
if target is not None:
|
||||
if distance > self.__getDistance(waiter, target):
|
||||
path = finder.getPath(origin, target, True)
|
||||
if path:
|
||||
return path
|
||||
result = len(path)
|
||||
if result < distance:
|
||||
distance = result
|
||||
nearestTargetPath = path
|
||||
|
||||
return nearestTargetPath
|
||||
|
||||
def __changeWaiterDirection(self, waiter, x, y):
|
||||
targetDirection = x - waiter.getX(), y - waiter.getY()
|
||||
@ -172,13 +195,14 @@ class WaiterManager(threading.Thread):
|
||||
|
||||
if len(waiter.getAcceptedOrders()) > 1:
|
||||
waiter.set_target('kitchen')
|
||||
path = self.__getNearestTargetPath(waiter, target=waiter.get_target())
|
||||
path = self.__getNearestTargetPath(waiter, [(14, 1), (13, 0)])
|
||||
waiter.make_busy()
|
||||
else:
|
||||
if waiter.get_target() == 'return_order' and waiter.isPathEmpty():
|
||||
print("Order returned")
|
||||
table = self._table_manager.get_table(waiter.get_remaining_positions()[0])
|
||||
table.setStatus(Status.Served)
|
||||
self.__changeWaiterDirection(waiter, table.getX(), table.getY())
|
||||
waiter.get_remaining_positions().pop(0)
|
||||
time.sleep(2)
|
||||
|
||||
@ -187,7 +211,7 @@ class WaiterManager(threading.Thread):
|
||||
path = self.get_specified_path(waiter, waiter.get_remaining_positions()[0])
|
||||
else:
|
||||
waiter.set_target('table')
|
||||
path = self.__getNearestTargetPath(waiter, target='table')
|
||||
path = self.__getNearestTargetPath(waiter)
|
||||
|
||||
waiter.setPath([] if path is None else path)
|
||||
|
||||
@ -201,6 +225,7 @@ class WaiterManager(threading.Thread):
|
||||
if waiter.get_target() == 'kitchen':
|
||||
self._table_manager.pause()
|
||||
kitchen = self.__drawableManager.get_kitchen()
|
||||
self.__changeWaiterDirection(waiter, kitchen.getX(), kitchen.getY())
|
||||
waiter_orders = waiter.getAcceptedOrders()
|
||||
# print("Waiter near kitchen. Collected orders: {}".format(waiter_orders))
|
||||
kitchen.add_orders(waiter_orders)
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user