DSZI_2020_Projekt/Restaurant/main.py
2020-04-27 13:18:18 +02:00

488 lines
16 KiB
Python

import pygame
import random
import time
import queue
import math
from tkinter import messagebox
import tkinter as tk
root = tk.Tk()
root.withdraw() #ukrycie okna tworzonego przez tkinter
pygame.init()
def heuristic(current, goal):
dx = abs(current[0] - goal[0])
dy = abs(current[1] - goal[1])
return math.sqrt(dx * dx + dy * dy)
class Node():
def __init__(self, parent = None, position = None):
self.parent = parent
self.position = position
self.g = 0
self.h = 0
self.f = 0
def __eq__(self, other):
return self.position == other.position
def aStar(start, end):
if end in cantwalk:
print("Wybrano nieodpowiednie pole!")
return []
start_node = Node(None, start)
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end)
end_node.g = end_node.h = end_node.f = 0
open_list = []
closed_list = []
open_list.append(start_node)
while len(open_list) > 0:
current_node = open_list[0]
current_index = 0
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
open_list.pop(current_index)
closed_list.append(current_node)
if current_node == end_node:
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return list(map(lambda t: (t[0], t[1]), path[::-1])) #zwraca odwróconą ściezkę
children = []
# można dodać (-1, -1), (-1, 1), (1, -1), (1, 1) dla poruszania się po przekątnej
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]:
node_position = (current_node.position[0] + new_position[0], current_node.position[1]
+ new_position[1])
if node_position[0] >= (rows - 1) or node_position[0] <= 0 or node_position[1] >= (rows - 1) \
or node_position[1] <= 0: #spr. czy w kracie
continue
if node_position in cantwalk: #spr. czy można przejść
continue
new_node = Node(current_node, node_position)
children.append(new_node)
didBreak = False
for child in children:
didBreak = False
for closed_child in closed_list:
if child == closed_child:
didBreak = True
break
if didBreak:
continue
if child.position in cantwalk:
child.g = current_node.g + 99999
elif child.position in puddles:
child.g = current_node.g + 3
else:
child.g = current_node.g + 1
child.h = heuristic(child.position, end_node.position)
child.f = child.g + child.h
for open_node in open_list:
if child == open_node and child.g > open_node.g:
didBreak = True
break
if didBreak:
continue
open_list.append(child)
class Dish(object):
def __init__(self, dishName, prepTime, eatTime, price):
self.dishName = dishName
self.preparationTime = prepTime
self.eatingTime = eatTime
self.price = price
class Plate(object):
def __init__(self, dish):
self.dishName = dish.dishName
self.isEmpty = False
self.preparationTime = dish.preparationTime
self.eatingTime = dish.eatingTime
self.price = dish.price
def eat(self):
time.sleep(self.eatingTime)
self.isEmpty = True #zjadanie dania jest oznaczeniem talerza jako pusty (metoda będzie wywoływana przez klienta)
class Kitchen(object):
def __init__(self, pos):
self.readyDishes = queue.Queue(32) #kolejka o maksymalnej długości 32
self.orders = queue.Queue(32) #wyskakiwał mi tu błąd - poprawiłam na dużą literę i jest ok
self.pos = pos
def makeDish(self):
if not self.orders.empty():
plate = self.orders.get()
time.sleep(plate.preparationTime) #kuchnia przygotowuje danie przez określony czas
self.readyDishes.put(plate)
def giveDish(self):
if not self.readyDishes.empty():
plate = self.readyDishes.get()
return plate
else:
return None
def draw(self, surface):
image1 = pygame.image.load(r'kitchen1.png')
image1 = pygame.transform.scale(image1, (sizeBetween - 1, sizeBetween - 1))
surface.blit(image1, (13*sizeBetween+1, 0*sizeBetween+1))
image2 = pygame.image.load(r'kitchen2.png')
image2 = pygame.transform.scale(image2, (sizeBetween - 1, sizeBetween - 1))
surface.blit(image2, (14*sizeBetween+1, 0*sizeBetween+1))
image3 = pygame.image.load(r'kitchen3.png')
image3 = pygame.transform.scale(image3, (sizeBetween - 1, sizeBetween - 1))
surface.blit(image3, (13*sizeBetween+1, 1*sizeBetween+1))
image4 = pygame.image.load(r'kitchen4.png')
image4 = pygame.transform.scale(image4, (sizeBetween - 1, sizeBetween - 1))
surface.blit(image4, (14*sizeBetween+1, 1*sizeBetween+1))
class Client(object):
def __init__(self, age, sex, budget):
self.age = age
self.sex = sex
self.myPlate = None
self.budget = budget
self.myTable = 0 #domyślnie klient nie siedzi przy żadnym stole
def takePlateAndEat(self, plate):
self.myPlate = plate
plate.eat()
def takeASeat(self, table):
self.myTable = table
class Table(object):
def __init__(self, pos, capacity):
self.pos = pos
self.capacity = capacity
def move(self, newx, newy): #metoda do ustawiania stołów poprzez podanie nowych współrzędnych
self.pos[0] = newx
self.pos[1] = newy
def draw(self, surface):
image = pygame.image.load(r'Table-croped.png')
image = pygame.transform.scale(image, (sizeBetween - 1, sizeBetween - 1))
i = self.pos[0]
j = self.pos[1]
surface.blit(image, (i*sizeBetween+1, j*sizeBetween+1))
class Waiter(object):
def __init__(self, color, pos, direction):
self.color = color
self.pos = pos #pozycja agenta, zapisana w formie dwuelementowej listy
self.posx = pos[0]
self.posy = pos[1]
self.dirnx = 0 #zmienne dirnx i dirny używane są do ruchu bota i ustalania, w którą stronę jest zwrócony
self.dirny = 1
self.plates = [] #lista niesionych przez agenta talerzy, planowo lista par: (talerz, klient)
self.direction = direction #kierunek, w ktory jest skierowany bot
self.currentRotation = 0
self.rotate = "forward"
self.rotationNumber = 0
def moveRandomly(self, noWalkable):
rand = random.randrange(1, 5, 1) #losuje w zakresie 1-4
#print(rand)
if rand == 1:
self.dirnx = -1
self.dirny = 0
self.direction = 'left'
if self.pos[0] == 0 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable): #zabezpieczenie przed wyjściem bota poza obszar okna w ruchu losowym
self.dirnx *= (-1) #oraz w miejsce, na ktore nie moze wejsc (stoły, kuchania)
self.direction = 'right'
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
elif rand == 2:
self.dirnx = 1
self.dirny = 0
self.direction = 'right'
if self.pos[0] == 14 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
self.dirnx *= (-1)
self.direction = 'left'
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
elif rand == 3:
self.dirnx = 0
self.dirny = -1
if self.pos[1] == 0 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
self.dirny *= (-1)
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
elif rand == 4:
self.dirnx = 0
self.dirny = 1
if self.pos[1] == 14 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
self.dirny *= (-1)
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
def moveWithKeyboard(self, noWalkable): #funkcja testowa - bot sterowany z klawiatury
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
keys = pygame.key.get_pressed()
for key in keys:
if keys[pygame.K_LEFT]:
self.dirnx = -1
self.dirny = 0
self.direction = 'left'
if self.pos[0] == 0 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable): # zabezpieczenie przed wyjściem bota poza obszar okna w ruchu losowym
#self.dirnx *= (-1)
break
else:
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
break
# te break musiałam dodać, bo w przeciwnym wypadku zamiast jednego kroku robił 303 - jeden za drugim
# nie wiem dlaczego tak było, po zmianie sterowania z klawiatury na bota samego w sobie nie powinno
# być z tym problemów, to jest na razie tylko, żeby pokazać, że ten ruch jest
elif keys[pygame.K_RIGHT]:
self.dirnx = 1
self.dirny = 0
self.direction = 'right'
if self.pos[0] == 14 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
#self.dirnx *= (-1)
break
else:
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
break
elif keys[pygame.K_UP]:
self.dirnx = 0
self.dirny = -1
if self.pos[1] == 0 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
#self.dirny *= (-1)
break
else:
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
break
elif keys[pygame.K_DOWN]:
self.dirnx = 0
self.dirny = 1
if self.pos[1] == 14 or ([self.pos[0] + self.dirnx, self.pos[1] + self.dirny] in noWalkable):
#self.dirny *= (-1)
break
else:
self.pos = [self.pos[0] + self.dirnx, self.pos[1] + self.dirny]
break
def resetPosition(self, pos):
self.pos = pos
def takePlates(self, kitchen):
for i in range(2):
plate = kitchen.giveDish()
if plate == None:
break
else:
self.plates.append(plate)
def giveClientPlate(self, client):
plate = self.plates.pop(0)
client.takePlateAndEat(plate)
def rotateRight(self):
self.currentRotation += 90
def rotateLeft(self):
self.currentRotation -= 90
def goForward(self, movex, movey):
self.posx += movex
self.posy += movey
self.pos = (self.posx, self.posy)
def draw(self, surface):
image = pygame.image.load(r'waiter_right.png')
image = pygame.transform.scale(image, (sizeBetween - 1, sizeBetween - 1))
if self.rotate == "right":
self.rotateRight()
elif self.rotate == "left":
self.rotateLeft()
elif self.direction == "forward":
pass
image = pygame.transform.rotate(image, self.currentRotation)
i = self.pos[0]
j = self.pos[1]
surface.blit(image, (i * sizeBetween + 1, j * sizeBetween + 1))
def goByAStar(self, end):
positionList = aStar(self.pos, end)
print(positionList)
if len(positionList) == 0:
messagebox.showerror("BŁĄD!", "Wybrano nieosiągalne pole!")
pygame.quit()
exit()
else:
lenght = len(positionList) - 1
for i in range(lenght):
movex = positionList[i + 1][0] - positionList[i][0]
movey = positionList[i + 1][1] - positionList[i][1]
prevDirection = self.direction
if movex == -1 and movey == 0:
self.direction = 1 #"left"
elif movex == 1 and movey == 0:
self.direction = 3 #"right"
elif movey == 1 and movex == 0:
self.direction = 4 #"down"
else:
self.direction = 2 #"up"
howToRotate = prevDirection - self.direction #działa!
if howToRotate < 0:
self.rotate = "left"
self.rotationNumber = abs(howToRotate)
elif howToRotate > 0:
self.rotate = "right"
self.rotationNumber = abs(howToRotate)
elif howToRotate == 0:
self.rotate = "forward"
self.rotationNumber = 0
#print(self.rotate)
for i in range(self.rotationNumber):
redrawWindow(window)
time.sleep(0.5)
self.rotate = "forward"
self.rotationNumber = 0
self.goForward(movex, movey)
redrawWindow(window)
time.sleep(0.5)
def drawGrid(width, rows, surface):
x = 0
y = 0
for i in range(rows):
x = x + sizeBetween
y = y + sizeBetween
pygame.draw.line(surface, (255, 255, 255), (x, 0), (x, width))
pygame.draw.line(surface, (255, 255, 255), (0, y), (width, y))
def redrawWindow(surface):
surface.fill(beige)
bot.draw(surface)
kitchen.draw(surface)
for i in range(len(tables)):
tables[i].draw(surface)
for i in range(len(puddles)):
image = pygame.image.load(r'puddle.png')
image = pygame.transform.scale(image, (sizeBetween - 1, sizeBetween - 1))
surface.blit(image, (puddles[i][0]* sizeBetween + 1, puddles[i][1]* sizeBetween + 1))
drawGrid(width, rows, surface)
pygame.display.update()
def noWalkable(tables, kitchen):
list = []
for i in range(len(tables)):
list.append(tables[i].pos)
list.append(kitchen.pos)
return list
def main():
global width, rows, bot, beige, white, black, sizeBetween, tables, kitchen, cantwalk, puddles, window
# skróty do kolorów
beige = (255, 205, 178)
white = (255, 255, 255)
black = (0, 0, 0)
width = 600
rows = 15
sizeBetween = width // rows #wielkość pojedynczej kratki
window = pygame.display.set_mode((width, width))
bot = Waiter((255, 0, 0), (12, 8), 2)
tables = []
tables.append(Table((0, 3), 1))
tables.append(Table((0, 6), 1))
tables.append(Table((0, 9), 2))
tables.append(Table((0, 12), 2))
tables.append(Table((4, 4), 2))
tables.append(Table((4, 7), 2))
tables.append(Table((4, 10), 2))
tables.append(Table((4, 13), 2))
tables.append(Table((8, 3), 1))
tables.append(Table((8, 6), 1))
tables.append(Table((8, 9), 2))
tables.append(Table((8, 12), 2))
flag = True
clock = pygame.time.Clock()
kitchen = Kitchen((13, 1))
cantwalk = noWalkable(tables, kitchen) # lista pozycji, na ktore bot nie moze wejsc
puddles = []
puddles.append((7, 10))
puddles.append((2, 5))
puddles.append((3, 12))
puddles.append((10, 3))
puddles.append((6, 2))
puddles.append((12, 10))
puddles.append((1, 4))
while flag:
redrawWindow(window)
#bot.moveRandomly()
goal = (1, 3)
bot.goByAStar(goal)
time.sleep(5)
flag = False
pygame.quit()
exit()
main()