added A* algorithm and new types of tiles with different prices
This commit is contained in:
parent
b6879f3c77
commit
2e1edf91c4
141
main.py
141
main.py
|
@ -1,11 +1,10 @@
|
||||||
import pygame
|
import pygame
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import numpy
|
|
||||||
import threading
|
|
||||||
|
|
||||||
kuchnia_xy = 0
|
kuchnia_xy = 0
|
||||||
pozycja_startowa = 0
|
pozycja_startowa = 0
|
||||||
|
losuj_uklad = False #Gdy True, losuje uklad stolikow oraz przeszkod
|
||||||
|
|
||||||
#------------Ustawienia siatki
|
#------------Ustawienia siatki
|
||||||
blockSize = 60
|
blockSize = 60
|
||||||
|
@ -17,7 +16,7 @@ class Kelner:
|
||||||
def __init__(self, x, y):
|
def __init__(self, x, y):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.speed = 70 # od 0 do 100, preferowane 70
|
self.speed = 80 # od 0 do 100, preferowane 80
|
||||||
self.stanPrzestrzeni = [0,0,0]
|
self.stanPrzestrzeni = [0,0,0]
|
||||||
self.stan = "stoi" # Stan kelnera: stoi, odbiera lub wraca
|
self.stan = "stoi" # Stan kelnera: stoi, odbiera lub wraca
|
||||||
self.stolik_docelowy = None # Stolik, do którego idzie kelner
|
self.stolik_docelowy = None # Stolik, do którego idzie kelner
|
||||||
|
@ -86,43 +85,69 @@ class Stolik:
|
||||||
def wklej(self):
|
def wklej(self):
|
||||||
screen.blit(stolikImg, (self.x * blockSize, self.y * blockSize))
|
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
|
#-----------------Przeszukiwanie przestrzeni stanów
|
||||||
|
|
||||||
from collections import deque
|
import heapq
|
||||||
|
|
||||||
def bfs(start, cel, stoliki):
|
def a_star(start, cel, stoliki, przeszkody):
|
||||||
queue = deque([start])
|
queue = [] # Kolejka priorytetowa
|
||||||
|
heapq.heappush(queue, (0, start)) # (koszt, stan)
|
||||||
odwiedzone = set([start])
|
odwiedzone = set([start])
|
||||||
poprzednik = {start: (None, None)} # Słownik ścieżek (stan, ruch)
|
poprzednicy = {start: (None, None, 0)} # (poprzedni stan, ruch, koszt do tej pory)
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
obecny = queue.popleft()
|
obecny_koszt, obecny = heapq.heappop(queue) # pobranie stanu z najniższym kosztem
|
||||||
|
|
||||||
if obecny[:2] == cel:
|
if obecny[:2] == cel:
|
||||||
return odtworz_ruchy(poprzednik, obecny)
|
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
|
||||||
|
|
||||||
for sasiad, ruch in generuj_nastepniki_i_ruchy(obecny, stoliki):
|
#nastepnik nie był odwiedzony lub znaleziono tansza sciezke do niego
|
||||||
if sasiad not in odwiedzone:
|
if nastepnik not in odwiedzone or nowy_koszt < poprzednicy.get(nastepnik, (None, None, float('inf')))[2]:
|
||||||
odwiedzone.add(sasiad)
|
heapq.heappush(queue, (nowy_koszt + heurystyka(nastepnik, cel), nastepnik))
|
||||||
queue.append(sasiad)
|
poprzednicy[nastepnik] = (obecny, ruch, nowy_koszt)
|
||||||
poprzednik[sasiad] = (obecny, ruch)
|
odwiedzone.add(nastepnik)
|
||||||
|
return []
|
||||||
|
|
||||||
return [] # Cel nie został znaleziony
|
|
||||||
|
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
|
#----------Funkcja generowania następników dla poszczególnych stanów
|
||||||
def generuj_nastepniki_i_ruchy(stan, stoliki):
|
def generuj_nastepniki_i_ruchy(stan, stoliki, przeszkody):
|
||||||
x, y, kierunek = stan
|
x, y, kierunek = stan
|
||||||
ruchy = []
|
ruchy = []
|
||||||
|
|
||||||
# Obrot w lewo
|
# Obrot w lewo
|
||||||
nowy_kierunek = (kierunek - 1) % 4
|
nowy_kierunek = (kierunek - 1) % 4
|
||||||
ruchy.append(((x, y, nowy_kierunek), 'L'))
|
ruchy.append(((x, y, nowy_kierunek), 'L', 1))
|
||||||
|
|
||||||
# Obrot w prawo
|
# Obrot w prawo
|
||||||
nowy_kierunek = (kierunek + 1) % 4
|
nowy_kierunek = (kierunek + 1) % 4
|
||||||
ruchy.append(((x, y, nowy_kierunek), 'R'))
|
ruchy.append(((x, y, nowy_kierunek), 'R', 1))
|
||||||
|
|
||||||
# Krok do przodu
|
# Krok do przodu
|
||||||
if kierunek == 0:
|
if kierunek == 0:
|
||||||
|
@ -137,37 +162,66 @@ def generuj_nastepniki_i_ruchy(stan, stoliki):
|
||||||
#sprawdzamy, czy następny stan jest w granicach planszy
|
#sprawdzamy, czy następny stan jest w granicach planszy
|
||||||
if 0 <= nowy_x < columns and 0 <= nowy_y < rows:
|
if 0 <= nowy_x < columns and 0 <= nowy_y < rows:
|
||||||
#sprawdzamy, czy następny stan nie wchodzi w stolik
|
#sprawdzamy, czy następny stan nie wchodzi w stolik
|
||||||
if (nowy_x, nowy_y) not in stoliki:
|
if not any(stolik.x == nowy_x and stolik.y == nowy_y for stolik in stoliki):
|
||||||
ruchy.append(((nowy_x, nowy_y, kierunek), 'F'))
|
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
|
return ruchy
|
||||||
|
|
||||||
|
|
||||||
#-----Funkcja tworząca listę kroków potrzebnych do uzyskania celu
|
#-----Funkcja tworząca listę kroków potrzebnych do uzyskania celu
|
||||||
def odtworz_ruchy(poprzednicy, cel):
|
def odtworz_ruchy(poprzednicy, cel):
|
||||||
ruchy = []
|
ruchy = []
|
||||||
krok = cel
|
krok = cel
|
||||||
while poprzednicy[krok][0] is not None:
|
while krok and poprzednicy[krok][0] is not None:
|
||||||
ruchy.append(poprzednicy[krok][1])
|
ruchy.append(poprzednicy[krok][1])
|
||||||
krok = poprzednicy[krok][0]
|
krok = poprzednicy[krok][0]
|
||||||
ruchy.reverse()
|
ruchy.reverse()
|
||||||
return ruchy
|
return ruchy
|
||||||
|
|
||||||
|
|
||||||
start = (0, 0, 0) # Początkowy stan
|
start = (0, 0, 0) # Początkowy stan
|
||||||
cel = (0, 0) # Docelowe współrzędne
|
cel = (0, 0) # Docelowe współrzędne
|
||||||
|
|
||||||
|
|
||||||
#--------------Inicjacja obiektów
|
#--------------Inicjacja obiektów
|
||||||
kelner = Kelner(pozycja_startowa,pozycja_startowa)
|
kelner = Kelner(pozycja_startowa,pozycja_startowa)
|
||||||
|
|
||||||
#-----------wspolrzedne stolikow
|
#-----------wspolrzedne stolikow
|
||||||
coords = ["8 10", "4 12", "16 10", "12 12", "20 12", "12 9", "0 6", "8 4", "16 4", "23 6"]
|
coords = ["8 4", "16 4", "0 7", "23 7", "12 9", "8 10", "16 10", "4 12", "12 12", "20 12"]
|
||||||
|
|
||||||
#Tworzenie listy stolikow
|
#-----------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 = []
|
stoliki = []
|
||||||
for coord in coords:
|
przeszkody = []
|
||||||
x, y = map(int, coord.split())
|
if not losuj_uklad:
|
||||||
stoliki.append(Stolik(x, y))
|
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.init()
|
||||||
pygame.display.set_caption("Automatyczny kelner")
|
pygame.display.set_caption("Automatyczny kelner")
|
||||||
|
@ -186,6 +240,10 @@ menuImg = pygame.image.load("menu.png")
|
||||||
menuImg = pygame.transform.scale(menuImg, (blockSize / 2, blockSize / 2))
|
menuImg = pygame.transform.scale(menuImg, (blockSize / 2, blockSize / 2))
|
||||||
kitchenImg = pygame.image.load("kitchen.png")
|
kitchenImg = pygame.image.load("kitchen.png")
|
||||||
kitchenImg = pygame.transform.scale(kitchenImg, (blockSize * 2, blockSize * 2))
|
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):
|
def kuchnia(x, y):
|
||||||
screen.blit(kitchenImg, (x * blockSize, y * blockSize))
|
screen.blit(kitchenImg, (x * blockSize, y * blockSize))
|
||||||
|
@ -193,26 +251,13 @@ def kuchnia(x, y):
|
||||||
def menu(x, y):
|
def menu(x, y):
|
||||||
screen.blit(menuImg, (x * blockSize, y * blockSize))
|
screen.blit(menuImg, (x * blockSize, y * blockSize))
|
||||||
|
|
||||||
kosztKosztownejPlytki = 5
|
|
||||||
|
|
||||||
def kosztownaPlytka(x, y):
|
|
||||||
if x > 60*4 and x < 60*7 and y < 60*9:
|
|
||||||
return True
|
|
||||||
if x > 60*13 and x < 60*16 and y > 60*5:
|
|
||||||
return True
|
|
||||||
if x > 60*20 and y < 60*9 and y > 60*3:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def wypiszOkno():
|
def wypiszOkno():
|
||||||
screen.fill((0, 0, 0))
|
screen.fill((0, 0, 0))
|
||||||
for x in range(0, width, blockSize):
|
for x in range(0, width, blockSize):
|
||||||
for y in range(0, height, blockSize):
|
for y in range(0, height, blockSize):
|
||||||
rect = pygame.Rect(x, y, blockSize, blockSize)
|
rect = pygame.Rect(x, y, blockSize, blockSize)
|
||||||
if kosztownaPlytka(x, y):
|
pygame.draw.rect(screen, (200, 200, 200), rect, 1) #-------------Wypisz kratę -TA
|
||||||
pygame.draw.rect(screen, (200, 0, 0), rect, 1)
|
#pygame.draw.rect(screen, (0, 0, 0), rect, 1) #-------------Wypisz kratę -TA
|
||||||
else:
|
|
||||||
pygame.draw.rect(screen, (200, 200, 200), rect, 1) #-------------Wypisz kratę -TA
|
|
||||||
|
|
||||||
run = True
|
run = True
|
||||||
|
|
||||||
|
@ -223,7 +268,6 @@ ruchy = []
|
||||||
cel2 = []
|
cel2 = []
|
||||||
|
|
||||||
while run:
|
while run:
|
||||||
stoliki_pozycje = [(stolik.x, stolik.y) for stolik in stoliki]
|
|
||||||
cel2 = list(cel)
|
cel2 = list(cel)
|
||||||
|
|
||||||
#print(f"{kelner.stanPrzestrzeni}, {cel2}, {kelner.indexRuchu} {kelner.stan}")
|
#print(f"{kelner.stanPrzestrzeni}, {cel2}, {kelner.indexRuchu} {kelner.stan}")
|
||||||
|
@ -233,13 +277,16 @@ while run:
|
||||||
for stolik in stoliki:
|
for stolik in stoliki:
|
||||||
stolik.wklej()
|
stolik.wklej()
|
||||||
|
|
||||||
|
for przeszkoda in przeszkody:
|
||||||
|
przeszkoda.wklej()
|
||||||
|
|
||||||
kelner.wklej()
|
kelner.wklej()
|
||||||
|
|
||||||
if kelner.stan == "wraca":
|
if kelner.stan == "wraca":
|
||||||
menu(kelner.x, kelner.y)
|
menu(kelner.x, kelner.y)
|
||||||
|
|
||||||
licznik += 1
|
licznik += 1
|
||||||
|
|
||||||
#------------weź zamowienie
|
#------------weź zamowienie
|
||||||
for stolik in stoliki:
|
for stolik in stoliki:
|
||||||
if stolik.zamowione == True:
|
if stolik.zamowione == True:
|
||||||
|
@ -249,7 +296,7 @@ while run:
|
||||||
kelner.cel_x, kelner.cel_y = kelner.stolik_docelowy.x, kelner.stolik_docelowy.y - 1
|
kelner.cel_x, kelner.cel_y = kelner.stolik_docelowy.x, kelner.stolik_docelowy.y - 1
|
||||||
cel = (kelner.cel_x, kelner.cel_y)
|
cel = (kelner.cel_x, kelner.cel_y)
|
||||||
print("Szukam ścieżki do stolika...")
|
print("Szukam ścieżki do stolika...")
|
||||||
ruchy = bfs(tuple(kelner.stanPrzestrzeni), cel, stoliki_pozycje)
|
ruchy = a_star(tuple(kelner.stanPrzestrzeni), cel, stoliki, przeszkody)
|
||||||
kelner.stan = "odbiera"
|
kelner.stan = "odbiera"
|
||||||
if ruchy:
|
if ruchy:
|
||||||
print("Znaleziono ścieżkę ruchów: ", ruchy)
|
print("Znaleziono ścieżkę ruchów: ", ruchy)
|
||||||
|
@ -280,7 +327,7 @@ while run:
|
||||||
kelner.idz_do_kuchni()
|
kelner.idz_do_kuchni()
|
||||||
cel = (kelner.cel_x, kelner.cel_y)
|
cel = (kelner.cel_x, kelner.cel_y)
|
||||||
print("Szukam ścieżki do kuchni...")
|
print("Szukam ścieżki do kuchni...")
|
||||||
ruchy = bfs(tuple(kelner.stanPrzestrzeni), cel, stoliki_pozycje)
|
ruchy = a_star(tuple(kelner.stanPrzestrzeni), cel, stoliki, przeszkody)
|
||||||
if ruchy:
|
if ruchy:
|
||||||
print("Znaleziono ścieżkę ruchów: ", ruchy)
|
print("Znaleziono ścieżkę ruchów: ", ruchy)
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue