diff --git a/main_network.py b/main_network.py new file mode 100644 index 0000000..27ab9aa --- /dev/null +++ b/main_network.py @@ -0,0 +1,544 @@ +import pygame +import random +import time +import pandas as pd +import math +import matplotlib.pyplot as plt + +kuchnia_xy = 0 +pozycja_startowa = 0 +losuj_uklad = False # Gdy True, losuje uklad stolikow oraz przeszkod + +# ------------Ustawienia siatki +blockSize = 60 +rows = 14 +columns = 24 + + +# -----------------------------Inicjacja klas +class Kelner: + def __init__(self, x, y): + self.x = x + self.y = y + self.speed = 80 # od 0 do 100, preferowane 80 + self.stanPrzestrzeni = [0, 0, 0] + self.stan = "stoi" # Stan kelnera: stoi, odbiera lub wraca + self.stolik_docelowy = None # Stolik, do którego idzie kelner + self.chodzi = True + self.cel_x = x + self.cel_y = y + self.kierunek = 0 # 0 - północ, 1 - wschód, 2 - południe, 3 - zachód + self.indexRuchu = 0 + + def wklej(self): + kelnerRotated = pygame.transform.rotate(kelnerImg, -90 * kelner.kierunek) + screen.blit(kelnerRotated, (self.x * blockSize, self.y * blockSize)) + + # def idz_do_stolika(self): + # self.cel_x, self.cel_y = self.stolik_docelowy.x, self.stolik_docelowy.y + # kelner.stan = "odbiera" + + def idz_do_kuchni(self): + self.cel_x, self.cel_y = kuchnia_xy, kuchnia_xy + self.stolik_docelowy = None + kelner.stan = "wraca" + + def obrot_w_lewo(self): + self.kierunek = (self.kierunek - 1) % 4 + self.stanPrzestrzeni[2] = (self.stanPrzestrzeni[2] - 1) % 4 + + def obrot_w_prawo(self): + self.kierunek = (self.kierunek + 1) % 4 + self.stanPrzestrzeni[2] = (self.stanPrzestrzeni[2] + 1) % 4 + + def idz_do_przodu(self): + if self.kierunek == 0: + self.y -= 1 + self.stanPrzestrzeni[1] -= 1 + elif self.kierunek == 1: + self.x += 1 + self.stanPrzestrzeni[0] += 1 + elif self.kierunek == 2: + self.y += 1 + self.stanPrzestrzeni[1] += 1 + elif self.kierunek == 3: + self.x -= 1 + self.stanPrzestrzeni[0] -= 1 + + def wykonajAkcje(self, ruchy): + if self.indexRuchu < len(ruchy): + akcja = ruchy[self.indexRuchu] + if akcja == 'F': + self.idz_do_przodu() + elif akcja == 'L': + self.obrot_w_lewo() + elif akcja == 'R': + self.obrot_w_prawo() + self.indexRuchu += 1 + if self.indexRuchu >= len(ruchy): # Reset po zakończeniu wszystkich ruchów + self.indexRuchu = 0 + + +class Stolik: + def __init__(self, x, y): + self.x = x + self.y = y + self.zamowione = False + + def wklej(self): + screen.blit(stolikImg, (self.x * blockSize, self.y * blockSize)) + + +class Przeszkoda: + def __init__(self, x, y, typ): + self.x = x + self.y = y + self.typ = typ + + # ocena kosztu przeszkody + if self.typ == "sliska podloga": + self.cena = 2 + + elif self.typ == "dywan": + self.cena = 4 + + def wklej(self): + if self.typ == "sliska podloga": + screen.blit(sliskaPodlogaImg, (self.x * blockSize, self.y * blockSize)) + elif self.typ == "dywan": + screen.blit(dywanImg, (self.x * blockSize, self.y * blockSize)) + + +# -----------------Przeszukiwanie przestrzeni stanów + +import heapq + + +def a_star(start, cel, stoliki, przeszkody): + queue = [] # Kolejka priorytetowa + heapq.heappush(queue, (0, start)) # (koszt, stan) + odwiedzone = set([start]) + poprzednicy = {start: (None, None, 0)} # (poprzedni stan, ruch, koszt do tej pory) + + while queue: + obecny_koszt, obecny = heapq.heappop(queue) # pobranie stanu z najniższym kosztem + + if obecny[:2] == cel: + return odtworz_ruchy(poprzednicy, obecny) + + for nastepnik, ruch, koszt_ruchu in generuj_nastepniki_i_ruchy(obecny, stoliki, przeszkody): + nowy_koszt = poprzednicy[obecny][2] + koszt_ruchu # Obliczanie nowego kosztu dojscia do nastepnika + + # nastepnik nie był odwiedzony lub znaleziono tansza sciezke do niego + if nastepnik not in odwiedzone or nowy_koszt < poprzednicy.get(nastepnik, (None, None, float('inf')))[2]: + heapq.heappush(queue, (nowy_koszt + heurystyka(nastepnik, cel), nastepnik)) + poprzednicy[nastepnik] = (obecny, ruch, nowy_koszt) + odwiedzone.add(nastepnik) + return [] + + +def heurystyka(nastepnik, cel): + # Oszacowanie sumy odleglosci w pionie i w poziomie + return abs(nastepnik[0] - cel[0]) + abs(nastepnik[1] - cel[1]) + + +# ----------Funkcja generowania następników dla poszczególnych stanów +def generuj_nastepniki_i_ruchy(stan, stoliki, przeszkody): + x, y, kierunek = stan + ruchy = [] + + # Obrot w lewo + nowy_kierunek = (kierunek - 1) % 4 + ruchy.append(((x, y, nowy_kierunek), 'L', 1)) + + # Obrot w prawo + nowy_kierunek = (kierunek + 1) % 4 + ruchy.append(((x, y, nowy_kierunek), 'R', 1)) + + # Krok do przodu + if kierunek == 0: + nowy_x, nowy_y = x, y - 1 + elif kierunek == 1: + nowy_x, nowy_y = x + 1, y + elif kierunek == 2: + nowy_x, nowy_y = x, y + 1 + elif kierunek == 3: + nowy_x, nowy_y = x - 1, y + + # sprawdzamy, czy następny stan jest w granicach planszy + if 0 <= nowy_x < columns and 0 <= nowy_y < rows: + # sprawdzamy, czy następny stan nie wchodzi w stolik + if not any(stolik.x == nowy_x and stolik.y == nowy_y for stolik in stoliki): + koszt = next( + (przeszkoda.cena for przeszkoda in przeszkody if przeszkoda.x == nowy_x and przeszkoda.y == nowy_y), 1) + ruchy.append(((nowy_x, nowy_y, kierunek), 'F', koszt)) + + return ruchy + + +# -----Funkcja tworząca listę kroków potrzebnych do uzyskania celu +def odtworz_ruchy(poprzednicy, cel): + ruchy = [] + krok = cel + while krok and poprzednicy[krok][0] is not None: + ruchy.append(poprzednicy[krok][1]) + krok = poprzednicy[krok][0] + ruchy.reverse() + return ruchy + +def licz_entropie(data, target_column): + total_rows = len(data) + target_values = data[target_column].unique() + + entropy = 0 + for value in target_values: + value_count = len(data[data[target_column] == value]) + proportion = value_count / total_rows + entropy -= proportion * math.log2(proportion) + return entropy + +def licz_zysk(atrybut,korzen,data): + entropia_wazona = 0 + unique_values = data[atrybut].unique() + for value in unique_values: + subset = data[data[atrybut] == value] + proportion = len(subset) / len(data) + entropia_wazona += proportion * licz_entropie(subset, data.columns[-1]) + + zysk = korzen - entropia_wazona + return zysk + +def szukaj_split(z, atrybuty): + max = 0 + max_atr = "None" + for atrybut in atrybuty: + if z[atrybut]>max: + max = z[atrybut] + max_atr = atrybut + return max_atr + +def GenerujDane(ques): + k = [0,0,0,0,0,0,0,0] + for n in range(8): + k[n] = random.choice([0,1]) + print(ques[n] + str(k[n])) + return k + +def id3(data,mode,klient): + zysk = {} + korzen = licz_entropie(data,data.columns[-1]) + lista = data.columns + for atrybut in lista[:-1]: + zysk[atrybut] = licz_zysk(atrybut,korzen,data) + split = szukaj_split(zysk, data.head(0).columns[:-1]) + if split == "None": + wynik = data.iloc[0, -1] + if wynik == 1 and mode == "klient": + print("Klient zadowolony!") + elif wynik == 0 and mode == "klient": + print("Klient niezadowolony!") + print("---------------------------------------------------------------------------------------") + else: + #print("Split: " + str(split)) + subset0 = data[data[split] == 0] + subset0 = subset0.drop([split], axis=1) + subset1 = data[data[split] == 1] + subset1 = subset1.drop([split], axis=1) + #print("Klient: " + str(klient)) + if len(subset0) < len(data) and len(subset1) < len(data): + if mode == "klient": + if klient[split] == 0: + frames.append(subset0) + else: + frames.append(subset1) + elif mode == "full": + frames.append(subset0) + frames.append(subset1) + if len(frames) > 0: + newData = frames.pop() + id3(newData,mode, klient) + +start = (0, 0, 0) # Początkowy stan +cel = (0, 0) # Docelowe współrzędne + +# --------------Inicjacja obiektów +kelner = Kelner(pozycja_startowa, pozycja_startowa) + +# -----------wspolrzedne stolikow +coords = ["8 4", "16 4", "0 7", "23 7", "12 9", "8 10", "16 10", "4 12", "12 12", "20 12"] + +# -----------wspolrzedne sliskich podlog +coords2 = ["0 2", "0 3", "0 4", "0 5", "4 8", "4 9", "12 2", "12 3", "15 8", "16 8", "19 4", "20 4", "21 4"] + +# -----------wspolrzedne dywanow +coords3 = ["6 0", "6 1", "2 2", "3 2", "4 2", "5 2", "1 5", "6 2", "8 6", "8 7", "20 2", "20 3", "19 9", "20 9", "21 9"] + +# Tworzenie listy stolikow i przeszkod +stoliki = [] +przeszkody = [] +if not losuj_uklad: + for coord in coords: + x, y = map(int, coord.split()) + stoliki.append(Stolik(x, y)) + for coord in coords2: + x, y = map(int, coord.split()) + przeszkody.append(Przeszkoda(x, y, "sliska podloga")) + for coord in coords3: + x, y = map(int, coord.split()) + przeszkody.append(Przeszkoda(x, y, "dywan")) +else: + juzbyly = [] + for j in range(1, rows): + for i in range(columns): + if (random.randrange(7) == 0) and ((i, j - 1) not in juzbyly) and ( + ((i - 1, j - 1) not in juzbyly) or ((i + 1, j - 1) not in juzbyly)): + stoliki.append(Stolik(i, j)) + juzbyly.append((i, j)) + elif random.randrange(9) == 0: + przeszkody.append(Przeszkoda(i, j, "sliska podloga")) + elif random.randrange(12) == 0: + przeszkody.append(Przeszkoda(i, j, "dywan")) + +# stoliki = [] +# for i in range(rows) + +pygame.init() +pygame.display.set_caption("Automatyczny kelner") + +# ----------------wymiary okna +width = columns * blockSize +height = rows * blockSize + +screen = pygame.display.set_mode((width, height)) + +kelnerImg = pygame.image.load("kelner.png") +kelnerImg = pygame.transform.scale(kelnerImg, (blockSize, blockSize)) +stolikImg = pygame.image.load("stolik.png") +stolikImg = pygame.transform.scale(stolikImg, (blockSize, blockSize)) +menuImg = pygame.image.load("menu.png") +menuImg = pygame.transform.scale(menuImg, (blockSize / 2, blockSize / 2)) +kitchenImg = pygame.image.load("kitchen.png") +kitchenImg = pygame.transform.scale(kitchenImg, (blockSize * 2, blockSize * 2)) +sliskaPodlogaImg = pygame.image.load("plama.png") +sliskaPodlogaImg = pygame.transform.scale(sliskaPodlogaImg, (blockSize, blockSize)) +dywanImg = pygame.image.load("dywan.png") +dywanImg = pygame.transform.scale(dywanImg, (blockSize, blockSize)) + + +def kuchnia(x, y): + screen.blit(kitchenImg, (x * blockSize, y * blockSize)) + + +def menu(x, y): + screen.blit(menuImg, (x * blockSize, y * blockSize)) + + +def wypiszOkno(): + screen.fill((0, 0, 0)) + for x in range(0, width, blockSize): + for y in range(0, height, blockSize): + rect = pygame.Rect(x, y, blockSize, blockSize) + pygame.draw.rect(screen, (200, 200, 200), rect, 1) # -------------Wypisz kratę -TA + # pygame.draw.rect(screen, (0, 0, 0), rect, 1) #-------------Wypisz kratę -TA + +def czyZadowolony(): + data = pd.read_csv('zbior_uczacy.csv') + frames = [] + frames.append(data) + ques = ["Czy klient sie usmiecha? ", "Czy zostawil napiwek? ", "Czy zachowywal sie grzecznie? ", + "Czy zjadl cala porcje? ", "Czy zlozyl dodatkowe zamowienia? ", + "Czy wyrazil zainteresowanie karta stalego klienta? ", "Czy zarezerwowal stolik na przyszlosc? ", + "Czy zabral wizytowke? "] + k = GenerujDane(ques) + atrybuty = [] + for column in data.columns[:-1]: + atrybuty.append(column) + klient = {} + i = 0 + for atr in atrybuty: + klient[atr] = k[i] + i = i + 1 + while len(frames) > 0: + data = frames.pop() + id3(data, "klient", klient) + +run = True + +# czcionka = pygame.font.SysFont('Arial',50) + +licznik = 0 +ruchy = [] +cel2 = [] + +klient = {} +frames = [] + +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt + +from sklearn.model_selection import train_test_split +from sklearn.tree import plot_tree, DecisionTreeClassifier + +data = pd.read_csv('zbior_uczacy.csv') +data.head() +#print(heart_data) + +data_x = data.drop('Zadowolony', axis=1) +data_y = data['Zadowolony'] + +data_x_encoded = pd.get_dummies(data_x, drop_first = True) +data_x_encoded.head() + +best_acc = 0 + +from sklearn.tree import DecisionTreeClassifier +from sklearn.metrics import accuracy_score +X_train, X_test, y_train, y_test = train_test_split(data_x_encoded, data_y, test_size=0.3) + +dtree = DecisionTreeClassifier(max_depth=100) +dtree.fit(X_train, y_train) + +fig = plt.figure(figsize=((25,20))) +plot_tree(dtree, + feature_names=data_x_encoded.columns, + class_names=['niezadowolony', 'zadowolony'], + impurity=False, + proportion=False, + filled=True) +fig.savefig('tree.png') + + +#---------------Neural network + +import tensorflow as tf +from tensorflow import keras +import numpy as np +import os +import random +from PIL import Image + +new_model = keras.models.load_model("/home/kwak/PycharmProjects/AutomatycznyKelner/pythonProject1/nn.keras") + +data_cat = ["churros", "cup_cakes", "donuts"] + +img_height = 160 +img_width = 160 + + +def randomImage(img_height, img_width): + folder_path = r"Automatyczny_kelner/onTable_toFillWIthRandomPictures" + files = os.listdir(folder_path) + image_files = [file for file in files if file.endswith(('png', 'jpg', 'jpeg', 'gif'))] + + random_image = random.choice(image_files) + + image_path = os.path.join(folder_path, random_image) + image = Image.open(image_path) + image.show() + + image = image_path + + image_load = tf.keras.utils.load_img(image, target_size=(img_height, img_width)) + img_arr = tf.keras.utils.array_to_img(image_load) + img_bat = tf.expand_dims(img_arr, 0) + + predict = new_model.predict(img_bat) + print(predict) + #predicted_class = np.argmax(predict, axis=-1) + #print(data_cat[int(predicted_class)]) + score = tf.nn.softmax(predict) + print('Food in image is {} with accuracy of {:0.2f}'.format(data_cat[np.argmax(score)], np.max(score) * 100)) + + +while run: + cel2 = list(cel) + + # print(f"{kelner.stanPrzestrzeni}, {cel2}, {kelner.indexRuchu} {kelner.stan}") + wypiszOkno() + kuchnia(kuchnia_xy, kuchnia_xy) + + for stolik in stoliki: + stolik.wklej() + + for przeszkoda in przeszkody: + przeszkoda.wklej() + + kelner.wklej() + + if kelner.stan == "wraca": + menu(kelner.x, kelner.y) + + licznik += 1 + + # ------------weź zamowienie + for stolik in stoliki: + if stolik.zamowione == True: + menu(stolik.x, stolik.y) + if kelner.stan == "stoi": + kelner.stolik_docelowy = stolik + kelner.cel_x, kelner.cel_y = kelner.stolik_docelowy.x, kelner.stolik_docelowy.y - 1 + cel = (kelner.cel_x, kelner.cel_y) + print("Szukam ścieżki do stolika...") + ruchy = a_star(tuple(kelner.stanPrzestrzeni), cel, stoliki, przeszkody) + kelner.stan = "odbiera" + + if ruchy: + print("Znaleziono ścieżkę ruchów: ", ruchy) + czyZadowolony() + else: + print("Nie znaleziono ścieżki do celu.") + + # ----------Losuje stoliki, które dokonają zamówienia + if kelner.stan == "stoi": + for stolik in stoliki: + if stolik.zamowione == True: + break + for i in range(len(stoliki)): + if random.randrange(2) == 1: + stoliki[i].zamowione = True + + # print(kelner.stan)--------------------------Wypisuje stan kelnera + # print(f"{kelner.x} {kelner.y}")-------------Wypisuje wspolrzedne kelnera + + # ----------------Zmiana pozycji kelnera + if kelner.chodzi == True and licznik % (101 - kelner.speed) == 0 and kelner.stanPrzestrzeni[ + :2] != cel2: # ograniczenie prędkości + kelner.wykonajAkcje(ruchy) + + if kelner.stanPrzestrzeni[:2] == cel2: + if kelner.stan == "odbiera" and kelner.x == kelner.stolik_docelowy.x and kelner.y == kelner.stolik_docelowy.y - 1: + kelner.stolik_docelowy.zamowione = False + kelner.idz_do_kuchni() + cel = (kelner.cel_x, kelner.cel_y) + print("Szukam ścieżki do kuchni...") + ruchy = a_star(tuple(kelner.stanPrzestrzeni), cel, stoliki, przeszkody) + if ruchy: + print("Znaleziono ścieżkę ruchów: ", ruchy) + else: + print("Nie znaleziono ścieżki do celu.") + + # ---------neural_network + randomImage(img_height, img_width) + + elif kelner.stan == "wraca" and kelner.x == kuchnia_xy and kelner.y == kuchnia_xy: + kelner.stan = "stoi" + + time.sleep(0.001) + + key = pygame.key.get_pressed() + pygame.display.update() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + run = False +#------------------------------------------------------------------------------------------------------------------ + + +''' +frames.clear() +frames.append(data) +while len(frames) > 0: + data = frames.pop() + id3(data,"full") +''' +pygame.quit() \ No newline at end of file diff --git a/neural_network.py b/neural_network.py new file mode 100644 index 0000000..cc9b171 --- /dev/null +++ b/neural_network.py @@ -0,0 +1,89 @@ +#https://youtu.be/V61xy1ZnVTM?si=ZpPwSP5eOnaItPn2 +#https://www.kaggle.com/datasets/fadwateimi/food-plates2 + +import numpy as np +#import pandas as pd +import matplotlib.pyplot as plt +import tensorflow as tf + +from tensorflow import keras +from tensorflow.keras import layers + +def wykres(epochs_size): + epochs_range = range(epochs_size) + plt.figure(figsize=(8,8)) + plt.subplot(1,2,1) + plt.plot(epochs_range,history.history['accuracy'], label = 'Training Accuracy') + plt.plot(epochs_range, history.history['val_accuracy'], label='Validation Accuracy') + plt.title('Accuracy') + + plt.subplot(1, 2, 2) + plt.plot(epochs_range, history.history['loss'], label='Training Loss') + plt.plot(epochs_range, history.history['val_loss'], label='Validation Loss') + plt.title('Loss') + + plt.show() + +trainset_path = r"Automatyczny_kelner/trainset" +testset_path = r"Automatyczny_kelner/testset" +useset_path = r"Automatyczny_kelner/validationset" + +img_width = 180 +img_height = 180 + +trainset = tf.keras.utils.image_dataset_from_directory( + trainset_path, + shuffle = True, + image_size = (img_width, img_height), + batch_size = 32, + validation_split = False +) + +data_cat = trainset.class_names + +useset = tf.keras.utils.image_dataset_from_directory( + useset_path, + shuffle = True, + image_size = (img_height, img_width), + batch_size = 32, + validation_split = False +) + +testset = tf.keras.utils.image_dataset_from_directory( + testset_path, + shuffle = True, + image_size = (img_height, img_width), + batch_size = 32, + validation_split = False +) + +plt.figure(figsize = (10, 10)) +for image, labels in trainset.take(1): + for i in range(4): + plt.subplot(1, 4, i+1) + plt.imshow(image[i].numpy().astype('uint8')) + plt.title(data_cat[labels[i]]) + +from tensorflow.keras.models import Sequential + + +model = Sequential([ + layers.Rescaling(1./255), + layers.Conv2D(16, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(32, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Conv2D(64, 3, padding='same', activation='relu'), + layers.MaxPooling2D(), + layers.Flatten(), + layers.Dropout(0.2), + layers.Dense(128), + layers.Dense(len(data_cat)) +]) + +model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) + +epochs_size = 25 +history = model.fit(trainset, validation_data = useset, epochs = epochs_size) + +model.save("nn.keras") diff --git a/nn.keras b/nn.keras new file mode 100644 index 0000000..ba716f9 Binary files /dev/null and b/nn.keras differ