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"?>
|
<?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>
|
@ -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>
|
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 |
115
kelner/main.py
115
kelner/main.py
@ -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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
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)
|
|
||||||
|
@ -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()
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user