Compare commits
2 Commits
master
...
szukanie_s
Author | SHA1 | Date | |
---|---|---|---|
![]() |
32c80c0c0e | ||
![]() |
1e265ec281 |
@ -1,141 +0,0 @@
|
||||
## Podprojekt: drzewa decyzyjne
|
||||
### Andrzej Preibisz
|
||||
|
||||
#### Opis problemu
|
||||
Metodą uczenia, którą postanowiłem zaimplementować w projekcie były
|
||||
drzewa decyzyjne. Pola reprezentujące regały, lub chłodziarki
|
||||
różnią się między sobą temperaturą, oraz wilgotnością powietrza w danym miejscu.
|
||||
Paczki z kolei mogą zawierać towary następujących rodzajów:
|
||||
- towar zwykły(normal)
|
||||
- mrożony(freezed)
|
||||
- kruchy(fragile)
|
||||
- łatwo niszczejący pod wpływem wilgoci (keep_dry)
|
||||
- łatwopalne(flammable)
|
||||
|
||||
Paczki zawierające określony rodzaj towarów mają pewne parametry
|
||||
środowiskowe, w których zdecydowanie nie powinno się danego typu towaru
|
||||
przechowywać. Jako przykład może posłużyć mrożone jedzenie, którego stan
|
||||
stosunkowo szybko ulegnie pogorszeniu w temperaturze dodatniej, lub lakier,
|
||||
który zdecydowanie nie powinien znaleźć się w części magazynu, gdzie panuje temperatura 30 stopni.
|
||||
|
||||
Celem drzewa decyzyjnego jest w tym wypadku przewidzenie prawdopodobnej szansy na to, że towar po przechowywaniu
|
||||
na danym regale przez dłuższy czas będzie w dobrym stanie.
|
||||
|
||||
##### Zastosowane drzewo
|
||||
Drzewa decyzyjne dzielą się ogólnie na dwa rodzaje - drzew klasyfikujących, lub drzew regresyjnych.
|
||||
Drzewo klasyfikujące pozwala podzielić zmienna przewidywaną na kategorie, na przykład Tak i Nie.
|
||||
|
||||
Drzewo regresyjne z kolei dostarczy nam informacji o oczekiwanej wartości zmiennej estymowanej przy
|
||||
danej wartości atrybutów.
|
||||
|
||||
W świecie projektu różny rodzaj towarów ma różne "progi", od których można go kłaść na regale X,
|
||||
na przykład kładąc paczkę z lakierem/benzyną na regale lepiej mieć trochę większą pewność, że towar nie nagrzeje się nadmiernie, aniżeli
|
||||
kładąc książkę - że nie zniszczeje od wilgoci. W związku z tym zamiast prostej odpowiedzi Tak/Nie na pytanie
|
||||
czy dany obiekt można położyć na danym regale potrzebna była przewidywana wartość prawdopodobieństwa że w danym miejscu
|
||||
zachowa się on w dobrym stanie. Wszystkie te progi wynoszą odpowiednio:
|
||||
``` python
|
||||
PACKAGE_PLACE_TRESHOLD = {
|
||||
"normal": 0.8,
|
||||
"freezed": 0.85,
|
||||
"fragile": 0.85,
|
||||
"flammable": 0.9,
|
||||
"keep_dry": 0.8
|
||||
}
|
||||
```
|
||||
Zdecydowałem się więc na wybór drzewa regresyjnego.
|
||||
Biblioteką której użyłem w celu implementacji drzewa jest scikit-learn.
|
||||
Najważniejszym problemem oprócz dokładności oszacowań dokonanych przy pomocy drzewa było uniknięcie overfittingu(przepasowania),
|
||||
czyli sytuacji, w której drzewo perfekcyjnie dopasuje się do danych ze zbioru uczącego, jednak
|
||||
z danymi spoza tego zbioru poradzi sobie już dużo gorzej. Oprócz błędnej oceny danych innych niż ze zbioru uczącego sygnałem wskazującym na overfitting drzewa
|
||||
jest zbyt duża jego głębokość drzewa (odległość od korzenia do najdalszego liścia), oraz liście zawierające tylko 1 rekord.
|
||||
W celu uniknięcia overfittingu zdecydowałem się na ograniczenie maksymalnej głębokości drzewa, oraz na ustawienie minimalnej
|
||||
ilości rekordów w liściu. Drzewo wraz z odpowiednimi ograniczeniami zdefiniowane jest w następujący sposób
|
||||
```python
|
||||
clf = DecisionTreeRegressor(ccp_alpha=0.02, min_samples_leaf=5, max_depth=5)
|
||||
```
|
||||
gdzie argumenty min_samples_leaf, oraz max_depth oznaczają odpowiednio minimalną ilość rekordów(przykładów ze zbioru uczącego) w liściu, oraz maksymalną głębokość drzewa.
|
||||
Argument ccp_alpha oznacza parametr \alpha stosowany przy complexity-cost pruning. Pruning oznacza dalsze przycięcie drzewa, aby uniknąć overfittingu
|
||||
Kryterium według którego mierzona jest "jakość" rozgałęzienia jest tzw. MSE(Mean Squared Error), czyli błąd średniokwadratowy(średnia kwadratów odchylenia wielkości oczekiwanej od rzeczywistej).
|
||||
Dobierając te parametry wyszedłem z założenia że jeżeli 5 rekordów będzie w jednym liściu, to znaczy że najprawdopodbniej zachodzi
|
||||
już w ich przypadku pewna prawidłowość, i mają one jakieś wspólne cechy, które determinują taką, a nie inną wartość przewidywaną,
|
||||
w odróżnieniu od sytuacji gdy liść zawierałby tylko 1-2 rekordy, co wskazywałoby na bardzo specyficzne parametry takiego/ich rekordu/ów,
|
||||
i prawdopodobnie oznaczało overfitting drzewa. W przypadku głębokości chodziło o uniknięcie nadmiernego rozrostu drzewa.
|
||||
Zastosowany zbiór uczący obejmuje 373 rekordy zapisane w formacie .csv, w którym poszczególne kolumny oznaczają odpowiednio:
|
||||
produkt, kategorię produktu, temperature na regale, wilgotność powietrza na danym regale, szansę że przedmiot po dłuższym czasie przechowywania będzie w dobrym stanie, oraz informację czy można bezpiecznie go tu położyć.
|
||||
Przykładowy rekord: ``frozen food,freezed,21, 0.5, 0.01, 0 `` . Zbiór testowy z kolei zawiera 26 rekordów w tym samym formacie.
|
||||
Zbiór uczący znajduje się w pliku package_location_classifier/trainset/trainset.csv, a testowy package_location/testset/testset.csv.
|
||||
Przygotowanie zbioru uczącego i testowego dla drzewa:
|
||||
``` python
|
||||
products = pd.read_csv("package_location_classifier/trainset/trainset.csv", header=0, sep=",", names=cols_names)
|
||||
testset = pd.read_csv("package_location_classifier/testset/testset.csv", header=None, sep=",", names=cols_names)
|
||||
products = products.round({"chance_of_survive": 1})
|
||||
testset = testset.round({"chance_of_survive": 1})
|
||||
products.chance_of_survive *= 10
|
||||
testset.chance_of_survive *= 10
|
||||
test_X = pd.get_dummies(testset[feature_cols])
|
||||
test_y = testset.chance_of_survive
|
||||
products = products.sample(frac=1)
|
||||
X_train = pd.get_dummies(products[feature_cols])
|
||||
y_train = products.chance_of_survive
|
||||
```
|
||||
Uczenie drzewa i ewaluacja przy pomocy zbioru testowego:
|
||||
``` python
|
||||
self.predictor = clf.fit(X_train, y_train)
|
||||
|
||||
y_pred = self.predictor.predict(test_X)
|
||||
|
||||
```
|
||||
|
||||
|
||||
Graficzna reprezentacja drzewa wygenerowanego dla tego zbioru uczącego:
|
||||
![Przykładowe drzewo](Drzewo.png)
|
||||
|
||||
Wyniki ewaluacji zestawu testowego, znajdujące się w pliku Test_results.xlsx:
|
||||
![Wyniki testu](Test_Results.png)
|
||||
|
||||
Przewidywana wartość w zestawie testowym różni się od wartości faktycznej średnio o 0.87, jako że w raporcie wartości są pomnożone przez 10, daje to średnio
|
||||
0.087 wartości różnicy w czasie działania drzewa.
|
||||
|
||||
|
||||
##### Zastosowanie drzewa w części wspólnej projektu
|
||||
|
||||
Po podniesieniu paczki przez agenta odpalana jest funkcja szukająca najbliższego pasującego regału.
|
||||
Przy poszukiwaniu takiego regału stosowana jest funkcja heurystyczna o następującym kodzie:
|
||||
```python
|
||||
def rack_heuristics(self, start, goal, can_place):
|
||||
heur_can_place = not can_place
|
||||
diff_x = pow(goal.x - start.x, 2)
|
||||
diff_y = pow(goal.y - start.y, 2)
|
||||
place_cost = 100 * float(heur_can_place)
|
||||
return round(sqrt(diff_x + diff_y), 3) + float(place_cost)
|
||||
```
|
||||
Parametr can_place to wynik ewaluacji pola goal, przy pomocy drzewa:
|
||||
```python
|
||||
for rack in quarter_racks:
|
||||
new_node = Node(rack.x_position, rack.y_position)
|
||||
can_place = self.location_classifier.check_if_can_place(package, rack)
|
||||
cost = self.rack_heuristics(start_node, new_node, can_place)
|
||||
```
|
||||
self.location_classifier, to obiekt klasy PackageLocationClassifier.
|
||||
Klasa ta zawiera metodę check_if_can_place() :
|
||||
```python
|
||||
def check_if_can_place(self, package, tile):
|
||||
category = package.category
|
||||
cat_treshold = PACKAGE_PLACE_TRESHOLD[category]
|
||||
fields = [[
|
||||
tile.air_temperature,
|
||||
tile.humidity,
|
||||
category == "flammable",
|
||||
category == "fragile",
|
||||
category=="freezed" ,
|
||||
category == "keep_dry",
|
||||
category == "normal"
|
||||
]]
|
||||
|
||||
quality_of_place = round(self.predictor.predict(fields)[0]/10, 2)
|
||||
if quality_of_place > cat_treshold:
|
||||
return True
|
||||
return False
|
||||
```
|
||||
|
||||
Self.predictor to nauczone drzewo.
|
BIN
Drzewo.png
Before Width: | Height: | Size: 338 KiB |
@ -1,54 +0,0 @@
|
||||
## Podprojekt: algorytm genetyczny
|
||||
### Jakub Damiński
|
||||
|
||||
#### Opis problemu
|
||||
Metodą uczenia, którą postanowiłem zaimplementować w projekcie był algorytm genetyczny. Zastosowalem go, by znaleźć najszybszą ścieżkę, którą może podążyć wózek widłowy pomiędzy paczkami, by przejechać w sumie jak najkrótszy dystans.
|
||||
|
||||
#### Metoda
|
||||
Pierwszym krokiem jest zbudowanie grafu z wagami w którym wierzchołkami są paczki, regały na które te paczki mają trafić oraz punkt startowy wózka, a wagi krawędzi to odległości między nimi. Ponieważ środowisko opiera się na 2-wymiarowej powierzchni, gdzie nie ma odizolowanych pól jest to graf pełny. Graf zapisany jest w 2-wymiarowej tablicy.
|
||||
|
||||
Ponieważ wózek musi odwiedzić wszystkie paczki każde rozwiązanie tego problemu będzie permutacja zbioru tych paczek, przedstawiający, które paczki po kolei powinien wózek odwiedzić. Wartościowość takiego rozwiązania jest weryfikowana poprzez zsumowanie odległości jakie wózek musi przebyć do paczki oraz od paczki do jej wyznaczonego regału.
|
||||
|
||||
Wykorzystując algorytm genetyczny sprawimy, że spośród losowych permotacji zaczną wyłaniać się tej najbardziej efektywne, czyli te o najkrótszej ścieżce.
|
||||
|
||||
#### Zasada działania
|
||||
Pierwszym krokiem jest zapełnienie populacji losowymi permutacjiami.
|
||||
Następnie wykonuje się liczba iteracji w których najlepsze osobniki krzyżują się ze sobą tworzyć nowe permutacje wymianiając między sobą losową ilość elementów
|
||||
```
|
||||
def crossover(a, b):
|
||||
new_a = copy.deepcopy(a)
|
||||
new_b = copy.deepcopy(b)
|
||||
for i in range(floor(len(a) / 2)):
|
||||
rel = randrange(len(a))
|
||||
tmp_a = new_a[rel]
|
||||
tmp_b = new_b[rel]
|
||||
if tmp_a == tmp_b:
|
||||
continue
|
||||
new_a[new_a.index(tmp_b)] = tmp_a
|
||||
new_b[new_b.index(tmp_a)] = tmp_b
|
||||
new_a[rel] = tmp_b
|
||||
new_b[rel] = tmp_a
|
||||
return new_a, new_b
|
||||
```
|
||||
Nowo stworzone osobniki mają następnie szansę na mutacje, która polega na zamienieniu dwóch losowych elementów ze sobą
|
||||
```
|
||||
def mutate(route):
|
||||
new_route = copy.deepcopy(route)
|
||||
for i in range(len(route) - 1):
|
||||
if random() < mutation_probability:
|
||||
tmp = new_route[i]
|
||||
new_route[i] = new_route[i + 1]
|
||||
new_route[i + 1] = tmp
|
||||
return new_route
|
||||
```
|
||||
Następnym krokiem jest dodanie do populacji najlepszych osobników z poprzedniej populacji
|
||||
```
|
||||
for j in range(0, num_of_surviving):
|
||||
new_population.append(population[scores[j][0]])
|
||||
```
|
||||
Po wykonaniu tych kroków do nowej populacji dodawane są zupelnie nowe soobniki by osiągną maksymalną ilość populacji
|
||||
```
|
||||
for j in range(max_population - (num_of_surviving + num_of_couples)):
|
||||
new_population.append(create_new_route(packages))
|
||||
```
|
||||
Na koniec iteracji wszystkie permutacje są oceniane na podstawie tego ile wózkowi zajęło by przejechanie całej trasy
|
BIN
Test_Results.png
Before Width: | Height: | Size: 74 KiB |
401
agent.py
Executable file → Normal file
@ -1,292 +1,159 @@
|
||||
|
||||
from warehouse import Coordinates, Tile, Pack
|
||||
from attributes import PackStatus, TURN_LEFT_DIRECTIONS, TURN_RIGHT_DIRECTIONS
|
||||
from queue import PriorityQueue
|
||||
from math import sqrt, ceil
|
||||
from attributes import TURN_LEFT_DIRECTIONS, TURN_RIGHT_DIRECTIONS, PackStatus
|
||||
import pygame
|
||||
import sys
|
||||
import pdb
|
||||
import numpy as np
|
||||
from package_location_classifier.classifier import PackageLocationClassifier
|
||||
from genetic_route import genetic_trace_route
|
||||
from siec import imgSkan, imageClass
|
||||
from keras.models import Sequential
|
||||
|
||||
class Node:
|
||||
def __init__(self, coord_x, coord_y, package=None, is_rack=False):
|
||||
self.x = coord_x
|
||||
self.y = coord_y
|
||||
self.parent = None
|
||||
self.package = package
|
||||
self.is_rack = is_rack
|
||||
self.g_cost = 0
|
||||
self.h_cost = 0
|
||||
self.graph_map = None
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Node):
|
||||
return self.x == other.x and self.y == other.y
|
||||
return False
|
||||
|
||||
def __lt__(self, other):
|
||||
return isinstance(other, Node) and self.g_cost < other.g_cost
|
||||
|
||||
def __repr__(self):
|
||||
return "Node:{}x{}".format(self.x, self.y)
|
||||
|
||||
from pathfinder import Node
|
||||
from math import sqrt
|
||||
|
||||
class Agent:
|
||||
def __init__(self, start_x, start_y, assigned_warehouse, radius=5):
|
||||
self.x = start_x
|
||||
self.y = start_y
|
||||
self.radius = radius
|
||||
self.warehouse = assigned_warehouse
|
||||
self.graph_map = np.zeros(((self.warehouse.no_of_packages * 2) + 1, (self.warehouse.no_of_packages * 2) + 1))
|
||||
self.is_loaded = False
|
||||
self.transported_package = None
|
||||
self.direction = "up"
|
||||
self.closed = list()
|
||||
self.open = PriorityQueue()
|
||||
self.path = list()
|
||||
self.location_classifier = PackageLocationClassifier()
|
||||
self.check_packages_locations()
|
||||
self.route = []
|
||||
self.destination = None
|
||||
def __init__(self, start_x, start_y, assigned_warehouse, radius=5):
|
||||
self.x = start_x
|
||||
self.y = start_y
|
||||
self.direction = 'down'
|
||||
self.radius = radius
|
||||
self.assigned_warehouse = assigned_warehouse
|
||||
self.is_loaded = False
|
||||
self.transported_package = None
|
||||
|
||||
def check_packages_locations(self):
|
||||
for pack in self.warehouse.packages:
|
||||
if pack.lays_on_field.category.name in self.warehouse.storage_types:
|
||||
can_place = self.location_classifier.check_if_can_place(pack, pack.lays_on_field)
|
||||
pack.status = PackStatus.STORED if (
|
||||
can_place and pack.lays_on_field.capacity >= 0) else PackStatus.STORED_BAD_LOCATION
|
||||
def demo_agent_move(self, demo_agent_step, demo_step_max=5):
|
||||
demo_agent_sign = 0
|
||||
next_coords = self.get_next_move_coordinates()
|
||||
can_move = self.check_if_can_move(next_coords)
|
||||
if demo_agent_step >= demo_step_max:
|
||||
demo_agent_sign = -1
|
||||
self.direction = 'up'
|
||||
elif demo_agent_step == 0:
|
||||
demo_agent_sign = 1
|
||||
self.direction = 'down'
|
||||
if not can_move:
|
||||
alternative_move = ('left' if self.check_if_can_move(self.move_left()) else None) or ('right' if self.check_if_can_move(self.move_right()) else self.direction)
|
||||
self.direction = alternative_move
|
||||
else:
|
||||
self.x = next_coords.x
|
||||
self.y = next_coords.y
|
||||
|
||||
def find_path(self, *args, **kwargs):
|
||||
self.closed = []
|
||||
self.path = []
|
||||
self.open = PriorityQueue()
|
||||
if len(args) != 0:
|
||||
if len(args) == 1:
|
||||
start_node = Node(self.x, self.y)
|
||||
else:
|
||||
start_node = args[1]
|
||||
self.destination = args[0]
|
||||
else:
|
||||
packages_to_go = [p for p in self.warehouse.packages if p.status != PackStatus.STORED]
|
||||
if not packages_to_go and not self.transported_package:
|
||||
return
|
||||
if self.is_loaded:
|
||||
print(self.transported_package)
|
||||
rack = self.find_nearest_rack_for(self.transported_package)
|
||||
self.destination = Node(rack.x_position, rack.y_position, is_rack=True)
|
||||
else:
|
||||
package = self.find_package()
|
||||
self.destination = Node(package.lays_on_field.x_position, package.lays_on_field.y_position, package=package)
|
||||
def turn_left(self):
|
||||
new_direction = TURN_LEFT_DIRECTIONS.get(self.direction, self.direction)
|
||||
self.direction = new_direction
|
||||
|
||||
start_node = Node(self.x, self.y)
|
||||
def turn_right(self):
|
||||
new_direction = TURN_RIGHT_DIRECTIONS.get(self.direction, self.direction)
|
||||
self.direction = new_direction
|
||||
|
||||
self.open.put((0, start_node))
|
||||
while self.open:
|
||||
_, current_node = self.open.get()
|
||||
self.closed.append(current_node)
|
||||
if current_node.x == self.destination.x and current_node.y == self.destination.y:
|
||||
while current_node.x != start_node.x or current_node.y != start_node.y:
|
||||
self.path.append(current_node)
|
||||
current_node = current_node.parent
|
||||
return True
|
||||
neighbour_list = self.get_neighbours(current_node)
|
||||
for neighbour in neighbour_list:
|
||||
cost = current_node.g_cost + self.heuristic(current_node, neighbour)
|
||||
if self.check_if_closed(neighbour):
|
||||
continue
|
||||
if self.check_if_open(neighbour):
|
||||
if neighbour.g_cost > cost:
|
||||
neighbour.g_cost = cost
|
||||
neighbour.parent = current_node
|
||||
else:
|
||||
neighbour.g_cost = cost
|
||||
neighbour.h_cost = self.heuristic(neighbour, self.destination)
|
||||
neighbour.parent = current_node
|
||||
self.open.put((neighbour.g_cost, neighbour))
|
||||
return False
|
||||
def move(self):
|
||||
next_coords = self.get_next_move_coordinates()
|
||||
can_move = self.check_if_can_move(next_coords)
|
||||
if can_move:
|
||||
self.x = next_coords.x
|
||||
self.y = next_coords.y
|
||||
|
||||
def turn_left(self):
|
||||
new_direction = TURN_LEFT_DIRECTIONS.get(self.direction, self.direction)
|
||||
self.direction = new_direction
|
||||
def get_next_move_coordinates(self):
|
||||
direction_moves = {
|
||||
'up': self.move_up(),
|
||||
'down': self.move_down(),
|
||||
'left': self.move_left(),
|
||||
'right': self.move_right()
|
||||
}
|
||||
next_coords = direction_moves.get(self.direction, Coordinates(self.x, self.y))
|
||||
return next_coords
|
||||
|
||||
def turn_right(self):
|
||||
new_direction = TURN_RIGHT_DIRECTIONS.get(self.direction, self.direction)
|
||||
self.direction = new_direction
|
||||
def check_if_can_move(self, next_coords: Coordinates):
|
||||
next_tile = self.assigned_warehouse.tiles[next_coords.x][next_coords.y]
|
||||
tile_passable = isinstance(next_tile, Tile) and next_tile.category.passable
|
||||
tile_on_map = 0 <= next_coords.x < self.assigned_warehouse.width and 0 <= next_coords.y < self.assigned_warehouse.height
|
||||
return tile_passable and tile_on_map
|
||||
|
||||
def heuristic(self, start: Node, goal: Node):
|
||||
diff_x = pow(goal.x - start.x, 2)
|
||||
diff_y = pow(goal.y - start.y, 2)
|
||||
additional_cost = 0
|
||||
return round(sqrt(diff_x + diff_y), 3) + float(10 * additional_cost)
|
||||
def move_right(self):
|
||||
pos_x = self.x + 1
|
||||
if pos_x > self.assigned_warehouse.width - 1:
|
||||
pos_x = self.assigned_warehouse.width - 1
|
||||
return Coordinates(x=pos_x, y=self.y)
|
||||
|
||||
def check_if_open(self, node: Node):
|
||||
return (node.x, node.y) in [(n.x, n.y) for (_, n) in self.open.queue]
|
||||
def move_left(self):
|
||||
pos_x = self.x - 1
|
||||
if pos_x < 0:
|
||||
pos_x = 0
|
||||
return Coordinates(x=pos_x, y=self.y)
|
||||
|
||||
def check_if_closed(self, node: Node):
|
||||
return (node.x, node.y) in [(n.x, n.y) for n in self.closed]
|
||||
def move_down(self):
|
||||
pos_y = self.y + 1
|
||||
if pos_y > self.assigned_warehouse.height - 1:
|
||||
pos_y = self.assigned_warehouse.height - 1
|
||||
return Coordinates(x=self.x, y=pos_y)
|
||||
|
||||
def get_neighbours(self, node: Node):
|
||||
neighbours = []
|
||||
if self.check_if_can_move(Coordinates(node.x + 1, node.y)):
|
||||
neighbours.append(Node(node.x + 1, node.y))
|
||||
if self.check_if_can_move(Coordinates(node.x - 1, node.y)):
|
||||
neighbours.append(Node(node.x - 1, node.y))
|
||||
if self.check_if_can_move(Coordinates(node.x, node.y + 1)):
|
||||
neighbours.append(Node(node.x, node.y + 1))
|
||||
if self.check_if_can_move(Coordinates(node.x, node.y - 1)):
|
||||
neighbours.append(Node(node.x, node.y - 1))
|
||||
return neighbours
|
||||
def move_up(self):
|
||||
pos_y = self.y - 1
|
||||
if pos_y < 0:
|
||||
pos_y = 0
|
||||
return Coordinates(x=self.x, y=pos_y)
|
||||
|
||||
def move(self):
|
||||
if len(self.path) == 0:
|
||||
self.find_path()
|
||||
next_coord = self.path.pop()
|
||||
star_dir = self.direction
|
||||
if self.x > next_coord.x and not self.direction == 'left':
|
||||
if self.direction == 'down':
|
||||
self.turn_right()
|
||||
else:
|
||||
self.turn_left()
|
||||
elif self.x < next_coord.x and not self.direction == 'right':
|
||||
if self.direction == 'down':
|
||||
self.turn_left()
|
||||
else:
|
||||
self.turn_right()
|
||||
elif self.y > next_coord.y and not self.direction == 'up':
|
||||
if self.direction == 'left':
|
||||
self.turn_right()
|
||||
else:
|
||||
self.turn_left()
|
||||
elif self.y < next_coord.y and not self.direction == 'down':
|
||||
if self.direction == 'right':
|
||||
self.turn_right()
|
||||
else:
|
||||
self.turn_left()
|
||||
if Node(next_coord.x, next_coord.y) == self.destination or Node(self.x, self.y) == self.destination:
|
||||
if self.destination.package:
|
||||
self.pick_up_package(self.destination.package)
|
||||
return
|
||||
elif self.destination.is_rack:
|
||||
self.unload_package(self.destination)
|
||||
return
|
||||
def package_ahead(self):
|
||||
next_coords = self.get_next_move_coordinates()
|
||||
potential_package = self.assigned_warehouse.tiles[next_coords.x][next_coords.y]
|
||||
return isinstance(potential_package, Pack) and potential_package.status != PackStatus.STORED
|
||||
|
||||
if star_dir == self.direction:
|
||||
self.x = next_coord.x
|
||||
self.y = next_coord.y
|
||||
else:
|
||||
self.path.append(next_coord)
|
||||
self.closed = []
|
||||
def pick_up_package(self, pack):
|
||||
tile = pack.lays_on_field
|
||||
self.assigned_warehouse.tiles[tile.x_position][tile.y_position] = tile
|
||||
self.is_loaded = True
|
||||
pack.lays_on_field = None
|
||||
self.transported_package = pack
|
||||
|
||||
def check_if_can_move(self, next_coords: Coordinates):
|
||||
tile_on_map = 0 <= next_coords.x < self.warehouse.width and 0 <= next_coords.y < self.warehouse.height
|
||||
tile_passable = True
|
||||
if not tile_on_map:
|
||||
return False
|
||||
next_tile = self.warehouse.tiles[next_coords.x][next_coords.y]
|
||||
if (next_coords.x, next_coords.y) != (self.destination.x, self.destination.y):
|
||||
tile_passable = isinstance(next_tile, Tile) and next_tile.category.passable
|
||||
return tile_passable
|
||||
def find_route(self, goal):
|
||||
explored = []
|
||||
# tu trzeba dodać kolejkę priorytetową fringe
|
||||
fringe = PriorityQueue()
|
||||
current_tile = self.assigned_warehouse.tiles[self.x][self.y]
|
||||
fringe.put((1, current_tile))
|
||||
|
||||
def find_package(self):
|
||||
if len(self.route) == 0:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
pack_id = self.route[0]
|
||||
self.route = self.route[1:]
|
||||
# print("Next package ID:")
|
||||
# print(pack_id)
|
||||
dst_package = None
|
||||
for pack in self.warehouse.packages:
|
||||
if pack.id + 1 == pack_id:
|
||||
dst_package = pack
|
||||
break
|
||||
if dst_package is not None:
|
||||
return dst_package
|
||||
|
||||
nmodel = Sequential()
|
||||
imageClass(nmodel)
|
||||
nmodel.load_weights('model_weights.h5')
|
||||
while True:
|
||||
if len(fringe) == 0:
|
||||
return False
|
||||
# elem to węzeł z kolejki o najmniejszym priorytecie (najlepszy)
|
||||
elem = fringe.get()
|
||||
|
||||
imgSkan()
|
||||
|
||||
def rack_heuristics(self, start, goal, can_place):
|
||||
heur_can_place = not can_place
|
||||
diff_x = pow(goal.x - start.x, 2)
|
||||
diff_y = pow(goal.y - start.y, 2)
|
||||
place_cost = 100 * float(heur_can_place)
|
||||
return round(sqrt(diff_x + diff_y), 3) + float(place_cost)
|
||||
# jeśli zgadzają się współrzędne x i y wybranego węzłą oraz celu
|
||||
if elem.x_position == goal.x_position and elem.y_position == goal.y_position:
|
||||
# tu powinna zostać zwrócona ścieżka
|
||||
print("doszedl")
|
||||
return True
|
||||
|
||||
def find_nearest_rack_for(self, package, expand_box=0):
|
||||
weight = package.size
|
||||
storage = "Rack"
|
||||
if package.category == "freezed":
|
||||
storage = "Fridge"
|
||||
start_node = Node(self.x, self.y)
|
||||
quarter_x = int(self.warehouse.width / 4) + expand_box
|
||||
quarter_y = int(self.warehouse.height / 4) + expand_box
|
||||
start_quarter_x = self.x - quarter_x if self.x - quarter_x > 0 else 0
|
||||
end_quarter_x = self.x + quarter_x if self.x + quarter_x < self.warehouse.width else self.warehouse.width - 1
|
||||
start_quarter_y = self.y - quarter_y if self.y - quarter_y > 0 else 0
|
||||
end_quarter_y = self.y + quarter_y if self.y + quarter_y < self.warehouse.height else self.warehouse.height - 1
|
||||
quarter = [row[start_quarter_y:end_quarter_y] for row in self.warehouse.tiles[start_quarter_x:end_quarter_x]]
|
||||
quarter_racks = [[t for t in row if t.category.name == storage and t.capacity >= weight] for row in quarter]
|
||||
quarter_racks = [t for row in quarter_racks for t in row]
|
||||
racks_costs = []
|
||||
for rack in quarter_racks:
|
||||
new_node = Node(rack.x_position, rack.y_position)
|
||||
can_place = self.location_classifier.check_if_can_place(package, rack)
|
||||
cost = self.rack_heuristics(start_node, new_node, can_place)
|
||||
if cost > 0:
|
||||
racks_costs.append((rack, cost))
|
||||
# przeniesienie wybranego węzłą z fringe do explored
|
||||
explored.append(elem)
|
||||
|
||||
rack = self.find_nearest_rack_for(package, expand_box + 1) if not racks_costs else \
|
||||
min(racks_costs, key=lambda l: l[1])[0]
|
||||
return rack
|
||||
# dla każdego następnika węzła elem
|
||||
# trzeba napisać funkcję succ wyznaczającą następników elem
|
||||
# succesor[0] - akcja
|
||||
# succesor[1] - stan czyli współrzędne i zwrot
|
||||
# succesor[2] - rodzic
|
||||
succ = self.get_succ(elem)
|
||||
|
||||
def pick_up_package(self, pack):
|
||||
self.warehouse.packages.remove(pack)
|
||||
self.is_loaded = True
|
||||
if pack.lays_on_field.category.name in ['Rack', 'Fridge']:
|
||||
pack.lays_on_field.capacity += pack.size
|
||||
for action, state in succ:
|
||||
new_node = Node(elem, elem.x_position, elem.y_position)
|
||||
# x[1] = succesor[1]
|
||||
# x[2] = elem
|
||||
# x[0] = akcja
|
||||
# trzeba napisać funkcję f(x) liczącą priorytet danego węzła
|
||||
# p = f(x)
|
||||
|
||||
self.destination.package = None
|
||||
pack.lays_on_field = None
|
||||
self.transported_package = pack
|
||||
# if x[1] not in fringe and x[1] not in explored:
|
||||
# fringe.append(x[1])
|
||||
# nie wiem jak wyznaczyć priorytet który x już ma w kolejce
|
||||
# elif x[1] in fringe and priorytet który stan x już ma w kolejce > p:
|
||||
# tu chodzi o to że zmieni się akcja i rodzić, ale stan nie
|
||||
# zamień w fringe stary węzeł o stanie x[1] z węzłem x
|
||||
|
||||
def unload_package(self, rack):
|
||||
pack = self.transported_package
|
||||
tile = self.warehouse.tiles[rack.x][rack.y]
|
||||
self.transported_package = None
|
||||
self.is_loaded = False
|
||||
pack.lays_on_field = tile
|
||||
pack.lays_on_field.capacity -= pack.size
|
||||
pack.status = PackStatus.STORED
|
||||
self.warehouse.packages.append(pack)
|
||||
def h(self, start, goal):
|
||||
diff_x = pow(goal.x_position - start.x_position,2)
|
||||
diff_y = pow(goal.y_position - start.y_position, 2)
|
||||
return round(sqrt(diff_x+diff_y), 3)
|
||||
|
||||
# print(tile.air_temperature, tile.humidity)
|
||||
|
||||
def create_graph_map(self):
|
||||
for package1 in self.warehouse.packages:
|
||||
rack = self.find_nearest_rack_for(package1)
|
||||
for package2 in self.warehouse.packages:
|
||||
self.find_path(Node(package2.x, package2.y), Node(rack.x_position, rack.y_position))
|
||||
self.graph_map[package2.id + 1][package1.id + ceil((len(self.warehouse.packages) / 2)) + 1] = len(self.path)
|
||||
self.graph_map[package1.id + ceil((len(self.warehouse.packages) / 2)) + 1][package2.id + 1] = len(self.path)
|
||||
if package1 == package2:
|
||||
continue
|
||||
self.find_path(Node(package1.x, package1.y), Node(package2.x, package2.y))
|
||||
self.graph_map[package1.id + 1][package2.id + 1] = len(self.path)
|
||||
self.find_path(Node(package1.x, package1.y))
|
||||
self.graph_map[package1.id + 1][0] = len(self.path)
|
||||
self.graph_map[0][package1.id + 1] = len(self.path)
|
||||
|
||||
def trace_route(self):
|
||||
# for packs in self.warehouse.packages:
|
||||
# print(packs.id)
|
||||
self.route = genetic_trace_route(self.graph_map, len(self.warehouse.packages))
|
||||
# print("best route")
|
||||
# print(self.route)
|
||||
def get_succ(self, elem):
|
||||
move = self.move
|
||||
turn_left = self.turn_left
|
||||
turn_right = self.turn_right
|
||||
successors = [
|
||||
(move, self.get_next_move_coordinates()),
|
||||
(turn_right, TURN_RIGHT_DIRECTIONS.get(self.direction, self.direction)),
|
||||
(turn_left, TURN_LEFT_DIRECTIONS.get(self.direction, self.direction))
|
||||
]
|
||||
return successors
|
||||
|
20
attributes.py
Executable file → Normal file
@ -1,5 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
class PackSize(Enum):
|
||||
ALL = 0
|
||||
SMALL = 1
|
||||
MEDIUM = 2
|
||||
LARGE = 3
|
||||
HUGE = 4
|
||||
|
||||
class PackStatus(Enum):
|
||||
LOOSE = 0
|
||||
@ -18,13 +24,10 @@ COLORS = {
|
||||
'darkgray': (60, 60, 60),
|
||||
'yellow': (235, 235, 0),
|
||||
'lightgreen': (70, 238, 70),
|
||||
'red': (255, 0, 0),
|
||||
'lightblue': (120, 180, 230),
|
||||
'iceblue': (186, 242, 239),
|
||||
'blue': (0, 0, 255),
|
||||
'orange': (255, 165, 0)
|
||||
'red': (255, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
TURN_LEFT_DIRECTIONS = {
|
||||
"left": "down",
|
||||
"down": "right",
|
||||
@ -37,11 +40,4 @@ TURN_RIGHT_DIRECTIONS = {
|
||||
"up": "right",
|
||||
"right": "down",
|
||||
"down": "left"
|
||||
}
|
||||
|
||||
DIRECTION_ANGLES = {
|
||||
"left": 0,
|
||||
"up": -90,
|
||||
"right": 180,
|
||||
"down": 90
|
||||
}
|
0
environment.md
Executable file → Normal file
BIN
forklift.png
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
@ -1,148 +0,0 @@
|
||||
## Raport z podprojektu genetic_algorithm
|
||||
#### Autorka - Magdalena Biadała
|
||||
Program wykorzystuje algorytm genetyczny w celu znalezienia najlepszego dopasowania paczek do regałów, przy czym:
|
||||
- każda paczka musi zostać umieszczona na jakimś regale
|
||||
- waga wszystkich paczek umieszczoanych na regale nie może przekroczyć pojemności regału
|
||||
- paczki umieszczane są na regałach których parametry, takie jak temperatura czy wilgotność powietrza pozwalają na bezpieczne jej przechowywanie, bez zniszczenia jej zawartości.
|
||||
|
||||
Algorytm jako struktury danych przyjmuje 2 listy:
|
||||
|
||||
Listę *packs* w której indeksy oznaczają numery paczek, a wartości oznaczają wagę poszczególnych paczek. Na przykład:
|
||||
lista [2,6,2,5] to struktura, gdzie:
|
||||
- paczka o nr 0 ma wagę 2
|
||||
- paczka o nr 1 ma wagę 6
|
||||
- paczka o nr 2 ma wagę 2
|
||||
- paczka o nr 3 ma wagę 5
|
||||
|
||||
Listę *racks* w której indeksy oznaczają numery regałów, a wartości oznaczają pojemność poszczególnych regałów. Na przykład:
|
||||
lista [15,13,20,16] to struktura, gdzie:
|
||||
- regał o nr 0 ma pojemność 15
|
||||
- regał o nr 1 ma pojemność 13
|
||||
- regał o nr 2 ma pojemność 20
|
||||
- regał o nr 3 ma pojemność 16
|
||||
|
||||
|
||||
#### Program zawiera kilka ważnych funkcji:
|
||||
|
||||
```python
|
||||
def first_gen():
|
||||
first_generation = []
|
||||
for individual in range(generation_size):
|
||||
individual = []
|
||||
for pack in range(number_of_packages):
|
||||
r = random.randint(0,number_of_racks-1)
|
||||
individual.append(r)
|
||||
first_generation.append(individual)
|
||||
return first_generation
|
||||
```
|
||||
>funkcja *first_gen()* tworzy pierwsze pokolenie osobników;
|
||||
|
||||
```python
|
||||
def evaluation(individual):
|
||||
rest_of_capacity = racks.copy()
|
||||
for i in range(number_of_packages):
|
||||
rest_of_capacity[individual[i]] -= packages[i]
|
||||
fitness = 0
|
||||
for i in range(number_of_racks):
|
||||
if rest_of_capacity[i] < 0:
|
||||
fitness += rest_of_capacity[i]
|
||||
elif rest_of_capacity[i] == 0:
|
||||
fitness += amount_of_promotion
|
||||
return fitness
|
||||
```
|
||||
> funkcja *evaluation()* ocenia wybranego osobnika pod względem tego, czy:
|
||||
- regały nie są przepełnione
|
||||
|
||||
>Dodatkowo delikatnie promuje ona osobniki, króre wykorzystują pojemność regałów w całości, a na koniec zwraca parametr *fitness*.
|
||||
|
||||
|
||||
```python
|
||||
def roulette(generation):
|
||||
evaluations = []
|
||||
for i in range(generation_size):
|
||||
individual_fitness = evaluation(generation[i])
|
||||
evaluations.append(individual_fitness)
|
||||
maximum = min(evaluations)
|
||||
normalized = [x+(-1*maximum)+1 for x in evaluations]
|
||||
sum_of_normalized = sum(normalized)
|
||||
roulette_tab = [x/sum_of_normalized for x in normalized]
|
||||
for i in range(1,generation_size-1):
|
||||
roulette_tab[i] += roulette_tab[i-1]
|
||||
roulette_tab[generation_size-1] = 1
|
||||
survivors = []
|
||||
for individual in range(generation_size):
|
||||
random_number = random.random()
|
||||
interval_number = 0
|
||||
while random_number > roulette_tab[interval_number]:
|
||||
interval_number += 1
|
||||
survivors.append(generation[interval_number])
|
||||
return survivors
|
||||
```
|
||||
> funkcja *roulette()*:
|
||||
- liczy parametr *fitness* (oznaczający dopasowanie) dla każdego osobnika w pokoleniu
|
||||
- tworzy tablicę z przedziałami, przy czym im większy *fitness* osobnika tym większy jego przedział, a tym samym szansa że zostanie wylosowany
|
||||
- losuje liczby z zakresu od 0 do 1 (liczb jest tyle ile osobników w pokoleniu)
|
||||
-zwraca tych osobników, dla krótych wylosoana liczba wpadła w odpowiadający im przedział.
|
||||
|
||||
```python
|
||||
def crossover(individual1, individual2):
|
||||
cut = random.randint(1,number_of_packages-1)
|
||||
new1 = individual1[:cut]
|
||||
new2 = individual2[:cut]
|
||||
new1 = new1 + individual2[cut:]
|
||||
new2 = new2 + individual1[cut:]
|
||||
return new1, new2
|
||||
```
|
||||
>funkcja *crossover()* zajmuje się krzyżowaniem osobników.
|
||||
|
||||
```python
|
||||
def mutation(individual):
|
||||
locus = random.randint(0,number_of_packages-1)
|
||||
individual[locus] = random.randint(0,number_of_racks-1)
|
||||
return individual
|
||||
```
|
||||
>funkcja *mutation()* dokonuje mutacji osobnika.
|
||||
|
||||
#### Inicjalizacja pierwszego pokolenia
|
||||
Pierwsze pokolenie jest tworzone za pomocą funkcji *first_gen()*. Osobnikiem jest lista której indeksy oznaczają numery paczek, a wartości oznaczają numery regałów. Na przykład:
|
||||
osobnik [3,0,5,5] to przyporządkowanie, gdzie:
|
||||
- paczka nr 0 leży na regale nr 3
|
||||
- paczka nr 1 leży na regale nr 0
|
||||
- paczka nr 2 leży na regale nr 5
|
||||
- paczka nr 3 leży na regale nr 5.
|
||||
|
||||
Dla każdego osobnika w pierwszym pokoleniu liczony jest parametr *fitness*.
|
||||
|
||||
#### Główna pętla programu
|
||||
Dla każdego pokolenia wykonywane są kolejno funkcje:
|
||||
- roulette()
|
||||
>pozostawia ona tylko część osobników w pokoleniu, część z nich zostaje zmultiplikowana
|
||||
|
||||
- crossover()
|
||||
>dla pokolenia które pozostało po ruletce
|
||||
|
||||
- mutation()
|
||||
> ta funkcja wykonywana jest tylko z pewnym prawdopodobieństem określonym w zmiennej *mutation_prob*.
|
||||
|
||||
- evaluation()
|
||||
>dla pokolenia które pozostawiły po sobie poprzednie funkcje znalezione zostaje maksimum (największa wartość *fitness*).
|
||||
|
||||
#### Wynik działania algorytmu
|
||||
Algorytm zwraca osobnika (przyporządkowanie) dla którego wartość fitness była największa.
|
||||
|
||||
#### Przeprowadzone testy
|
||||
W celu rozeznania i dobrania wstępnych wartości parametrów:
|
||||
- *mutation_prob* (prawdopodobieństwo mutacji),
|
||||
- *generation_size* (wielkość pojedynczego pokolenia),
|
||||
- *number_of_generations* (liczba pokoleń),
|
||||
|
||||
został przeprowadzony test. Wykonywał on 200 razy algorytm genetyczny dla wybranych parametrów, oraz losowych list paczek i regałów, a następnie liczył średnią i medianę maksymalnej wartości *fitness* znalezionej w każdej z prób. W poniższej tabeli oprócz średniej i mediany można także odczytać czas działania algorytmu.
|
||||
|
||||
![Tabela wyników](wyniki_testu.PNG)
|
||||
|
||||
#### Zastosowanie w projekcie
|
||||
|
||||
Algorytm uruchamiany jest po wygenerowaniu magazynu. Zwraca on najlepsze znalezione dopasowanie, które następnie zostanie wykorzystane w kolejnych podprojektach innych osób z grupy, które zajmą się optymalizacją rozwożenia paczek na przydzielone im miejsca.
|
||||
|
||||
|
||||
- *amount_of_promotion* (wartość jaka zostaje dodana do *fitness* osobnika, jeśli wykorzysta jakiś regał w pełni)
|
@ -1,175 +0,0 @@
|
||||
import random
|
||||
import math
|
||||
### prawdopodobieństwo mutacji
|
||||
mutation_prob = 0.03
|
||||
### ilość osobników w pokoleniu, powinna być parzysta
|
||||
# generation_size = 40
|
||||
### liczba pokoleń
|
||||
# number_of_generations = 30
|
||||
### jak bardzo promowane są osobniki wykorzystujące całą pojemność regału
|
||||
amount_of_promotion = 5
|
||||
|
||||
|
||||
def first_gen(number_of_packages, number_of_racks, generation_size):
|
||||
first_generation = []
|
||||
for individual in range(generation_size):
|
||||
individual = []
|
||||
for pack in range(number_of_packages):
|
||||
r = random.randint(0,number_of_racks-1)
|
||||
individual.append(r)
|
||||
first_generation.append(individual)
|
||||
return first_generation
|
||||
|
||||
# def evaluation(individual, packages, racks, number_of_packages, number_of_racks, tree_predictor):
|
||||
# # im większy fitness tym lepszy osobnik
|
||||
# # print("regały: ",racks)
|
||||
# rest_of_capacity = [rack.capacity for rack in racks]
|
||||
# # print("początkowa pojemność: ",rest_of_capacity)
|
||||
# for i in range(number_of_packages):
|
||||
# can_place = tree_predictor.check_if_can_place(packages[i], racks[i])
|
||||
# if not can_place:
|
||||
# rest_of_capacity[individual[i]] -= packages[i].size * 5
|
||||
# else:
|
||||
# rest_of_capacity[individual[i]] -= packages[i].size
|
||||
# # print("pozostała pojemność: ",rest_of_capacity)
|
||||
# # pdb.set_trace()
|
||||
# fitness = 0
|
||||
# for i in range(number_of_racks):
|
||||
# # jak regał jest przepełniony, zmniejsza fitness osobnika
|
||||
# if rest_of_capacity[i] < 0:
|
||||
# fitness += rest_of_capacity[i]
|
||||
# # delikane promowanie osobników wykorzystujących regały w pełni
|
||||
# elif rest_of_capacity[i] == 0:
|
||||
# fitness += 2
|
||||
# else:
|
||||
# fitness += 1
|
||||
# return fitness
|
||||
|
||||
|
||||
def evaluation(individual, packages, racks, number_of_packages, number_of_racks, tree_predictor):
|
||||
# im większy fitness tym lepszy osobnik
|
||||
# print("regały: ",racks)
|
||||
rest_of_capacity = [rack.capacity for rack in racks]
|
||||
# print("początkowa pojemność: ",rest_of_capacity)
|
||||
bad_placed = 0
|
||||
for i in range(number_of_packages):
|
||||
rest_of_capacity[individual[i]] -= packages[i].size
|
||||
can_place = tree_predictor.check_if_can_place(packages[i], racks[i])
|
||||
if not can_place:
|
||||
bad_placed +=1
|
||||
# print("pozostała pojemność: ",rest_of_capacity)
|
||||
# pdb.set_trace()
|
||||
fitness = 0
|
||||
for i in range(number_of_racks):
|
||||
# jak regał jest przepełniony, zmniejsza fitness osobnika
|
||||
if rest_of_capacity[i] < 0:
|
||||
fitness += rest_of_capacity[i]
|
||||
# delikane promowanie osobników wykorzystujących regały w pełni
|
||||
elif rest_of_capacity[i] == 0:
|
||||
fitness += amount_of_promotion
|
||||
fitness -= 5*bad_placed
|
||||
return fitness
|
||||
|
||||
def roulette(generation, packages, generation_size ,racks, number_of_packages, number_of_racks, tree_predictor):
|
||||
# print('pokolenie: ', generation)
|
||||
evaluations = []
|
||||
for i in range(generation_size):
|
||||
individual_fitness = evaluation(generation[i], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
||||
evaluations.append(individual_fitness)
|
||||
# print("tablica dopasowań: ", evaluations)
|
||||
maximum = min(evaluations)
|
||||
# dodaję tą 1 żeby nie wywalać najgorszego osobnika
|
||||
normalized = [x+(-1*maximum)+1 for x in evaluations]
|
||||
# print(normalized)
|
||||
sum_of_normalized = sum(normalized)
|
||||
roulette_tab = [x/sum_of_normalized for x in normalized]
|
||||
# print(roulette_tab)
|
||||
for i in range(1,generation_size-1):
|
||||
roulette_tab[i] += roulette_tab[i-1]
|
||||
# wpisuję 1 ręcznie, bo czasem liczby nie sumowały się idealnie do 1
|
||||
#(niedokładność komputera)
|
||||
roulette_tab[generation_size-1] = 1
|
||||
# print("ruletka: ", roulette_tab)
|
||||
survivors = []
|
||||
for individual in range(generation_size):
|
||||
random_number = random.random()
|
||||
interval_number = 0
|
||||
while random_number > roulette_tab[interval_number]:
|
||||
interval_number += 1
|
||||
survivors.append(generation[interval_number])
|
||||
# print('przetrwali: ',survivors)
|
||||
return survivors
|
||||
|
||||
def crossover(individual1, individual2, number_of_packages):
|
||||
cut = random.randint(1,number_of_packages-1)
|
||||
new1 = individual1[:cut]
|
||||
new2 = individual2[:cut]
|
||||
new1 = new1 + individual2[cut:]
|
||||
new2 = new2 + individual1[cut:]
|
||||
# print(individual1)
|
||||
# print(individual2)
|
||||
# print(new1)
|
||||
# print(new2)
|
||||
# print(cut)
|
||||
return new1, new2
|
||||
|
||||
def mutation(individual, number_of_packages, number_of_racks):
|
||||
# print(individual)
|
||||
locus = random.randint(0,number_of_packages-1)
|
||||
individual[locus] = random.randint(0,number_of_racks-1)
|
||||
return individual
|
||||
|
||||
|
||||
def gen_alg(packages, racks, number_of_generations, generation_size, mutation_prob, amount_of_promotion, tree_predictor):
|
||||
number_of_packages = len(packages)
|
||||
number_of_racks = len(racks)
|
||||
|
||||
### WŁAŚCIWY ALGORYTM
|
||||
generation = first_gen(number_of_packages, number_of_racks, generation_size)
|
||||
global_maximum = -math.inf
|
||||
|
||||
# pętla znajdująca najlepszy fitness w pierwszym pokoleniu
|
||||
for i in range(generation_size):
|
||||
evaluation_of_individual = evaluation(generation[i], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
||||
if evaluation_of_individual > global_maximum:
|
||||
global_maximum = evaluation_of_individual
|
||||
best_individual = generation[i].copy()
|
||||
|
||||
#właściwa pętla programu
|
||||
for generation_index in range(number_of_generations):
|
||||
# print('pokolenie numer: ', generation_index)
|
||||
# print(generation)
|
||||
|
||||
### RULETKA
|
||||
survivors = roulette(generation, packages, generation_size, racks, number_of_packages, number_of_racks, tree_predictor)
|
||||
# print('przetrwali: ',survivors)
|
||||
|
||||
### KRZYŻOWANIE
|
||||
descendants = []
|
||||
for individual in range(0,generation_size,2):
|
||||
pair = crossover(survivors[individual],survivors[individual+1], number_of_packages)
|
||||
for each in pair:
|
||||
descendants.append(each)
|
||||
# print('potomkowie: ', descendants)
|
||||
|
||||
### MUTACJA
|
||||
for individual in range(generation_size):
|
||||
if random.random() <= mutation_prob:
|
||||
mutation(descendants[individual], number_of_packages, number_of_racks)
|
||||
# print('potomkowie po mutacji: ', descendants)
|
||||
|
||||
### NAJLEPSZE DOPASOWANIE
|
||||
local_maximum = -math.inf
|
||||
for each in range(generation_size):
|
||||
specific_fitness = evaluation(descendants[each], packages, racks, number_of_packages, number_of_racks, tree_predictor)
|
||||
if specific_fitness > local_maximum:
|
||||
local_maximum = specific_fitness
|
||||
generation_best_individual = descendants[each].copy()
|
||||
print('maksimum w pokoleniu: ',local_maximum)
|
||||
if local_maximum > global_maximum:
|
||||
global_maximum = local_maximum
|
||||
best_individual = generation_best_individual.copy()
|
||||
generation = descendants
|
||||
print('maksimum globalne: ', global_maximum)
|
||||
# print("jeśli maksimum globalne wynosi 0, każda paczka ma swój regał")
|
||||
print("najlepsze dopasowanie: ", best_individual)
|
@ -1,98 +0,0 @@
|
||||
import numpy as np
|
||||
from random import randrange, random
|
||||
from math import floor
|
||||
import copy
|
||||
|
||||
num_of_surviving = 6
|
||||
num_of_couples = 8
|
||||
mutation_probability = 0.07
|
||||
max_population = 20
|
||||
iterations = 50
|
||||
|
||||
# creates new random solution to add to population
|
||||
def create_new_route(points):
|
||||
route = np.random.permutation(points)
|
||||
route = [x + 1 for x in route]
|
||||
return route
|
||||
|
||||
# creates initian population
|
||||
def create_population(points):
|
||||
population = []
|
||||
for i in range(max_population):
|
||||
population.append(create_new_route(points))
|
||||
return population
|
||||
|
||||
# gives score to a solution based on lenght
|
||||
def score_route(graph_map, route):
|
||||
score = graph_map[0][route[0]]
|
||||
for i in range(len(route) - 2):
|
||||
rack = len(route) + route[0]
|
||||
score = score + graph_map[rack][route[i + 1]]
|
||||
score = score + graph_map[route[i + 1]][route[i + 2]]
|
||||
return score
|
||||
|
||||
# scores every solution in population
|
||||
def score_all(graph_map, population):
|
||||
scores = []
|
||||
for i in range(len(population)):
|
||||
tmp = [i, score_route(graph_map, population[i])]
|
||||
scores.append(tmp)
|
||||
return scores
|
||||
|
||||
# designed to create new population by mixing steps between most succesfull solutions
|
||||
def crossover(a, b):
|
||||
new_a = copy.deepcopy(a)
|
||||
new_b = copy.deepcopy(b)
|
||||
for i in range(floor(len(a) / 2)):
|
||||
rel = randrange(len(a))
|
||||
tmp_a = new_a[rel]
|
||||
tmp_b = new_b[rel]
|
||||
if tmp_a == tmp_b:
|
||||
continue
|
||||
new_a[new_a.index(tmp_b)] = tmp_a
|
||||
new_b[new_b.index(tmp_a)] = tmp_b
|
||||
new_a[rel] = tmp_b
|
||||
new_b[rel] = tmp_a
|
||||
return new_a, new_b
|
||||
|
||||
# adds randomness to newly created solutions
|
||||
def mutate(route):
|
||||
new_route = copy.deepcopy(route)
|
||||
for i in range(len(route) - 1):
|
||||
if random() < mutation_probability:
|
||||
tmp = new_route[i]
|
||||
new_route[i] = new_route[i + 1]
|
||||
new_route[i + 1] = tmp
|
||||
return new_route
|
||||
|
||||
# main function that iterate population until the best solutions emerge
|
||||
def genetic_trace_route(graph_map, packages):
|
||||
population = create_population(packages)
|
||||
for i in range(iterations):
|
||||
new_population = []
|
||||
scores = score_all(graph_map, population)
|
||||
scores.sort(key=lambda x: x[1])
|
||||
# breeding
|
||||
for j in range(0, num_of_couples, 2):
|
||||
a, b = crossover(population[scores[j][0]], population[scores[j+1][0]])
|
||||
new_population.append(a)
|
||||
new_population.append(b)
|
||||
# mutations
|
||||
for j in range(len(new_population)):
|
||||
mutate(new_population[j])
|
||||
# survival
|
||||
for j in range(0, num_of_surviving):
|
||||
new_population.append(population[scores[j][0]])
|
||||
# random new
|
||||
for j in range(max_population - (num_of_surviving + num_of_couples)):
|
||||
new_population.append(create_new_route(packages))
|
||||
population.clear()
|
||||
population = copy.deepcopy(new_population)
|
||||
scores = score_all(graph_map, population)
|
||||
scores.sort(key=lambda x: x[1])
|
||||
# print("Best route of all population in iteration " + str(i + 1))
|
||||
# print(scores[0][1])
|
||||
|
||||
scores = score_all(graph_map, population)
|
||||
scores.sort(key=lambda x: x[1])
|
||||
return population[scores[0][0]]
|
82
main.py
Executable file → Normal file
@ -1,52 +1,32 @@
|
||||
import pygame
|
||||
import warehouse
|
||||
import agent
|
||||
from genetic_algorithm import gen_alg
|
||||
import random
|
||||
import sys
|
||||
from attributes import PackStatus, COLORS, DIRECTION_ANGLES
|
||||
from attributes import PackSize, PackStatus, COLORS
|
||||
|
||||
WINDOW_SIZE = (640, 640)
|
||||
WINDOW_SIZE = (600, 600)
|
||||
COLOR_OF_FIELD = {
|
||||
'Floor': 'gray',
|
||||
'Rack': 'white',
|
||||
'Pack': 'yellow',
|
||||
'path': 'orange',
|
||||
'FridgeFloor': 'lightblue',
|
||||
'Fridge': 'iceblue'
|
||||
'Pack': 'yellow'
|
||||
}
|
||||
TILE_WIDTH = 32
|
||||
TILE_HEIGHT = 32
|
||||
TILE_WIDTH = 30
|
||||
TILE_HEIGHT = 30
|
||||
CIRCLE_CENTER_X, CIRCLE_CENTER_Y = int(TILE_WIDTH/2), int(TILE_HEIGHT/2)
|
||||
|
||||
class MainGameFrame:
|
||||
def __init__(self, mutation_prob=0.03, generation_size=30, number_of_generations=100, amount_of_promotion=0):
|
||||
pygame.font.init()
|
||||
def __init__(self):
|
||||
self.display = pygame.display.set_mode(WINDOW_SIZE)
|
||||
pygame.display.set_caption("Smart ForkLift")
|
||||
agent_radius = int(TILE_WIDTH/2)
|
||||
self.agent_tex = pygame.image.load('forklift.png')
|
||||
self.agent_tex2 = pygame.image.load('forklift_loaded.png')
|
||||
self.font = pygame.font.Font('freesansbold.ttf', 16)
|
||||
self.warehouse_map = warehouse.Warehouse(20, 20, 150, 10)
|
||||
self.warehouse_map = warehouse.Warehouse(20, 20, 150, 20)
|
||||
starting_x, starting_y = self.set_starting_agent_position()
|
||||
self.agent = agent.Agent(starting_x, starting_y, self.warehouse_map, agent_radius)
|
||||
self.clock = pygame.time.Clock()
|
||||
packs_coords = [(pack.lays_on_field.x_position, pack.lays_on_field.y_position) for pack in self.warehouse_map.packages]
|
||||
list_of_racks = self.warehouse_map.get_all_racks(True)
|
||||
racks_coords = [(line.x_position, line.y_position) for line in list_of_racks]
|
||||
packs_sizes = [pack for pack in self.warehouse_map.packages]
|
||||
racks_capacities = list_of_racks
|
||||
# print("koordynaty paczek: ",packs_coords)
|
||||
# print("koordynaty regałów: ",racks_coords)
|
||||
print("wagi paczek: ",packs_sizes)
|
||||
print("pojemności regałów: ",racks_capacities)
|
||||
gen_alg(packs_sizes, racks_capacities, number_of_generations, generation_size, mutation_prob, amount_of_promotion, self.agent.location_classifier)
|
||||
self.agent.create_graph_map()
|
||||
self.agent.trace_route()
|
||||
self.agent.find_path()
|
||||
|
||||
def run(self):
|
||||
# demo_agent_step = 1
|
||||
# demo_agent_sign = 1
|
||||
while True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
@ -55,14 +35,15 @@ class MainGameFrame:
|
||||
self.draw_floor()
|
||||
self.draw_packages()
|
||||
self.draw_agent()
|
||||
self.draw_nums()
|
||||
self.agent.move()
|
||||
packages_to_go = [p for p in self.warehouse_map.packages if p.status != PackStatus.STORED]
|
||||
if not packages_to_go and not self.agent.transported_package:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
# self.agent.demo_agent_move(demo_agent_step, 8) #linijka w celu zademonstrowania poruszania się agenta
|
||||
# self.agent.move() #oryginalna linijka
|
||||
# demo_agent_step += (1*demo_agent_sign)
|
||||
# if demo_agent_step >= 8:
|
||||
# demo_agent_sign = -1
|
||||
# if demo_agent_step == 0:
|
||||
# demo_agent_sign = 1
|
||||
pygame.display.update()
|
||||
self.clock.tick(6)
|
||||
self.clock.tick(5)
|
||||
|
||||
def draw_floor(self):
|
||||
for x in range(self.warehouse_map.width):
|
||||
@ -71,10 +52,10 @@ class MainGameFrame:
|
||||
|
||||
def draw_field(self, x, y):
|
||||
current_tile = self.warehouse_map.tiles[x][y]
|
||||
if not isinstance(current_tile, warehouse.Tile):
|
||||
current_tile = current_tile.lays_on_field if isinstance(current_tile, warehouse.Pack) else None
|
||||
color = COLOR_OF_FIELD.get(current_tile.category.name, 'white')
|
||||
color = COLORS[color]
|
||||
if (current_tile.x_position,current_tile.y_position) in [(a.x, a.y) for a in self.agent.path]:
|
||||
color = COLORS.get('orange')
|
||||
pygame.draw.rect(self.display, COLORS['black'],
|
||||
(x * TILE_WIDTH, y * TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT))
|
||||
pygame.draw.rect(self.display, color,
|
||||
@ -94,28 +75,11 @@ class MainGameFrame:
|
||||
package_color = get_package_color(pack)
|
||||
pygame.draw.rect(self.display, package_color,
|
||||
((pack_x * TILE_WIDTH) + 3, (pack_y * TILE_HEIGHT) + 3, TILE_WIDTH - 5, TILE_HEIGHT - 5))
|
||||
if pack.category == "freezed":
|
||||
pygame.draw.rect(self.display, COLORS['blue'],
|
||||
((pack_x * TILE_WIDTH) + 2, (pack_y * TILE_HEIGHT) + 2, TILE_WIDTH - 4,
|
||||
TILE_HEIGHT - 4), 3)
|
||||
|
||||
def draw_nums(self):
|
||||
for row in self.warehouse_map.tiles:
|
||||
for cell in row:
|
||||
if cell.category.name in self.warehouse_map.storage_types:
|
||||
text_surface = self.font.render(str(cell.capacity), True, (0, 0, 0))
|
||||
self.display.blit(text_surface, ((cell.x_position * TILE_WIDTH) + 6, (cell.y_position * TILE_HEIGHT) + 6))
|
||||
for package in self.warehouse_map.packages:
|
||||
if package.status == PackStatus.LOOSE:
|
||||
text_surface = self.font.render(str(package.id + 1), True, (0, 0, 0))
|
||||
self.display.blit(text_surface, ((package.lays_on_field.x_position * TILE_WIDTH) + 6, (package.lays_on_field.y_position * TILE_HEIGHT) + 6))
|
||||
|
||||
def draw_agent(self):
|
||||
if self.agent.is_loaded:
|
||||
rotated = pygame.transform.rotate(self.agent_tex2, DIRECTION_ANGLES.get(self.agent.direction))
|
||||
else:
|
||||
rotated = pygame.transform.rotate(self.agent_tex, DIRECTION_ANGLES.get(self.agent.direction))
|
||||
self.display.blit(rotated, (self.agent.x*TILE_WIDTH, self.agent.y*TILE_WIDTH))
|
||||
agent_position_x, agent_position_y = self.agent.x, self.agent.y
|
||||
agent_screen_position = ((agent_position_x*TILE_WIDTH) + CIRCLE_CENTER_X, (agent_position_y*TILE_HEIGHT) + CIRCLE_CENTER_Y)
|
||||
pygame.draw.circle(self.display, COLORS['black'], agent_screen_position, self.agent.radius, int(self.agent.radius/2))
|
||||
|
||||
def set_starting_agent_position(self):
|
||||
starting_x, starting_y = random.randrange(self.warehouse_map.width), random.randrange(self.warehouse_map.height)
|
||||
@ -126,4 +90,4 @@ class MainGameFrame:
|
||||
|
||||
if __name__ == '__main__':
|
||||
maingame = MainGameFrame()
|
||||
maingame.run()
|
||||
maingame.run()
|
BIN
model_weights.h5
@ -1,75 +0,0 @@
|
||||
from sklearn.tree import DecisionTreeClassifier, plot_tree, export_graphviz, DecisionTreeRegressor
|
||||
from sklearn.externals.six import StringIO
|
||||
from IPython.display import Image
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pydotplus
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn import metrics
|
||||
|
||||
PACKAGE_PLACE_TRESHOLD = {
|
||||
"normal": 0.8,
|
||||
"freezed": 0.85,
|
||||
"fragile": 0.85,
|
||||
"flammable": 0.9,
|
||||
"keep_dry": 0.8
|
||||
}
|
||||
|
||||
|
||||
class PackageLocationClassifier():
|
||||
def __init__(self):
|
||||
|
||||
data = StringIO()
|
||||
|
||||
cols_names = ["product", "category", "temperature", "humidity", "chance_of_survive", "place_here"]
|
||||
feature_cols = ["category", "temperature", "humidity"]
|
||||
|
||||
products = pd.read_csv("package_location_classifier/trainset/trainset.csv", header=0, sep=",", names=cols_names)
|
||||
testset = pd.read_csv("package_location_classifier/testset/testset.csv", header=None, sep=",", names=cols_names)
|
||||
products = products.round({"chance_of_survive": 1})
|
||||
testset = testset.round({"chance_of_survive": 1})
|
||||
products.chance_of_survive *= 10
|
||||
testset.chance_of_survive *= 10
|
||||
test_X = pd.get_dummies(testset[feature_cols])
|
||||
test_y = testset.chance_of_survive
|
||||
products = products.sample(frac=1)
|
||||
X_train = pd.get_dummies(products[feature_cols])
|
||||
y_train = products.chance_of_survive
|
||||
dummies_names = X_train.columns.tolist()
|
||||
|
||||
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.01, random_state=1, shuffle=True)
|
||||
|
||||
clf = DecisionTreeRegressor(ccp_alpha=0.02, min_samples_leaf=5, max_depth=5)
|
||||
self.predictor = clf.fit(X_train, y_train)
|
||||
|
||||
y_pred = self.predictor.predict(test_X)
|
||||
|
||||
evaluation = pd.DataFrame({'category': testset.category, 'temperature': testset.temperature , 'humid': testset.humidity ,'Actual': test_y, 'Predicted': y_pred})
|
||||
evaluation = evaluation.round({'Actual': 3, 'Predicted': 3})
|
||||
evaluation['Prediction_diff'] = abs(evaluation['Actual'] - evaluation['Predicted'])
|
||||
print("Prediction differs from actual value by average {}".format(round(evaluation['Prediction_diff'].mean(), 2)))
|
||||
# export_graphviz(clf, out_file=data, filled=True, rounded=True, special_characters=True, feature_names=dummies_names)
|
||||
# graph = pydotplus.graph_from_dot_data(data.getvalue())
|
||||
# graph.write_png('Drzewo.png')
|
||||
# Image(graph.create_png())
|
||||
|
||||
def check_if_can_place(self, package, tile):
|
||||
category = package.category
|
||||
cat_treshold = PACKAGE_PLACE_TRESHOLD[category]
|
||||
fields = [[
|
||||
tile.air_temperature,
|
||||
tile.humidity,
|
||||
category == "flammable",
|
||||
category == "fragile",
|
||||
category=="freezed" ,
|
||||
category == "keep_dry",
|
||||
category == "normal"
|
||||
]]
|
||||
|
||||
quality_of_place = round(self.predictor.predict(fields)[0]/10, 2)
|
||||
if quality_of_place > cat_treshold:
|
||||
return True
|
||||
return False
|
||||
|
||||
if __name__ == '__main__':
|
||||
cfer = PackageLocationClassifier()
|
@ -1,26 +0,0 @@
|
||||
food,normal,20,0.3,0.95,1
|
||||
food,normal,-15,0.3,0.2,0
|
||||
metal,normal,-15,0.3,0.2,0
|
||||
frozen_food,freezed,-15,0.2,1,1
|
||||
frozen_food,freezed,20,0.3,0.01,0
|
||||
frozen_food,freezed,30,0.5,0,0
|
||||
frozen_food,freezed,28,0.5,0,0
|
||||
frozen_food,freezed,28,0.3,0,0
|
||||
electronic,keep_dry,22,0.3,0.99,1
|
||||
electronic,keep_dry,25,0.3,0.99,1
|
||||
electronic,keep_dry,25,0.7,0.4,0
|
||||
electronic,keep_dry,28,0.7,0.3,0
|
||||
gasoline,flammable,28,0.3,0.2,0
|
||||
gasoline,flammable,28,0.7,0.2,0
|
||||
gasoline,flammable,22,0.5,0.95,0
|
||||
gasoline,flammable,20,0.5,1,1
|
||||
gasoline,flammable,20,0.2,1,1
|
||||
books,keep_dry,30,0.7,0.3,0
|
||||
books,keep_dry,30,0.3,0.85,1
|
||||
books,keep_dry,25,0.2,1,1
|
||||
glass,fragile,-15,0.3,0.1,0
|
||||
seeds,freezed,-15,0.3,1,1
|
||||
seeds,freezed,20,0.3,0.1,0
|
||||
metal,normal,25,0.4,0.99,1
|
||||
wood,normal,26,0.3,0.99,1
|
||||
wood,normal,22,0.3,1,1
|
|
@ -1,376 +0,0 @@
|
||||
product,category,temperature,humidity,chance_of_survive,place_here
|
||||
food,normal, 20, 0.5, 0.85, 1
|
||||
food,normal,25, 0.7, 0.6, 0
|
||||
electronic,keep_dry,20, 0.3, 0.95, 1
|
||||
wood,normal,24, 0.5, 0.9, 1
|
||||
electronic,keep_dry,25, 0.7, 0.4, 0
|
||||
ammo,flammable,28, 0.4, 0.2, 0
|
||||
ammo,flammable,27, 0.4, 0.25, 0
|
||||
ammo,flammable,27, 0.6, 0.22, 0
|
||||
ammo,flammable,22, 0.5, 0.8, 1
|
||||
ammo,flammable,23, 0.5, 0.7, 0
|
||||
clothes,keep_dry,25, 0.6, 0.4, 0
|
||||
clothes,keep_dry,25, 0.7, 0.25, 0
|
||||
clothes,keep_dry,25, 0.7, 0.25, 0
|
||||
electronic,keep_dry,22,0.5,0.7,0
|
||||
electronic,keep_dry,22,0.7,0.45,0
|
||||
electronic,keep_dry,22,0.3,0.85,1
|
||||
electronic,keep_dry,22,0.2,0.99,1
|
||||
clothes,keep_dry,25, 0.7, 0.25, 0
|
||||
clothes,keep_dry,25, 0.7, 0.25, 0
|
||||
clothes,keep_dry,24, 0.2, 0.95, 0
|
||||
frozen_food,freezed,24, 0.5, 0.001, 0
|
||||
frozen_food,freezed,22, 0.5, 0.001, 0
|
||||
frozen_food,freezed, 20, 0.5, 0.004, 0
|
||||
frozen_food,freezed,-15, 0.3, 0.999, 1
|
||||
frozen_food,freezed,-15, 0.2, 0.999, 1
|
||||
frozen_food,freezed,-10, 0.3, 0.995, 1
|
||||
frozen_food,freezed, -15, 0.2, 1.00, 1
|
||||
frozen_food,freezed,24, 0.5, 0.001, 0
|
||||
frozen_food,freezed,22, 0.5, 0.001, 0
|
||||
frozen_food,freezed, 20, 0.5, 0.004, 0
|
||||
frozen_food,freezed,-15, 0.3, 0.999, 1
|
||||
frozen_food,freezed,-15, 0.2, 0.999, 1
|
||||
frozen_food,freezed,-10, 0.3, 0.995, 1
|
||||
frozen_food,freezed, -15, 0.2, 1.00, 1
|
||||
frozen_food,freezed,24, 0.5, 0.001, 0
|
||||
frozen_food,freezed,22, 0.5, 0.001, 0
|
||||
frozen_food,freezed, 20, 0.5, 0.004, 0
|
||||
frozen_food,freezed,-15, 0.3, 0.999, 1
|
||||
frozen_food,freezed,-15, 0.2, 0.999, 1
|
||||
frozen_food,freezed,-10, 0.3, 0.995, 1
|
||||
frozen_food,freezed, -15, 0.2, 1.00, 1
|
||||
clothes,keep_dry,28, 0.4, 0.7, 0
|
||||
clothes,keep_dry, 22, 0.4, 0.95, 1
|
||||
clothes,keep_dry, 21, 0.5, 0.5, 0
|
||||
metal,normal,20, 0.3, 1, 1
|
||||
metal,normal, 21, 0.3, 1, 1
|
||||
metal,normal, -10, 0.3, 0.2, 1
|
||||
metal,normal,28, 0.7, 0.9, 1
|
||||
metal,normal,30, 0.7, 0.9, 1
|
||||
wood,normal,25, 0.2, 0.98, 1
|
||||
wood,normal,28, 0.7, 0.65, 0
|
||||
books,keep_dry, 26, 0.7, 0.4, 0
|
||||
books,keep_dry, 24, 0.5, 0.7, 0
|
||||
books,keep_dry, 25, 0.3, 0.99, 1
|
||||
books,keep_dry, 22, 0.4, 0.78, 0
|
||||
books,keep_dry, 25, 0.35, 0.85, 1
|
||||
books,keep_dry, 20, 0.2, 1, 1
|
||||
drugs,keep_dry, 25, 0.5, 0.8, 0
|
||||
drugs,keep_dry, 20, 0.3, 0.99, 1
|
||||
drugs,keep_dry, 21, 0.3, 0.99, 1
|
||||
drugs,keep_dry, 22, 0.7, 0.75, 0
|
||||
drugs,keep_dry, 28, 0.3, 0.81, 0
|
||||
drugs,keep_dry, 23, 0.3, 0.88, 1
|
||||
drugs,keep_dry, 21, 0.37, 0.90, 1
|
||||
glass,fragile, 20, 0.7, 0.995, 1
|
||||
glass,fragile, -15, 0.3, 0.2, 0
|
||||
vials,fragile, -15, 0.3, 0.2, 0
|
||||
vials,fragile, 20, 0.5, 0.95, 1
|
||||
plate,fragile, 25, 0.3, 1, 1
|
||||
phials,fragile, 25, 0.5, 0.999, 1
|
||||
cardboard,keep_dry, 22, 0.3, 0.999, 1
|
||||
cardboard,keep_dry, 23, 0.7, 0.5, 0
|
||||
cardboard,keep_dry, 28, 0.7, 0.4, 0
|
||||
cardboard,keep_dry, 28, 0.5, 0.55, 0
|
||||
cardboard,keep_dry, 25, 0.7, 0.45, 0
|
||||
cardboard,keep_dry, 27, 0.3, 0.9, 1
|
||||
cardboard,keep_dry, 29, 0.3, 0.88, 1
|
||||
cardboard,keep_dry, 24, 0.4, 0.8, 1
|
||||
frozen food,freezed, 20, 0.4, 0.001, 0
|
||||
seeds,freezed, 25, 0.5, 0.2, 0
|
||||
seeds,freezed, 20, 0.8, 0.01, 0
|
||||
seeds,freezed, -10, 0.3, 0.998, 1
|
||||
seeds,freezed, 20, 0.3, 0.6, 0
|
||||
seeds,freezed, -8, 0.3, 0.99, 1
|
||||
seeds,freezed, -10, 0.5, 0.995, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.4, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-14, 0.3, 1, 1
|
||||
frozen food,freezed,-12, 0.3, 0.999, 1
|
||||
frozen food,freezed,-10, 0.3, 0.99, 1
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
food,normal,28,0.5,0.7,0
|
||||
food,normal,26,0.3,0.9,1
|
||||
food,normal,22,0.3,0.99,1
|
||||
gasoline,flammable, 20, 0.4, 1, 1
|
||||
gasoline,flammable,-15,0.3,0.5,0
|
||||
metal,normal,-15,0.3,0.1,0
|
||||
metal,normal,-15,0.4,0.1,0
|
||||
metal,normal,-15,0.2,0.1,0
|
||||
metal,normal,-10,0.2,0.1,0
|
||||
electronic,keep_dry,-15,0.3,0.1,0
|
||||
lacquer,flammable,-15,0.3,0.2,0
|
||||
books,keep_dry,-15,0.3,0.3,0
|
||||
plate,fragile, 20, 0.7, 1, 1
|
||||
plate,fragile, 24, 0.3, 1, 1
|
||||
plate,fragile, -15, 0.3, 0.15, 0
|
||||
plate,fragile, -10, 0.3, 0.2, 0
|
||||
vials,fragile, -15, 0.3, 0.12, 0
|
||||
vials,fragile, 20, 0.7, 1, 1
|
||||
vials,fragile, 20, 0.2, 1, 1
|
||||
books,keep_dry, 20, 0.3, 1, 1
|
||||
frozen food,freezed,20, 0.3, 0.01, 0
|
||||
frozen food,freezed,22, 0.5, 0.01, 0
|
||||
frozen food,freezed,22, 0.2, 0.01, 0
|
||||
frozen food,freezed,22, 0.4, 0.01, 0
|
||||
frozen food,freezed,22, 0.7, 0.01, 0
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
frozen food,freezed,24, 0.3, 0.01, 0
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
frozen food,freezed,28, 0.3, 0.01, 0
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
frozen food,freezed,20, 0.3, 0.01, 0
|
||||
frozen food,freezed,21, 0.5, 0.01, 0
|
||||
frozen food,freezed,20, 0.3, 0.01, 0
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
frozen food,freezed,23, 0.3, 0.01, 0
|
||||
frozen food,freezed,20, 0.5, 0.01, 0
|
||||
frozen food,freezed,22, 0.3, 0.01, 0
|
||||
frozen food,freezed,25, 0.5, 0.01, 0
|
||||
frozen food,freezed,20, 0.3, 0.01, 0
|
||||
frozen food,freezed,20, 0.7, 0.01, 0
|
||||
frozen food,freezed,20, 0.2, 0.01, 0
|
||||
seeds,freezed, 25, 0.5, 0.2, 0
|
||||
seeds,freezed, 20, 0.8, 0.01, 0
|
||||
seeds,freezed, -10, 0.3, 0.998, 1
|
||||
seeds,freezed, 20, 0.3, 0.6, 0
|
||||
seeds,freezed, -8, 0.3, 0.99, 1
|
||||
seeds,freezed, -10, 0.5, 0.995, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.4, 1, 1
|
||||
frozen food,freezed,22, 0.3, 0.00001, 0
|
||||
porcelain,fragile,20, 0.3, 0.99, 1
|
||||
porcelain,fragile,22, 0.5, 0.999, 1
|
||||
cosmetics,normal,20, 0.3, 1, 1
|
||||
cosmetics,normal,28, 0.7, 0.90, 1
|
||||
cosmetics,normal,22, 0.5, 0.99, 1
|
||||
plastic,normal,25, 0.7, 1, 1
|
||||
plastic,normal,24, 0.7, 1, 1
|
||||
plastic,normal,30, 0.4, 0.99, 1
|
||||
plastic,normal, 28, 0.6, 1, 1
|
||||
wood,normal,28,0.5,0.96,1
|
||||
wood,normal,27,0.4,1,1
|
||||
plastic,normal,30, 0.7, 0.985, 1
|
||||
electronic,keep_dry, 25, 0.6, 0.6, 0
|
||||
metal,normal, 22, 0.7, 0.99, 1
|
||||
metal,normal, 30, 0.5, 0.999, 1
|
||||
metal,normal, 25, 0.3, 1, 1
|
||||
metal,normal, 24, 0.4, 1, 1
|
||||
seeds,freezed, 25, 0.5, 0.2, 0
|
||||
seeds,freezed, 20, 0.8, 0.01, 0
|
||||
seeds,freezed, -10, 0.3, 0.998, 1
|
||||
seeds,freezed, 20, 0.3, 0.6, 0
|
||||
seeds,freezed, -8, 0.3, 0.99, 1
|
||||
seeds,freezed, -10, 0.5, 0.995, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.4, 1, 1
|
||||
lacquer,flammable, 30, 0.3, 0.4, 0
|
||||
lacquer,flammable, 28, 0.5, 0.6, 0
|
||||
lacquer,flammable, 28, 0.4, 0.6, 0
|
||||
lacquer,flammable, 29, 0.3, 0.45, 0
|
||||
lacquer,flammable, 25, 0.6, 0.65, 0
|
||||
lacquer,flammable, 24, 0.7, 0.89, 0
|
||||
lacquer,flammable, 22, 0.6, 0.95, 1
|
||||
lacquer,flammable, 20, 0.4, 1, 1
|
||||
lacquer,flammable, 20, 0.7, 1, 1
|
||||
lacquer,flammable, 21, 0.6, 0.99, 1
|
||||
lacquer,flammable, 23, 0.4, 0.9, 0
|
||||
lacquer,flammable, 26, 0.2, 0.6, 0
|
||||
lacquer,flammable, 30, 0.2, 0.35, 0
|
||||
lacquer,flammable, 30, 0.7, 0.35, 0
|
||||
gasoline,flammable, 30, 0.4, 0.1, 0
|
||||
gasoline,flammable, 30, 0.7, 0.1, 0
|
||||
gasoline,flammable, 26, 0.5, 0.4, 0
|
||||
gasoline,flammable, 25, 0.7, 0.5, 0
|
||||
gasoline,flammable, 25, 0.2, 0.5, 0
|
||||
gasoline,flammable, 21, 0.7, 0.99, 1
|
||||
gasoline,flammable, 22, 0.5, 0.92, 1
|
||||
gasoline,flammable, 22, 0.7, 0.93, 1
|
||||
gasoline,flammable, 20, 0.5, 1, 1
|
||||
gasoline,flammable, 20, 0.7, 1, 1
|
||||
gasoline,flammable, 20, 0.4, 1, 1
|
||||
plate,fragile, 20, 0.7, 1, 1
|
||||
plate,fragile, 24, 0.3, 1, 1
|
||||
plate,fragile, -15, 0.3, 0.1, 0
|
||||
plate,fragile, -10, 0.3, 0.2, 0
|
||||
vials,fragile, -15, 0.3, 0.15, 0
|
||||
vials,fragile, 20, 0.7, 1, 1
|
||||
vials,fragile, 20, 0.2, 1, 1
|
||||
books,keep_dry, 20, 0.3, 1, 1
|
||||
books,keep_dry, 20, 0.7, 0.79, 0
|
||||
books,keep_dry, 25, 0.7, 0.75, 0
|
||||
books,keep_dry, 25, 0.2, 0.99, 1
|
||||
books,keep_dry, 28, 0.2, 0.9, 1
|
||||
books,keep_dry, 28, 0.7, 0.2, 0
|
||||
books,keep_dry, 28, 0.6, 0.25, 0
|
||||
books,keep_dry, 26, 0.6, 0.28, 0
|
||||
books,keep_dry,26, 0.2, 0.95, 1
|
||||
cardboard,keep_dry, 28, 0.7, 0.15, 0
|
||||
cardboard,keep_dry, 28, 0.2, 0.9, 1
|
||||
cardboard,keep_dry, 25, 0.2, 0.95, 1
|
||||
cardboard,keep_dry, 25, 0.6, 0.3, 0
|
||||
cardboard,keep_dry, 25, 0.7, 0.2, 0
|
||||
electronics,keep_dry, 21, 0.4, 0.999, 1
|
||||
electronic,keep_dry, 21, 0.7, 0.68, 0
|
||||
electronic,keep_dry, 29, 0.2, 0.998, 1
|
||||
electronic,keep_dry, 29, 0.6, 0.45, 0
|
||||
electronic,keep_dry, 29, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 25, 0.4, 0.82, 1
|
||||
electronic,keep_dry, 25, 0.5, 0.70, 0
|
||||
electronic,keep_dry, 25, 0.7, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.2, 0.995, 1
|
||||
electronic,keep_dry, 28, 0.4, 0.81, 1
|
||||
electronic,keep_dry, 28, 0.6, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.7, 0.4, 0
|
||||
electronic,keep_dry, 28, 0.3, 0.93, 1
|
||||
clothes,keep_dry, 28, 0.3, 0.95, 1
|
||||
clothes,keep_dry, 28, 0.2, 0.999, 1
|
||||
clothes,keep_dry, 28, 0.7, 0.3, 0
|
||||
wood,normal, 27, 0.2, 1, 1
|
||||
wood,normal, 27, 0.7, 0.95, 1
|
||||
wood,normal, 25, 0.7, 0.96, 1
|
||||
wood,normal, 20, 0.3, 1, 1
|
||||
wood,normal, 23, 0.2, 1, 1
|
||||
wood,normal, 23, 0.7, 0.98, 1
|
||||
electronic,keep_dry, 29, 0.6, 0.45, 0
|
||||
electronic,keep_dry, 29, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 24, 0.4, 0.82, 1
|
||||
electronic,keep_dry, 20, 0.5, 0.72, 0
|
||||
electronic,keep_dry, 25, 0.7, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.2, 0.995, 1
|
||||
electronic,keep_dry, 28, 0.4, 0.81, 1
|
||||
electronic,keep_dry, 28, 0.6, 0.5, 0
|
||||
electronic,keep_dry, 30, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 28, 0.3, 0.93, 1
|
||||
clothes,keep_dry, 28, 0.3, 0.95, 1
|
||||
clothes,keep_dry, 28, 0.2, 0.999, 1
|
||||
clothes,keep_dry, 28, 0.7, 0.3, 0
|
||||
wood,normal, 27, 0.2, 1, 1
|
||||
wood,normal, 27, 0.7, 0.95, 1
|
||||
wood,normal, 25, 0.7, 0.96, 1
|
||||
wood,normal, 20, 0.3, 1, 1
|
||||
wood,normal, 23, 0.2, 1, 1
|
||||
wood,normal, 23, 0.7, 0.98, 1
|
||||
wood,normal,30,0.7,0.95,1
|
||||
books,keep_dry, 20, 0.7, 0.79, 0
|
||||
books,keep_dry, 25, 0.7, 0.75, 0
|
||||
books,keep_dry, 25, 0.2, 0.99, 1
|
||||
books,keep_dry,-15,0.3,0.2,0
|
||||
books,keep_dry,-15,0.2,0.2,0
|
||||
cardboard,keep_dry,-10,0.2,0.2,0
|
||||
cardboard,keep_dry,-15,0.3,0.2,0
|
||||
books,keep_dry, 28, 0.2, 0.9, 1
|
||||
books,keep_dry, 28, 0.7, 0.2, 0
|
||||
books,keep_dry, 28, 0.6, 0.25, 0
|
||||
books,keep_dry, 26, 0.6, 0.28, 0
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
books,keep_dry,26, 0.2, 0.95, 1
|
||||
cardboard,keep_dry, 28, 0.7, 0.15, 0
|
||||
cardboard,keep_dry, 28, 0.2, 0.9, 1
|
||||
cardboard,keep_dry, 25, 0.2, 0.95, 1
|
||||
cardboard,keep_dry, 25, 0.6, 0.3, 0
|
||||
cardboard,keep_dry, 25, 0.7, 0.2, 0
|
||||
electronics,keep_dry, 21, 0.4, 0.999, 1
|
||||
electronic,keep_dry, 21, 0.7, 0.68, 0
|
||||
electronic,keep_dry, 29, 0.2, 0.998, 1
|
||||
electronic,keep_dry, 29, 0.6, 0.45, 0
|
||||
cardboard,keep_dry, 30, 0.7, 0.2, 0
|
||||
cardboard,keep_dry, 30, 0.6, 0.25, 0
|
||||
electronic,keep_dry, 29, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 25, 0.4, 0.82, 1
|
||||
electronic,keep_dry, 25, 0.5, 0.70, 0
|
||||
electronic,keep_dry, 25, 0.7, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.2, 0.995, 1
|
||||
electronic,keep_dry, 28, 0.4, 0.81, 1
|
||||
electronic,keep_dry, 28, 0.6, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.7, 0.4, 0
|
||||
electronic,keep_dry, 28, 0.3, 0.93, 1
|
||||
clothes,keep_dry, 28, 0.3, 0.95, 1
|
||||
clothes,keep_dry, 28, 0.2, 0.999, 1
|
||||
clothes,keep_dry, 28, 0.7, 0.3, 0
|
||||
wood,normal, 27, 0.2, 1, 1
|
||||
wood,normal, 27, 0.7, 0.95, 1
|
||||
wood,normal, 25, 0.7, 0.96, 1
|
||||
wood,normal, 20, 0.3, 1, 1
|
||||
cardboard,keep_dry, 28, 0.5, 0.55, 0
|
||||
cardboard,keep_dry, 25, 0.7, 0.45, 0
|
||||
cardboard,keep_dry, 27, 0.3, 0.9, 1
|
||||
cardboard,keep_dry, 29, 0.3, 0.9, 1
|
||||
cardboard,keep_dry, 24, 0.4, 0.8, 1
|
||||
frozen food,freezed, 20, 0.4, 0.001, 0
|
||||
seeds,freezed, 25, 0.5, 0.2, 0
|
||||
seeds,freezed, 20, 0.8, 0.01, 0
|
||||
seeds,freezed, -10, 0.3, 0.998, 1
|
||||
seeds,freezed, 20, 0.3, 0.6, 0
|
||||
seeds,freezed, -8, 0.3, 0.99, 1
|
||||
seeds,freezed, -10, 0.5, 0.995, 1
|
||||
seeds,freezed, -15, 0.3, 1, 1
|
||||
seeds,freezed, -15, 0.4, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-15, 0.3, 1, 1
|
||||
frozen food,freezed,-14, 0.3, 1, 1
|
||||
frozen food,freezed,-12, 0.3, 0.999, 1
|
||||
frozen food,freezed,-2, 0.3, 0.7, 0
|
||||
frozen food,freezed,2, 0.3, 0.5, 0
|
||||
frozen food,freezed,5, 0.3, 0.2, 0
|
||||
frozen food,freezed,-10, 0.3, 0.99, 1
|
||||
frozen food,freezed,20, 0.3, 0, 0
|
||||
frozen food,freezed,25, 0.3, 0, 0
|
||||
frozen food,freezed,25, 0.7, 0, 0
|
||||
frozen food,freezed,22, 0.4, 0, 0
|
||||
frozen food,freezed,22, 0.5, 0, 0
|
||||
frozen food,freezed,22, 0.2, 0, 0
|
||||
seeds,freezed, 25, 0.5, 0, 0
|
||||
seeds,freezed, 20, 0.8, 0.01, 0
|
||||
seeds,freezed, -5, 0.3, 0.5, 1
|
||||
seeds,freezed, 20, 0.3, 0.1, 0
|
||||
seeds,freezed, -8, 0.3, 0.8, 1
|
||||
seeds,freezed, 20, 0.5, 0.1, 0
|
||||
wood,normal, 20, 0.3, 1, 1
|
||||
wood,normal, 23, 0.2, 1, 1
|
||||
wood,normal, 23, 0.7, 0.98, 1
|
||||
electronic,keep_dry, 29, 0.6, 0.45, 0
|
||||
electronic,keep_dry, 29, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 24, 0.4, 0.82, 1
|
||||
electronic,keep_dry, 20, 0.5, 0.72, 0
|
||||
electronic,keep_dry, 25, 0.7, 0.5, 0
|
||||
electronic,keep_dry, 28, 0.2, 0.995, 1
|
||||
electronic,keep_dry, 28, 0.4, 0.81, 1
|
||||
electronic,keep_dry, 28, 0.6, 0.5, 0
|
||||
electronic,keep_dry, 30, 0.7, 0.35, 0
|
||||
electronic,keep_dry, 28, 0.3, 0.93, 1
|
||||
clothes,keep_dry, 28, 0.3, 0.95, 1
|
||||
clothes,keep_dry, 28, 0.2, 0.999, 1
|
||||
clothes,keep_dry, 28, 0.7, 0.3, 0
|
||||
wood,normal, 27, 0.2, 1, 1
|
||||
wood,normal, 27, 0.7, 0.95, 1
|
||||
wood,normal, 25, 0.7, 0.96, 1
|
||||
wood,normal, 20, 0.3, 1, 1
|
||||
wood,normal, 23, 0.2, 1, 1
|
||||
wood,normal, 23, 0.7, 0.98, 1
|
||||
wood,normal,-10,0.3,0.2,0
|
||||
wood,normal,-15,0.3,0.1,0
|
||||
wood,normal,-15,0.2,0.2,0
|
||||
wood,normal,-15,0.3,0.1,0
|
||||
wood,normal,30,0.7,0.95,1
|
||||
food,normal,28,0.5,0.7,0
|
||||
food,normal,26,0.3,0.9,1
|
||||
food,normal,-15,0.2,0.2,0
|
||||
food,normal,-12,0.2,0.3,0
|
||||
electronic,keep_dry,-15,0.3,0.1,0
|
||||
food,normal,-15,0.3,0.2,0
|
||||
food,normal,22,0.3,0.99,1
|
||||
|
||||
|
|
@ -1,33 +0,0 @@
|
||||
PRODUCT_TYPES = {
|
||||
"freezed": [
|
||||
"frozen food",
|
||||
"seeds",
|
||||
],
|
||||
"fragile": [
|
||||
"glass",
|
||||
"porcelain",
|
||||
"vials",
|
||||
"phials",
|
||||
"plate",
|
||||
],
|
||||
"keep_dry": [
|
||||
"electronic",
|
||||
"drugs",
|
||||
"books",
|
||||
"clothes",
|
||||
"cardboard"
|
||||
],
|
||||
"normal": [
|
||||
"cosmetics",
|
||||
"wood",
|
||||
"metal",
|
||||
"plastic",
|
||||
"food"
|
||||
],
|
||||
"flammable": [
|
||||
"gasoline",
|
||||
"lacquer",
|
||||
"ammo"
|
||||
]
|
||||
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
absl-py==0.9.0
|
||||
astroid==2.4.0
|
||||
astunparse==1.6.3
|
||||
backcall==0.1.0
|
||||
cachetools==4.1.0
|
||||
certifi==2020.4.5.2
|
||||
chardet==3.0.4
|
||||
cycler==0.10.0
|
||||
decorator==4.4.2
|
||||
et-xmlfile==1.0.1
|
||||
gast==0.3.3
|
||||
google-auth==1.17.2
|
||||
google-auth-oauthlib==0.4.1
|
||||
google-pasta==0.2.0
|
||||
graphviz==0.14
|
||||
grpcio==1.29.0
|
||||
h5py==2.10.0
|
||||
idna==2.9
|
||||
importlib-metadata==1.6.1
|
||||
ipython==7.14.0
|
||||
ipython-genutils==0.2.0
|
||||
isort==4.3.21
|
||||
jdcal==1.4.1
|
||||
jedi==0.17.0
|
||||
joblib==0.14.1
|
||||
Keras==2.3.1
|
||||
Keras-Applications==1.0.8
|
||||
Keras-Preprocessing==1.1.2
|
||||
kiwisolver==1.2.0
|
||||
lazy-object-proxy==1.4.3
|
||||
Markdown==3.2.2
|
||||
matplotlib==3.2.1
|
||||
mccabe==0.6.1
|
||||
numpy==1.18.4
|
||||
oauthlib==3.1.0
|
||||
openpyxl==3.0.3
|
||||
opt-einsum==3.2.1
|
||||
pandas==1.0.3
|
||||
parso==0.7.0
|
||||
pexpect==4.8.0
|
||||
pickleshare==0.7.5
|
||||
prompt-toolkit==3.0.5
|
||||
protobuf==3.12.2
|
||||
ptyprocess==0.6.0
|
||||
pyasn1==0.4.8
|
||||
pyasn1-modules==0.2.8
|
||||
pydotplus==2.0.2
|
||||
pygame==1.9.6
|
||||
Pygments==2.6.1
|
||||
pylint==2.5.0
|
||||
pyparsing==2.4.7
|
||||
python-dateutil==2.8.1
|
||||
pytz==2020.1
|
||||
PyYAML==5.3.1
|
||||
requests==2.23.0
|
||||
requests-oauthlib==1.3.0
|
||||
rsa==4.6
|
||||
scikit-learn==0.22.2.post1
|
||||
scipy==1.4.1
|
||||
six==1.14.0
|
||||
sklearn==0.0
|
||||
tensorboard==2.2.2
|
||||
tensorboard-plugin-wit==1.6.0.post3
|
||||
tensorflow==2.2.0
|
||||
tensorflow-estimator==2.2.0
|
||||
termcolor==1.1.0
|
||||
toml==0.10.0
|
||||
traitlets==4.3.3
|
||||
typed-ast==1.4.1
|
||||
urllib3==1.25.9
|
||||
wcwidth==0.1.9
|
||||
Werkzeug==1.0.1
|
||||
wrapt==1.12.1
|
||||
zipp==3.1.0
|
@ -1,95 +0,0 @@
|
||||
#### Definicja pętli głównej przeszukiwania:
|
||||
W algorytmie znajdowania najlepszej ścieżki wykorzystana została kolejka priorytetowa *PriorityQueue()* służąca do przechowywania wierzchołków do odwiedzenia. Dopóki nie jest ona pusta, działa pętla główna przeszukiwania. W pętli kolejno:
|
||||
|
||||
1. z kolejki wybierany jest wierzchołek o najniższym priorytecie
|
||||
```python
|
||||
while self.open:
|
||||
_, current_node = self.open.get()
|
||||
```
|
||||
|
||||
2. dodawany jest on do listy już przeszukanych wierzchołków
|
||||
```python
|
||||
self.closed.append(current_node)
|
||||
```
|
||||
|
||||
3. sprawdzane jest czy aktualny wierzchołek jest jednocześnie celem, który miał zostać osiągnięty przez agenta
|
||||
```python
|
||||
if current_node.x == self.dest.x and current_node.y == self.dest.y:
|
||||
while current_node.x != start_node.x or current_node.y != start_node.y:
|
||||
self.path.append(current_node)
|
||||
current_node = current_node.parent
|
||||
return True
|
||||
```
|
||||
|
||||
>(jeśli tak, od strony celu odtwarzana jest najkrótsza ścieżka prowadząca z aktualnego punktu do celu)
|
||||
|
||||
4. znajdowani są sąsiedzi danego wierzchołka, a następnie dla każdego z nich:
|
||||
|
||||
+ liczony jest koszt za pomocą funkcji heurystyki
|
||||
```python
|
||||
cost = current_node.g_cost + self.heuristic(current_node, neighbour)
|
||||
```
|
||||
|
||||
+ sprawdane jest czy nie należy on do listy już przeszukanych wierzchołkow (jeśli tak, zostaje on pominięty)
|
||||
```python
|
||||
if self.check_if_closed(neighbour):
|
||||
continue
|
||||
```
|
||||
|
||||
+ jeśli znajduje się on już w kolejce priorytetowej ale z większym kosztem niż ten obecnie wyliczony, uaktualniony zostaje jego koszt oraz rodzic
|
||||
```python
|
||||
if self.check_if_open(neighbour):
|
||||
if neighbour.g_cost > cost:
|
||||
neighbour.g_cost = cost
|
||||
neighbour.parent = current_node
|
||||
```
|
||||
|
||||
+ w przeciwnym przypadku, zostaje on dodany do kolejki priorytetowej wraz ze swoim rodzicem oraz wyliczonym kosztem.
|
||||
```python
|
||||
else:
|
||||
neighbour.g_cost = cost
|
||||
neighbour.h_cost = self.heuristic(neighbour, self.dest)
|
||||
neighbour.parent = current_node
|
||||
self.open.put((neighbour.g_cost, neighbour))
|
||||
```
|
||||
|
||||
#### Definicja funkcji następnika:
|
||||
|
||||
```python
|
||||
def get_neighbours(self, node: Node):
|
||||
neighbours = []
|
||||
if self.check_if_can_move(Coordinates(node.x + 1, node.y)):
|
||||
neighbours.append(Node(node.x + 1, node.y))
|
||||
if self.check_if_can_move(Coordinates(node.x - 1, node.y)):
|
||||
neighbours.append(Node(node.x - 1, node.y))
|
||||
if self.check_if_can_move(Coordinates(node.x, node.y + 1)):
|
||||
neighbours.append(Node(node.x, node.y + 1))
|
||||
if self.check_if_can_move(Coordinates(node.x, node.y - 1)):
|
||||
neighbours.append(Node(node.x, node.y - 1))
|
||||
return neighbours
|
||||
```
|
||||
Funkcja zwracająca następników w naszym projekcie wykorzystuje sąsiedztwo von Neumanna. Sąsiadami danej płytki, są 4 najbliższe płytki znajdujące się od niej powyżej, poniżej, na prawo oraz na lewo.
|
||||
|
||||
Dla każdego z 4 potencjalnych sąsiadów sprawdzane jest najpierw czy takowy istnieje za pomocą funkcji *check_if_can_move*:
|
||||
|
||||
```python
|
||||
def check_if_can_move(self, next_coords: Coordinates):
|
||||
tile_on_map = 0 <= next_coords.x < self.warehouse.width and 0 <= next_coords.y < self.warehouse.height
|
||||
if not tile_on_map:
|
||||
return False
|
||||
next_tile = self.warehouse.tiles[next_coords.x][next_coords.y]
|
||||
tile_passable = isinstance(next_tile, Tile) and next_tile.category.passable
|
||||
return tile_passable
|
||||
```
|
||||
|
||||
Funkcja ta sprawdza czy wybrany sąsiad znajduje się w obrębie magazynu i czy jest on płytką po której może przemieszczać się agent.
|
||||
|
||||
#### Definicja funkcji heurystyki:
|
||||
|
||||
```python
|
||||
def heuristic(self, start: Node, goal: Node):
|
||||
diff_x = pow(goal.x - start.x, 2)
|
||||
diff_y = pow(goal.y - start.y, 2)
|
||||
return round(sqrt(diff_x + diff_y), 3)
|
||||
```
|
||||
w naszym projekcie jako heurystyki używamy funkcji liczącej odległość euklidesową pomiędzy dwoma wybranymi punktami, z których drugi jest aktualnym celem który agent ma osiągnąć.
|
43
siec.py
@ -1,43 +0,0 @@
|
||||
import numpy
|
||||
from keras.datasets import mnist
|
||||
from keras.layers import Conv2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Flatten
|
||||
from keras.models import Sequential
|
||||
from keras.utils import np_utils
|
||||
from keras_preprocessing.image import load_img, img_to_array
|
||||
|
||||
|
||||
img_rows, img_cols = 28, 28
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
producent = []
|
||||
def imageClass(model):
|
||||
model.add(Conv2D(75, kernel_size=(5, 5),
|
||||
activation='relu',
|
||||
input_shape=input_shape))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Conv2D(100, (5, 5), activation='relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Flatten())
|
||||
model.add(Dense(500, activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(10, activation='softmax'))
|
||||
|
||||
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
|
||||
nmodel = Sequential()
|
||||
imageClass(nmodel)
|
||||
nmodel.load_weights('model_weights.h5')
|
||||
|
||||
def imgSkan():
|
||||
img_width, img_height = 28, 28
|
||||
new_image = load_img('cyfra.png', target_size=(img_width, img_height), color_mode = "grayscale")
|
||||
new_image = img_to_array(new_image)
|
||||
new_image = new_image.reshape((1,) + new_image.shape)
|
||||
|
||||
prediction = nmodel.predict(new_image)
|
||||
prediction = numpy.argmax(prediction)
|
||||
print("Producent:", prediction)
|
||||
producent.append(prediction)
|
86
sieci.md
@ -1,86 +0,0 @@
|
||||
# Temat podptojektu:
|
||||
Stworzenie sieci neuronowej, która rozpoznaje odręcznie napisaną na paczce liczbę, która oznacza producenta paczki.
|
||||
|
||||
# Uczenie modelu
|
||||
## Dane wejściowe:
|
||||
### Pakiet Keras MNIST:
|
||||
- dwa pliki:
|
||||
- Plik z obrazkami
|
||||
- Plik z poprawnymi odpowiedziami
|
||||
### Format obrazków:
|
||||
- rozmiar 28x28
|
||||
- odcienie szarości (0-biały, 255- czarny)
|
||||
- obrazki w postaci binarnej są zapisane w jeden plik
|
||||
## Praca z pakietem:
|
||||
1. Zdefiniowano dane treningowe: tensory wejściowe i tensory wartości docelowych.
|
||||
2. Zdefiniowano warstwy sieci (lub modelu) przypisującej dane wejściowe do docelowych wartości.
|
||||
3. Skonfigurowano proces uczenia, wybierając funkcję straty, optymalizator i monitorowane metryki.
|
||||
4. Wykonano iteracje procesu uczenia na danych treningowych, wywołując metodę
|
||||
fit() zdefiniowanego modelu
|
||||
|
||||
# Proces uczenia
|
||||
-ustawiam seed, aby powtarzać wyniki
|
||||
-pobieram dane
|
||||
- konwertuję wymiary obrazu
|
||||
- normalizuję dane
|
||||
- konwertuję etykiety w kategorie
|
||||
## Inicjalizuję sieć neuronową (sieć sekwencyjna).
|
||||
model = Sequential()
|
||||
model.add(Conv2D(75, kernel_size=(5, 5),
|
||||
activation='relu',
|
||||
input_shape=input_shape))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Conv2D(100, (5, 5), activation='relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Flatten())
|
||||
model.add(Dense(500, activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(10, activation='softmax'))
|
||||
|
||||
### Dołączam kolejno warstwy:
|
||||
- Conv2D - mnoży obrazek przez macierz 2x2
|
||||
- activation='relu' - zeruje negatywne wyniki (funkcja aktuwacji)
|
||||
- MaxPooling2D - zmienia rozdzielczość zdjęcia
|
||||
- Droupout - ogranicza nadmierne dopasowanie
|
||||
- Flatten - spłaszcza macierz do wektora
|
||||
- Dense(10) - decyduje o przynależności zdjęcia do kategorii (cyfry od 0 do 9)
|
||||
Activation='soft-max' - zwraca rozkład prawdopodobieństwa 10 różnych klas
|
||||
|
||||
## Kompilacja modelu:
|
||||
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
Funkcja straty - "catecorical_crossentropy"
|
||||
Optymalizator - "Adam"
|
||||
Monitorowanie dokładności - "accuracy"
|
||||
|
||||
## Trenowanie modelu:
|
||||
model.fit(X_train, Y_train, batch_size=200, epochs=10, validation_split=0.2, verbose=1)
|
||||
trenuję model za pomocą funkcji fit()
|
||||
### Pokazuję dokładność pracy na testowanych rannych
|
||||
scores = model.evaluate(X_test, Y_test, verbose=0)
|
||||
print("Dokadnosc na testowanych dannych: %.2f%%" % (scores[1]*100))
|
||||
|
||||
# Integracja z projektem
|
||||
Tworzę model i ładuję wagi nauczonego modelu.
|
||||
|
||||
nmodel = Sequential()
|
||||
imageClass(nmodel)
|
||||
nmodel.load_weights('model_weights.h5')
|
||||
|
||||
Po podniesieniu paczki odpalana jest funkcja imgSkan(), która z czytuje ręcznie napisaną cyfrę i wpisuje nr producenta paczki.
|
||||
|
||||
def imgSkan():
|
||||
img_width, img_height = 28, 28
|
||||
new_image = load_img('cyfra.png', target_size=(img_width, img_height), color_mode = "grayscale")
|
||||
new_image = img_to_array(new_image)
|
||||
new_image = new_image.reshape((1,) + new_image.shape)
|
||||
|
||||
prediction = nmodel.predict(new_image)
|
||||
prediction = numpy.argmax(prediction)
|
||||
print("Producent:", prediction)
|
||||
producent.append(prediction)
|
||||
|
||||
|
||||
|
||||
|
51
sieci_n.py
@ -1,51 +0,0 @@
|
||||
import numpy
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Flatten
|
||||
from keras.layers import Conv2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
numpy.random.seed(42)
|
||||
|
||||
img_rows, img_cols = 28, 28
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
|
||||
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
|
||||
Y_train = np_utils.to_categorical(y_train, 10)
|
||||
Y_test = np_utils.to_categorical(y_test, 10)
|
||||
|
||||
model = Sequential()
|
||||
|
||||
model.add(Conv2D(75, kernel_size=(5, 5),
|
||||
activation='relu',
|
||||
input_shape=input_shape))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Conv2D(100, (5, 5), activation='relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Flatten())
|
||||
model.add(Dense(500, activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(10, activation='softmax'))
|
||||
|
||||
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
|
||||
|
||||
model.summary()
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=200, epochs=10, validation_split=0.2, verbose=1)
|
||||
|
||||
scores = model.evaluate(X_test, Y_test, verbose=0)
|
||||
print("Dokadnosc na testowanych dannych: %.2f%%" % (scores[1]*100))
|
||||
|
||||
|
||||
model.save_weights('model_weights.h5')
|
0
srodowisko_agenta.png
Executable file → Normal file
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 92 KiB |
138
warehouse.py
Executable file → Normal file
@ -1,68 +1,43 @@
|
||||
from attributes import PackStatus
|
||||
from products_types import PRODUCT_TYPES
|
||||
from attributes import PackSize, PackStatus
|
||||
import random
|
||||
import queue
|
||||
from collections import namedtuple
|
||||
import itertools
|
||||
|
||||
Coordinates = namedtuple("Coordinates", 'x y')
|
||||
Coordinates = namedtuple("Coordinates",'x y')
|
||||
|
||||
class CategoryData:
|
||||
def __init__(self, name, passable=False, can_store=True, location='general'):
|
||||
def __init__(self, name, passable=False, can_store=True, location='general', pack_size=PackSize.ALL, cost=1):
|
||||
self.name = name
|
||||
self.passable = passable
|
||||
self.can_store = can_store
|
||||
self.cost = cost
|
||||
self.location = location
|
||||
self.pack_size = pack_size
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
class Pack:
|
||||
def __init__(self, size=5, categ='normal', lays_on_field=None):
|
||||
def __init__(self, size=PackSize.MEDIUM, categ='general', lays_on_field=None):
|
||||
self.size = size
|
||||
self.category = categ
|
||||
self.products_inside = self.set_products_inside()
|
||||
|
||||
assert isinstance(lays_on_field, Tile), AssertionError("Attribute lays_on_field must be a Tile object! You know, package cannot lay in void :)")
|
||||
self.lays_on_field = lays_on_field
|
||||
self.status = self.set_status()
|
||||
|
||||
def set_status(self):
|
||||
status = PackStatus.LOOSE
|
||||
if self.lays_on_field.category.name in ['Floor', 'FridgeFloor']:
|
||||
if self.lays_on_field.category.name == 'Floor':
|
||||
status = PackStatus.LOOSE
|
||||
else:
|
||||
elif self.lays_on_field.category.name == 'Rack':
|
||||
status = PackStatus.STORED
|
||||
return status
|
||||
|
||||
def set_products_inside(self):
|
||||
seed = random.random()
|
||||
products_category = None
|
||||
if seed < 0.6:
|
||||
products_category = "normal"
|
||||
elif 0.6 <= seed < 0.75:
|
||||
products_category = "keep_dry"
|
||||
elif 0.75 <= seed < 0.9:
|
||||
products_category = "fragile"
|
||||
elif 0.9 <= seed < 0.98:
|
||||
products_category = "freezed"
|
||||
elif 0.96 <= seed <= 1.0:
|
||||
products_category = "flammable"
|
||||
|
||||
products_in_category = PRODUCT_TYPES.get(products_category, ["food"])
|
||||
self.category = products_category
|
||||
product_inside = random.choice(products_in_category)
|
||||
# print(product_inside)
|
||||
return product_inside
|
||||
|
||||
def __repr__(self):
|
||||
return "Pack {} -{}, on field {}".format(self.products_inside, self.category, self.lays_on_field)
|
||||
|
||||
CATEGORY = {
|
||||
'floor': CategoryData('Floor', True, False), #lava
|
||||
'rack': CategoryData('Rack', False, True),
|
||||
'fridge_floor': CategoryData('FridgeFloor', True, False, location='cold_room'),
|
||||
'fridge': CategoryData('Fridge', False, True, location='cold_room')
|
||||
'floor': CategoryData('Floor', True, False, cost=1), #lava
|
||||
'rack': CategoryData('Rack', False, True, cost=100000),
|
||||
# 'freezer': CategoryData('Freezer', False, True, location='cold_room')
|
||||
}
|
||||
|
||||
|
||||
@ -72,16 +47,11 @@ class Warehouse:
|
||||
self.height = length
|
||||
self.tiles = self.generate_map()
|
||||
self.no_of_racks = no_of_racks
|
||||
self.storage_types = ["Rack", "Fridge"]
|
||||
self.no_of_packages = no_of_packages
|
||||
self.generate_racks()
|
||||
self.open_isolated_areas()
|
||||
self.set_temperature(20, 30)
|
||||
self.set_humidity()
|
||||
self.create_fridge(8)
|
||||
# print([row[0].air_temperature for row in self.tiles])
|
||||
self.packages = self.place_packages(no_of_packages)
|
||||
self.tiles[1][1] = Tile('floor', 1, 1)
|
||||
|
||||
def __str__(self):
|
||||
return "Magazyn {}x{}".format(self.width, self.height)
|
||||
|
||||
@ -99,7 +69,7 @@ class Warehouse:
|
||||
node_x, node_y = random.randrange(1, self.width-1), random.randrange(1, self.height-1)
|
||||
node = self.tiles[node_x][node_y]
|
||||
next_node = None
|
||||
self.tiles[node_x][node_y] = Tile('rack', node_x, node_y, capacity=random.randrange(15, 20), temperature=node.air_temperature, humidity=node.humidity)
|
||||
self.tiles[node_x][node_y] = Tile('rack', node_x, node_y)
|
||||
q.put(node)
|
||||
while not q.empty():
|
||||
if next_node is not None:
|
||||
@ -121,51 +91,7 @@ class Warehouse:
|
||||
return
|
||||
node_x = next_node.x_position
|
||||
node_y = next_node.y_position
|
||||
self.tiles[node_x][node_y] = Tile('rack', node_x, node_y, capacity=random.randrange(15, 20), temperature=next_node.air_temperature, humidity=next_node.humidity)
|
||||
|
||||
def set_temperature(self, min_temperature=20, max_temperature=30):
|
||||
for num, row in enumerate(self.tiles):
|
||||
row_temperature = min_temperature + round(num/2)
|
||||
for cell in row:
|
||||
cell.air_temperature = row_temperature
|
||||
|
||||
def set_humidity(self, min_humidity=0.2, max_humidity=0.7):
|
||||
current_humidity = min_humidity
|
||||
for y in range(self.height):
|
||||
current_humidity += (0.1/4)
|
||||
for x in range(self.width):
|
||||
self.tiles[x][y].humidity = round(current_humidity, 1)
|
||||
# print(round(current_humidity, 1))
|
||||
|
||||
|
||||
def create_fridge(self, size):
|
||||
x_corner = random.choice(['left', 'right'])
|
||||
y_corner = random.choice(['top', 'bottom'])
|
||||
start_x = None
|
||||
start_y = None
|
||||
end_x = None
|
||||
end_y = None
|
||||
if x_corner == 'left':
|
||||
start_x = 0
|
||||
end_x = size
|
||||
else:
|
||||
start_x = (self.width-1) - size
|
||||
end_x = self.width - 1
|
||||
|
||||
if y_corner == 'top':
|
||||
start_y = 0
|
||||
end_y = size
|
||||
else:
|
||||
start_y = (self.height-1) - size
|
||||
end_y = self.height - 1
|
||||
|
||||
rows = self.tiles[start_x:end_x].copy()
|
||||
for num, row in enumerate(rows, start_x):
|
||||
for index, tile in enumerate(row[start_y:end_y], start_y):
|
||||
if self.tiles[num][index].category.name == "Floor":
|
||||
self.tiles[num][index] = Tile('fridge_floor', num, index, temperature=-5)
|
||||
else:
|
||||
self.tiles[num][index] = Tile('fridge', num, index, capacity=random.randrange(10, 12), temperature=-15)
|
||||
self.tiles[node_x][node_y] = Tile('rack', node_x, node_y)
|
||||
|
||||
def get_not_rack_nodes(self, node_x, node_y):
|
||||
adjacent_tiles = self.get_adjacent_tiles(node_x, node_y)
|
||||
@ -220,40 +146,29 @@ class Warehouse:
|
||||
self.tiles[bottom_left.x][bottom_left.y]
|
||||
]
|
||||
return diagonals
|
||||
|
||||
def get_all_racks(self, all_storages=False):
|
||||
def get_all_racks(self):
|
||||
""":return list of Tile objects"""
|
||||
racks = []
|
||||
for x in self.tiles:
|
||||
for x in self.tiles:
|
||||
# row_racks = [t for t in self.tiles[x] if t.category.name == 'Rack']
|
||||
for y in x:
|
||||
if all_storages:
|
||||
if y.category.name in self.storage_types:
|
||||
racks.append(y)
|
||||
elif y.category.name == 'Rack':
|
||||
if y.category.name == 'Rack':
|
||||
racks.append(y)
|
||||
return racks
|
||||
|
||||
def place_packages(self, no_of_packages: int):
|
||||
|
||||
def place_packages(self, no_of_packages):
|
||||
packages = []
|
||||
for i in range(no_of_packages):
|
||||
new_package_size = random.randrange(1, 10)
|
||||
pack_x, pack_y = self._set_package_position(new_package_size)
|
||||
pack_x, pack_y = self._set_package_position()
|
||||
package_field = self.tiles[pack_x][pack_y]
|
||||
new_package = Pack(lays_on_field=package_field)
|
||||
new_package.size = new_package_size
|
||||
new_package.id = i
|
||||
new_package.x = pack_x
|
||||
new_package.y = pack_y
|
||||
if package_field.category.name in self.storage_types:
|
||||
package_field.capacity -= new_package.size
|
||||
self.tiles[pack_x][pack_y] = new_package
|
||||
packages.append(new_package)
|
||||
return packages
|
||||
|
||||
def _set_package_position(self, pack_size: int):
|
||||
def _set_package_position(self):
|
||||
starting_x, starting_y = random.randrange(self.width), random.randrange(self.height)
|
||||
while not isinstance(self.tiles[starting_x][starting_y], Tile) \
|
||||
or self.tiles[starting_x][starting_y].capacity - pack_size < 0:
|
||||
while not isinstance(self.tiles[starting_x][starting_y], Tile):
|
||||
starting_x, starting_y = random.randrange(self.width), random.randrange(
|
||||
self.height)
|
||||
return starting_x, starting_y
|
||||
@ -289,17 +204,14 @@ class Warehouse:
|
||||
return wall
|
||||
|
||||
class Tile:
|
||||
def __init__(self, category, x_position, y_position, capacity=10, temperature: int=24, humidity: float=0.3):
|
||||
def __init__(self, category, x_position, y_position):
|
||||
self.category = CATEGORY.get(category, CATEGORY['floor'])
|
||||
self.x_position = x_position
|
||||
self.y_position = y_position
|
||||
self.air_temperature = temperature
|
||||
self.humidity = humidity
|
||||
self.capacity = capacity
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return "Tile type: {} on position ({},{})".format(self.category, self.x_position, self.y_position)
|
||||
|
||||
def __repr__(self):
|
||||
return "Tile type: {} on position ({},{})".format(self.category, self.x_position, self.y_position)
|
||||
return "Tile type: {} on position ({},{})".format(self.category, self.x_position, self.y_position)
|
BIN
wyniki_testu.PNG
Before Width: | Height: | Size: 90 KiB |