Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a1c9425a65 | ||
|
a4cf816bf2 | ||
|
a6d3bd8640 |
@ -4,4 +4,7 @@
|
|||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (ProjektAI)" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (ProjektAI)" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PyCharmProfessionalAdvertiser">
|
||||||
|
<option name="shown" value="true" />
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
26
README.md
26
README.md
@ -1,26 +0,0 @@
|
|||||||
## Table of contents
|
|
||||||
* [General info](#general-info)
|
|
||||||
* [Technologies](#technologies)
|
|
||||||
* [Setup](#setup)
|
|
||||||
|
|
||||||
## General info
|
|
||||||
This is AI project of autonomic waiter that recognizes images of placed ordes with CNN algorithm. Orders are generated using the decision tree algoritm while tables by generic algorithm.
|
|
||||||
|
|
||||||
Table of contents
|
|
||||||
* [General info](#general-info)
|
|
||||||
* [Technologies](#technologies)
|
|
||||||
* [Setup](#setup)
|
|
||||||
|
|
||||||
## Technologies
|
|
||||||
Project is created with:
|
|
||||||
* Python 64-bit: 3.6
|
|
||||||
* Tensorflow: 2.0.0
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
The `requirements.txt` file should list all Python libraries that your notebooks
|
|
||||||
depend on, and they will be installed using:
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
|||||||
|
|
||||||
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)
|
|
@ -1,82 +0,0 @@
|
|||||||
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()
|
|
@ -1,22 +0,0 @@
|
|||||||
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: 5.1 KiB After Width: | Height: | Size: 140 KiB |
Binary file not shown.
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 850 B |
112
kelner/main.py
112
kelner/main.py
@ -1,20 +1,21 @@
|
|||||||
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.TableGenerator import TableGenerator
|
from kelner.src.managers.TableManager import TableManager
|
||||||
|
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
|
||||||
from kelner.src.algorithms.FoodNet import classify
|
from kelner.src.algorithms.FoodNet import classify
|
||||||
import kelner.src.settings as settings
|
import kelner.src.settings as settings
|
||||||
|
# import time
|
||||||
|
|
||||||
Scale = 1.5 # scale for all images used within project
|
# create screen consts
|
||||||
|
Scale = 1 # 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
|
||||||
@ -23,10 +24,13 @@ 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': []}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# initialize background
|
# initialize background
|
||||||
gridBoard = GridBoard(ScreenWidth, ScreenHeight)
|
gridBoard = GridBoard(ScreenWidth, ScreenHeight)
|
||||||
|
|
||||||
classify.join('/src/algorithms/FoodNet/classify.py')
|
|
||||||
|
classify.join('C:/Users/Maria/Desktop/ProjektAI/kelner/src/algorithms/FoodNet/classify.py')
|
||||||
|
|
||||||
# start loading prediction model
|
# start loading prediction model
|
||||||
settings.init()
|
settings.init()
|
||||||
@ -36,15 +40,13 @@ 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(kitchenManager)
|
drawableManager = DrawableCollection()
|
||||||
|
|
||||||
# initialize menu manager
|
# initialize menu manager
|
||||||
menuManager = MenuManager()
|
menuManager = MenuManager()
|
||||||
|
|
||||||
##TESTING THE DECISION TREE
|
# TESTING THE DECISION TREE
|
||||||
# Testing Data
|
# Testing Data
|
||||||
testing_db = [
|
testing_db = [
|
||||||
[1, 0, 0, 0, "Kurczak"],
|
[1, 0, 0, 0, "Kurczak"],
|
||||||
@ -79,16 +81,48 @@ else:
|
|||||||
print("test4: fail")
|
print("test4: fail")
|
||||||
|
|
||||||
# initialize waiter component
|
# initialize waiter component
|
||||||
waiter1 = Waiter(7, 4, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
|
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)
|
||||||
|
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
tableGenerator = TableGenerator(GridCountX, GridCountY, 1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset, drawableManager)
|
# My comment
|
||||||
tableGenerator.start()
|
# 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()
|
||||||
|
|
||||||
# main loop
|
# main loop
|
||||||
running = True
|
running = True
|
||||||
@ -96,12 +130,56 @@ while running:
|
|||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
tableGenerator.stop()
|
tableTask.stop()
|
||||||
drawableManager.stop()
|
waiter1Task.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 call to forceRepaint()
|
# is set only on initial paint or after keyboard event or call to forceRepaint()
|
||||||
if drawableManager.mustRepaint():
|
if drawableManager.mustRepaint():
|
||||||
if not kitchenManager.is_running():
|
if not kitchenManager.is_running():
|
||||||
gridBoard.reinitialize()
|
gridBoard.reinitialize()
|
||||||
|
@ -2,7 +2,6 @@ from collections import defaultdict
|
|||||||
from shutil import copytree, rmtree, copy
|
from shutil import copytree, rmtree, copy
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import os
|
import os
|
||||||
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
|
|
||||||
import threading
|
import threading
|
||||||
from tensorflow.keras.models import load_model
|
from tensorflow.keras.models import load_model
|
||||||
import kelner.src.settings as settings
|
import kelner.src.settings as settings
|
||||||
@ -11,7 +10,7 @@ import kelner.src.settings as settings
|
|||||||
#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
|
||||||
|
|
||||||
|
|
||||||
# VISUALIZE DATA #
|
# VISUALIZE DATA #
|
||||||
|
@ -6,10 +6,10 @@ from os.path import isfile, join
|
|||||||
from tensorflow import keras
|
from tensorflow import keras
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
MACARONS_DIR = './././images/dataset/macarons'
|
MACARONS_DIR = '/kelner/images/dataset/macarons'
|
||||||
PIZZA_DIR = './././images/dataset/pizza'
|
PIZZA_DIR = '/kelner/images/dataset/pizza'
|
||||||
FFRIES_DIR = './././images/dataset/ffries'
|
FFRIES_DIR = '/kelner/images/dataset/ffries'
|
||||||
PEAS_DIR = './././images/dataset/peas'
|
PEAS_DIR = '/kelner/src/images/dataset/peas'
|
||||||
COUNT = 10
|
COUNT = 10
|
||||||
SIZE = 128, 128
|
SIZE = 128, 128
|
||||||
|
|
||||||
|
@ -1,304 +0,0 @@
|
|||||||
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()
|
|
||||||
"""
|
|
@ -1,33 +0,0 @@
|
|||||||
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,3 +1,5 @@
|
|||||||
|
from kelner.src.managers.ImageCache import ImageCache, Images
|
||||||
|
|
||||||
|
|
||||||
class Drawable:
|
class Drawable:
|
||||||
|
|
||||||
@ -60,3 +62,15 @@ 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,15 +1,18 @@
|
|||||||
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, x, y, minX, maxX, minY, maxY, cellSize, offset):
|
def __init__(self, minX, maxX, minY, maxY, cellSize, offset):
|
||||||
# call base class constructor
|
# call base class constructor
|
||||||
super().__init__(x, y, minX, maxX, minY, maxY, cellSize, offset)
|
super().__init__(14, 0, 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')
|
||||||
@ -89,17 +92,7 @@ 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, Images.Chicken]:
|
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
|
||||||
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,15 +164,3 @@ 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,43 +7,16 @@ 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, kitchenManager):
|
def __init__(self):
|
||||||
# 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):
|
||||||
@ -79,10 +52,6 @@ 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 = []
|
||||||
@ -92,10 +61,11 @@ 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):
|
||||||
return item
|
kitchen = item
|
||||||
return None
|
return kitchen
|
||||||
|
|
||||||
def lock(self):
|
def lock(self):
|
||||||
self.__waiterLock.acquire()
|
self.__waiterLock.acquire()
|
||||||
|
@ -23,7 +23,6 @@ class Images(Enum):
|
|||||||
ToolTip = 16
|
ToolTip = 16
|
||||||
Kitchen = 17
|
Kitchen = 17
|
||||||
Dishes = 18
|
Dishes = 18
|
||||||
Chicken = 19
|
|
||||||
|
|
||||||
|
|
||||||
class ImageCache:
|
class ImageCache:
|
||||||
@ -61,8 +60,7 @@ 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,8 +6,9 @@ import sys
|
|||||||
# creates new thread
|
# creates new thread
|
||||||
class KitchenManager(threading.Thread):
|
class KitchenManager(threading.Thread):
|
||||||
|
|
||||||
def __init__(self, gridboard):
|
def __init__(self, drawable_manager, gridboard):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self._drawable_manager = drawable_manager
|
||||||
self._gridboard = gridboard
|
self._gridboard = gridboard
|
||||||
self.__runThread = False
|
self.__runThread = False
|
||||||
|
|
||||||
|
@ -1,120 +0,0 @@
|
|||||||
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,7 +1,6 @@
|
|||||||
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
|
||||||
@ -21,39 +20,24 @@ 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 __getDistance(self, waiter, tupleXY):
|
def __getNearestTargetPath(self, waiter, target):
|
||||||
dx = waiter.getX() - tupleXY[0]
|
distance = sys.maxsize
|
||||||
dy = waiter.getY() - tupleXY[1]
|
nearestTargetPath = None
|
||||||
return sqrt(dx * dx + dy * dy)
|
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
|
||||||
|
|
||||||
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)
|
||||||
if tables:
|
finder = Finder(reservedPlaces)
|
||||||
origin = (waiter.getX(), waiter.getY())
|
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:
|
||||||
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 == origin:
|
if target is not None:
|
||||||
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)
|
path = finder.getPath(origin, target, True)
|
||||||
if path:
|
if path:
|
||||||
result = len(path)
|
result = len(path)
|
||||||
@ -64,22 +48,15 @@ class WaiterManager(threading.Thread):
|
|||||||
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 distance > self.__getDistance(waiter, target):
|
if target is not None:
|
||||||
path = finder.getPath(origin, target, True)
|
path = finder.getPath(origin, target, True)
|
||||||
if path:
|
if path:
|
||||||
result = len(path)
|
return 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()
|
||||||
@ -195,14 +172,13 @@ 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, [(14, 1), (13, 0)])
|
path = self.__getNearestTargetPath(waiter, target=waiter.get_target())
|
||||||
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)
|
||||||
|
|
||||||
@ -211,7 +187,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)
|
path = self.__getNearestTargetPath(waiter, target='table')
|
||||||
|
|
||||||
waiter.setPath([] if path is None else path)
|
waiter.setPath([] if path is None else path)
|
||||||
|
|
||||||
@ -225,7 +201,6 @@ 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.
Binary file not shown.
@ -1,6 +0,0 @@
|
|||||||
tensorflow==2.0.0
|
|
||||||
pygame==1.9.6
|
|
||||||
numpy==1.18.4
|
|
||||||
Pillow==7.1.2
|
|
||||||
Keras-Applications==1.0.8
|
|
||||||
Keras-Preprocessing==1.1.0
|
|
Loading…
Reference in New Issue
Block a user