import pygame import random import time 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 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 run = True # czcionka = pygame.font.SysFont('Arial',50) licznik = 0 ruchy = [] cel2 = [] 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) 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.") 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 pygame.quit()