Automatyczny_kelner/main.py

346 lines
12 KiB
Python

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()