From a16ec52642067a2be0b41a5c3bcab24193122343 Mon Sep 17 00:00:00 2001 From: Kacper Kalinowski Date: Fri, 10 Jun 2022 10:53:42 +0200 Subject: [PATCH] TSP v5 --- decision_tree/tree_as_txt.txt | 182 ++++++------ decision_tree/tree_model | Bin 5511 -> 5556 bytes genetic_algorithm/TSP.py | 485 +++++++++++++++--------------- last_map.nparr | Bin 896 -> 896 bytes main.py | 512 ++++++++++++++++---------------- path_search_algorthms/a_star.py | 155 +++++----- 6 files changed, 677 insertions(+), 657 deletions(-) diff --git a/decision_tree/tree_as_txt.txt b/decision_tree/tree_as_txt.txt index c9fff86..b13e1ac 100644 --- a/decision_tree/tree_as_txt.txt +++ b/decision_tree/tree_as_txt.txt @@ -1,91 +1,91 @@ -|--- feature_2 <= 3.50 -| |--- feature_4 <= 3.50 -| | |--- feature_0 <= 1.50 -| | | |--- class: 0 -| | |--- feature_0 > 1.50 -| | | |--- feature_3 <= 3.50 -| | | | |--- feature_2 <= 2.50 -| | | | | |--- class: 1 -| | | | |--- feature_2 > 2.50 -| | | | | |--- feature_4 <= 2.50 -| | | | | | |--- class: 1 -| | | | | |--- feature_4 > 2.50 -| | | | | | |--- class: 0 -| | | |--- feature_3 > 3.50 -| | | | |--- feature_3 <= 4.50 -| | | | | |--- feature_1 <= 2.50 -| | | | | | |--- feature_0 <= 2.50 -| | | | | | | |--- feature_1 <= 1.50 -| | | | | | | | |--- feature_4 <= 2.50 -| | | | | | | | | |--- class: 1 -| | | | | | | | |--- feature_4 > 2.50 -| | | | | | | | | |--- feature_2 <= 2.00 -| | | | | | | | | | |--- class: 1 -| | | | | | | | | |--- feature_2 > 2.00 -| | | | | | | | | | |--- class: 0 -| | | | | | | |--- feature_1 > 1.50 -| | | | | | | | |--- class: 0 -| | | | | | |--- feature_0 > 2.50 -| | | | | | | |--- feature_4 <= 2.50 -| | | | | | | | |--- class: 1 -| | | | | | | |--- feature_4 > 2.50 -| | | | | | | | |--- feature_2 <= 2.50 -| | | | | | | | | |--- class: 1 -| | | | | | | | |--- feature_2 > 2.50 -| | | | | | | | | |--- class: 0 -| | | | | |--- feature_1 > 2.50 -| | | | | | |--- feature_0 <= 3.50 -| | | | | | | |--- class: 0 -| | | | | | |--- feature_0 > 3.50 -| | | | | | | |--- feature_1 <= 3.50 -| | | | | | | | |--- feature_2 <= 2.50 -| | | | | | | | | |--- class: 1 -| | | | | | | | |--- feature_2 > 2.50 -| | | | | | | | | |--- feature_4 <= 2.00 -| | | | | | | | | | |--- class: 1 -| | | | | | | | | |--- feature_4 > 2.00 -| | | | | | | | | | |--- class: 0 -| | | | | | | |--- feature_1 > 3.50 -| | | | | | | | |--- class: 0 -| | | | |--- feature_3 > 4.50 -| | | | | |--- class: 0 -| |--- feature_4 > 3.50 -| | |--- feature_2 <= 1.50 -| | | |--- feature_4 <= 4.50 -| | | | |--- feature_3 <= 3.50 -| | | | | |--- feature_0 <= 1.50 -| | | | | | |--- class: 0 -| | | | | |--- feature_0 > 1.50 -| | | | | | |--- class: 1 -| | | | |--- feature_3 > 3.50 -| | | | | |--- feature_1 <= 2.50 -| | | | | | |--- feature_0 <= 2.50 -| | | | | | | |--- class: 0 -| | | | | | |--- feature_0 > 2.50 -| | | | | | | |--- feature_3 <= 4.50 -| | | | | | | | |--- class: 1 -| | | | | | | |--- feature_3 > 4.50 -| | | | | | | | |--- class: 0 -| | | | | |--- feature_1 > 2.50 -| | | | | | |--- class: 0 -| | | |--- feature_4 > 4.50 -| | | | |--- class: 0 -| | |--- feature_2 > 1.50 -| | | |--- class: 0 -|--- feature_2 > 3.50 -| |--- feature_4 <= 1.50 -| | |--- feature_1 <= 1.50 -| | | |--- feature_2 <= 4.50 -| | | | |--- feature_0 <= 1.50 -| | | | | |--- class: 0 -| | | | |--- feature_0 > 1.50 -| | | | | |--- feature_3 <= 4.50 -| | | | | | |--- class: 1 -| | | | | |--- feature_3 > 4.50 -| | | | | | |--- class: 0 -| | | |--- feature_2 > 4.50 -| | | | |--- class: 0 -| | |--- feature_1 > 1.50 -| | | |--- class: 0 -| |--- feature_4 > 1.50 -| | |--- class: 0 +|--- feature_2 <= 3.50 +| |--- feature_4 <= 3.50 +| | |--- feature_0 <= 1.50 +| | | |--- class: 0 +| | |--- feature_0 > 1.50 +| | | |--- feature_3 <= 3.50 +| | | | |--- feature_2 <= 2.50 +| | | | | |--- class: 1 +| | | | |--- feature_2 > 2.50 +| | | | | |--- feature_4 <= 2.50 +| | | | | | |--- class: 1 +| | | | | |--- feature_4 > 2.50 +| | | | | | |--- class: 0 +| | | |--- feature_3 > 3.50 +| | | | |--- feature_3 <= 4.50 +| | | | | |--- feature_1 <= 2.50 +| | | | | | |--- feature_0 <= 2.50 +| | | | | | | |--- feature_1 <= 1.50 +| | | | | | | | |--- feature_4 <= 2.50 +| | | | | | | | | |--- class: 1 +| | | | | | | | |--- feature_4 > 2.50 +| | | | | | | | | |--- feature_2 <= 2.00 +| | | | | | | | | | |--- class: 1 +| | | | | | | | | |--- feature_2 > 2.00 +| | | | | | | | | | |--- class: 0 +| | | | | | | |--- feature_1 > 1.50 +| | | | | | | | |--- class: 0 +| | | | | | |--- feature_0 > 2.50 +| | | | | | | |--- feature_4 <= 2.50 +| | | | | | | | |--- class: 1 +| | | | | | | |--- feature_4 > 2.50 +| | | | | | | | |--- feature_2 <= 2.50 +| | | | | | | | | |--- class: 1 +| | | | | | | | |--- feature_2 > 2.50 +| | | | | | | | | |--- class: 0 +| | | | | |--- feature_1 > 2.50 +| | | | | | |--- feature_1 <= 3.50 +| | | | | | | |--- feature_0 <= 3.50 +| | | | | | | | |--- class: 0 +| | | | | | | |--- feature_0 > 3.50 +| | | | | | | | |--- feature_4 <= 2.50 +| | | | | | | | | |--- class: 1 +| | | | | | | | |--- feature_4 > 2.50 +| | | | | | | | | |--- feature_2 <= 2.00 +| | | | | | | | | | |--- class: 1 +| | | | | | | | | |--- feature_2 > 2.00 +| | | | | | | | | | |--- class: 0 +| | | | | | |--- feature_1 > 3.50 +| | | | | | | |--- class: 0 +| | | | |--- feature_3 > 4.50 +| | | | | |--- class: 0 +| |--- feature_4 > 3.50 +| | |--- feature_2 <= 1.50 +| | | |--- feature_4 <= 4.50 +| | | | |--- feature_3 <= 3.50 +| | | | | |--- feature_0 <= 1.50 +| | | | | | |--- class: 0 +| | | | | |--- feature_0 > 1.50 +| | | | | | |--- class: 1 +| | | | |--- feature_3 > 3.50 +| | | | | |--- feature_1 <= 2.50 +| | | | | | |--- feature_3 <= 4.50 +| | | | | | | |--- feature_0 <= 2.50 +| | | | | | | | |--- class: 0 +| | | | | | | |--- feature_0 > 2.50 +| | | | | | | | |--- class: 1 +| | | | | | |--- feature_3 > 4.50 +| | | | | | | |--- class: 0 +| | | | | |--- feature_1 > 2.50 +| | | | | | |--- class: 0 +| | | |--- feature_4 > 4.50 +| | | | |--- class: 0 +| | |--- feature_2 > 1.50 +| | | |--- class: 0 +|--- feature_2 > 3.50 +| |--- feature_1 <= 1.50 +| | |--- feature_4 <= 1.50 +| | | |--- feature_2 <= 4.50 +| | | | |--- feature_3 <= 4.50 +| | | | | |--- feature_0 <= 1.50 +| | | | | | |--- class: 0 +| | | | | |--- feature_0 > 1.50 +| | | | | | |--- class: 1 +| | | | |--- feature_3 > 4.50 +| | | | | |--- class: 0 +| | | |--- feature_2 > 4.50 +| | | | |--- class: 0 +| | |--- feature_4 > 1.50 +| | | |--- class: 0 +| |--- feature_1 > 1.50 +| | |--- class: 0 diff --git a/decision_tree/tree_model b/decision_tree/tree_model index 77a527a912bdd51ed326dcf8b75f66359d046487..780ebcf00d66a447a2b7fa93647647d82535ec2a 100644 GIT binary patch delta 571 zcmZqI-lEOYz%tcrBa0}bs8DWZUVLV5L1|HDNo9O-K~84L6u-$5jF#NodGTqfi6x~) zsl}6h7$OD+p7E?Mq+NT6f z(eP%@(Dw85^ZE}2V8WZBWJ;2^1W=`KM!2^EkoE)W)Bw`{K)ylSlu~aCZ$@tcpsEbr z&HtF2Stozwl$bn|Q$kRh0Rm*8G{fXyoa&PUSv4d%VIp8!$w3y%mzylbp3W%`;?#jk>rS@fm7RQ?chzJ=PK(Kfd=nTMCo}PzGqOy! z;!mF}C?H|6L$398;EsFtTu>blO2xq(%C|rfhjD(`PY&dDm~6>su{l$KnNc1sT!Eft zYKMh=IMC1Cf-4y(y9f&~DLG7@CnPqxM#zKFdh$}?`IBQrI48%7Z~(Eu delta 457 zcmZ9I&nv@m7{~Yd{>Z*t^ZnR-+cf*ZrhRQTqhx4N%CE1~2BU@DI3fb5TAA6wl##_4In`>3Lr#DhZ{m)ErleLC{SySS7o1D~rG> zl}QX$Y0B^GT;nBfGCvElkVQ5*Yh&#!!eT6rcWI#Iuh0JaC`RS=#2AZNwk^)a1?_?p zf>dylMXS=P^4W8{XYs(NCKz_;6Fn XH-bSUN5ZHY0f*X?N~d~xv5@)#ezAgM diff --git a/genetic_algorithm/TSP.py b/genetic_algorithm/TSP.py index d540e77..199979d 100644 --- a/genetic_algorithm/TSP.py +++ b/genetic_algorithm/TSP.py @@ -1,235 +1,250 @@ -import numpy as np, random, operator, pandas as pd, matplotlib.pyplot as plt -from path_search_algorthms.a_star import get_cost -from decision_tree import decisionTree -from settings import * -import math - -# klasa tworząca miasta czy też śmietniki -class City: - def __init__(self, x, y): - self.x = x - self.y = y - #self.array = array - # self.dist = distance - - #dystans to d = sqrt(x^2 + y^2) - def distance(self, city): - - #getting distance by astar gives wrong final distance (intial = final) - #return get_cost(math.floor(self.x / TILESIZE), math.floor(self.y / TILESIZE), math.floor(city.x / TILESIZE), math.floor(city.y / TILESIZE), self.array) - xDis = abs(self.x - city.x) - yDis = abs(self.y - city.y) - distance = np.sqrt((xDis ** 2) + (yDis ** 2)) - return distance - - def __repr__(self): - return "(" + str(self.x) + "," + str(self.y) + ")" - - -# fitness function, -# inverse of route distance -# we want to minimize distance so the larger the fitness the better -class Fitness: - def __init__(self, route): - self.route = route - self.distance = 0 - self.fitness = 0.0 - - def routeDistance(self): - if self.distance == 0: - pathDistance = 0 - for i in range(0, len(self.route)): - fromCity = self.route[i] - toCity = None - if i + 1 < len(self.route): # for returning to point 0? - toCity = self.route[i + 1] - else: - toCity = self.route[0] - pathDistance += fromCity.distance(toCity) - self.distance = pathDistance - return self.distance - - def routeFitness(self): - if self.fitness == 0: - self.fitness = 1 / float(self.routeDistance()) - return self.fitness - - -# creating one individual - single route from city to city (trash to trash) -def createRoute(cityList): - route = random.sample(cityList, len(cityList)) - return route - - -# creating initial population of given size -def initialPopulation(popSize, cityList): - population = [] - - for i in range(0, popSize): - population.append(createRoute(cityList)) - return population - - -# ranking fitness of given route, output is ordered list with route id and its fitness score -def rankRoutes(population): - fitnessResults = {} - for i in range(0, len(population)): - fitnessResults[i] = Fitness(population[i]).routeFitness() - return sorted(fitnessResults.items(), key=operator.itemgetter(1), reverse=True) - - -# selecting "mating pool" -# we are using here "Firness proportionate selection", its fitness-weighted probability of being selected -# moreover we are using elitism to ensure that the best of the best will preserve - -def selection(popRanked, eliteSize): - selectionResults = [] - # roulette wheel - df = pd.DataFrame(np.array(popRanked), columns=["Index", "Fitness"]) - df['cum_sum'] = df.Fitness.cumsum() - df['cum_perc'] = 100 * df.cum_sum / df.Fitness.sum() - - for i in range(0, eliteSize): # elitism - selectionResults.append(popRanked[i][0]) - for i in range(0, - len(popRanked) - eliteSize): # comparing randomly drawn number to weights for selection for mating pool - pick = 100 * random.random() - for i in range(0, len(popRanked)): - if pick <= df.iat[i, 3]: - selectionResults.append(popRanked[i][0]) - break - return selectionResults # returns list of route IDs - - -# creating mating pool from list of routes IDs from "selection" -def matingPool(population, selectionResults): - matingpool = [] - for i in range(0, len(selectionResults)): - index = selectionResults[i] - matingpool.append(population[index]) - return matingpool - - -# creating new generation -# ordered crossover bc we need to include all locations exactly one time -# randomly selecting a subset of the first parent string and then filling the remainder of route -# with genes from the second parent in the order in which they appear, without duplicating any genes from the first parent -def breed(parent1, parent2): - child = [] - childP1 = [] - childP2 = [] - - geneA = int(random.random() * len(parent1)) - geneB = int(random.random() * len(parent1)) - - startGene = min(geneA, geneB) - endGene = max(geneA, geneB) - - for i in range(startGene, endGene): # ordered crossover - childP1.append(parent1[i]) - - childP2 = [item for item in parent2 if item not in childP1] - - child = childP1 + childP2 - return child - - -# creating whole offspring population -def breedPopulation(matingpool, eliteSize): - children = [] - length = len(matingpool) - eliteSize - pool = random.sample(matingpool, len(matingpool)) - - # using elitism to retain best genes (routes) - for i in range(0, eliteSize): - children.append(matingpool[i]) - - # filling rest generation - for i in range(0, length): - child = breed(pool[i], pool[len(matingpool) - i - 1]) - children.append(child) - return children - - -# using swap mutation -# with specified low prob we swap two cities in route -def mutate(individual, mutationRate): - for swapped in range(len(individual)): - if (random.random() < mutationRate): - swapWith = int(random.random() * len(individual)) - - city1 = individual[swapped] - city2 = individual[swapWith] - - individual[swapped] = city2 - individual[swapWith] = city1 - return individual - - -# extending mutate function to run through new pop -def mutatePopulation(population, mutationRate): - mutatedPop = [] - - for ind in range(0, len(population)): - mutatedInd = mutate(population[ind], mutationRate) - mutatedPop.append(mutatedInd) - return mutatedPop - - -# creating new generation -def nextGeneration(currentGen, eliteSize, mutationRate): - popRanked = rankRoutes(currentGen) # rank routes in current gen - selectionResults = selection(popRanked, eliteSize) # determining potential parents - matingpool = matingPool(currentGen, selectionResults) # creating mating pool - children = breedPopulation(matingpool, eliteSize) # creating new gen - nextGeneration = mutatePopulation(children, mutationRate) # applying mutation to new gen - return nextGeneration - - -def geneticAlgorithm(population, popSize, eliteSize, mutationRate, generations): - pop = initialPopulation(popSize, population) - print("Initial distance: " + str(1 / rankRoutes(pop)[0][1])) - - for i in range(0, generations): - pop = nextGeneration(pop, eliteSize, mutationRate) - - print("Final distance: " + str(1 / rankRoutes(pop)[0][1])) - bestRouteIndex = rankRoutes(pop)[0][0] - bestRoute = pop[bestRouteIndex] - return bestRoute - - -# tutaj ma być lista kordów potencjalnych śmietników z drzewa decyzyjnego - -cityList = [] - - -# for i in range(0,25): -# cityList.append(City(x=int(random.random() * 200), y=int(random.random() * 200))) - -# geneticAlgorithm(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) - - -# plotting the progress - -def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generations): - pop = initialPopulation(popSize, population) - progress = [] - progress.append(1 / rankRoutes(pop)[0][1]) - print("Initial distance: " + str(1 / rankRoutes(pop)[0][1])) - - for i in range(0, generations): - pop = nextGeneration(pop, eliteSize, mutationRate) - progress.append(1 / rankRoutes(pop)[0][1]) - - print("Final distance: " + str(1 / rankRoutes(pop)[0][1])) - bestRouteIndex = rankRoutes(pop)[0][0] - bestRoute = pop[bestRouteIndex] - - plt.plot(progress) - plt.ylabel('Distance') - plt.xlabel('Generation') - plt.show() - return bestRoute - -# geneticAlgorithmPlot(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) +import numpy as np, random, operator, pandas as pd, matplotlib.pyplot as plt +from path_search_algorthms.a_star import get_cost +from decision_tree import decisionTree +from settings import * +import math + +# klasa tworząca miasta czy też śmietniki +class City: + def __init__(self, x, y, array): + self.x = x + self.y = y + self.array = array + # self.dist = distance + + + + #dystans to d = sqrt(x^2 + y^2) + def distance(self, city): + + #getting distance by astar gives wrong final distance (intial = final) + return get_cost(math.floor(self.x / TILESIZE), math.floor(self.y / TILESIZE), math.floor(city.x / TILESIZE), math.floor(city.y / TILESIZE), self.array) + # xDis = abs(self.x - city.x) + # yDis = abs(self.y - city.y) + # distance = np.sqrt((xDis ** 2) + (yDis ** 2)) + # return distance + + def __repr__(self): + return "(" + str(self.x) + "," + str(self.y) + ")" + + +# fitness function, +# inverse of route distance +# we want to minimize distance so the larger the fitness the better +class Fitness: + def __init__(self, route, distanceArray): + self.route = route + self.distance = 0 + self.fitness = 0.0 + self.distanceArray = distanceArray + + def routeDistance(self): + if self.distance == 0: + pathDistance = 0 + for i in range(0, len(self.route)): + fromCity = self.route[i] + toCity = None + if i + 1 < len(self.route): # for returning to point 0? + toCity = self.route[i + 1] + else: + toCity = self.route[0] + # pathDistance += fromCity.distance(toCity) + pathDistance += self.distanceArray[str(fromCity.x)+" "+str(fromCity.y)+" "+str(toCity.x)+" "+str(toCity.y)] + self.distance = pathDistance + return self.distance + + def routeFitness(self): + if self.fitness == 0: + self.fitness = 1 / float(self.routeDistance()) + return self.fitness + + +# creating one individual - single route from city to city (trash to trash) +def createRoute(cityList): + route = random.sample(cityList, len(cityList)) + return route + + +# creating initial population of given size +def initialPopulation(popSize, cityList): + population = [] + + for i in range(0, popSize): + population.append(createRoute(cityList)) + return population + + +# ranking fitness of given route, output is ordered list with route id and its fitness score +def rankRoutes(population, distanceArray): + fitnessResults = {} + for i in range(0, len(population)): + fitnessResults[i] = Fitness(population[i], distanceArray).routeFitness() + return sorted(fitnessResults.items(), key=operator.itemgetter(1), reverse=True) + + +# selecting "mating pool" +# we are using here "Firness proportionate selection", its fitness-weighted probability of being selected +# moreover we are using elitism to ensure that the best of the best will preserve + +def selection(popRanked, eliteSize): + selectionResults = [] + # roulette wheel + df = pd.DataFrame(np.array(popRanked), columns=["Index", "Fitness"]) + df['cum_sum'] = df.Fitness.cumsum() + df['cum_perc'] = 100 * df.cum_sum / df.Fitness.sum() + + for i in range(0, eliteSize): # elitism + selectionResults.append(popRanked[i][0]) + for i in range(0, + len(popRanked) - eliteSize): # comparing randomly drawn number to weights for selection for mating pool + pick = 100 * random.random() + for i in range(0, len(popRanked)): + if pick <= df.iat[i, 3]: + selectionResults.append(popRanked[i][0]) + break + return selectionResults # returns list of route IDs + + +# creating mating pool from list of routes IDs from "selection" +def matingPool(population, selectionResults): + matingpool = [] + for i in range(0, len(selectionResults)): + index = selectionResults[i] + matingpool.append(population[index]) + return matingpool + + +# creating new generation +# ordered crossover bc we need to include all locations exactly one time +# randomly selecting a subset of the first parent string and then filling the remainder of route +# with genes from the second parent in the order in which they appear, without duplicating any genes from the first parent +def breed(parent1, parent2): + child = [] + childP1 = [] + childP2 = [] + + geneA = int(random.random() * len(parent1)) + geneB = int(random.random() * len(parent1)) + + startGene = min(geneA, geneB) + endGene = max(geneA, geneB) + + for i in range(startGene, endGene): # ordered crossover + childP1.append(parent1[i]) + + childP2 = [item for item in parent2 if item not in childP1] + + child = childP1 + childP2 + return child + + +# creating whole offspring population +def breedPopulation(matingpool, eliteSize): + children = [] + length = len(matingpool) - eliteSize + pool = random.sample(matingpool, len(matingpool)) + + # using elitism to retain best genes (routes) + for i in range(0, eliteSize): + children.append(matingpool[i]) + + # filling rest generation + for i in range(0, length): + child = breed(pool[i], pool[len(matingpool) - i - 1]) + children.append(child) + return children + + +# using swap mutation +# with specified low prob we swap two cities in route +def mutate(individual, mutationRate): + for swapped in range(len(individual)): + if (random.random() < mutationRate): + swapWith = int(random.random() * len(individual)) + + city1 = individual[swapped] + city2 = individual[swapWith] + + individual[swapped] = city2 + individual[swapWith] = city1 + return individual + + +# extending mutate function to run through new pop +def mutatePopulation(population, mutationRate): + mutatedPop = [] + + for ind in range(0, len(population)): + mutatedInd = mutate(population[ind], mutationRate) + mutatedPop.append(mutatedInd) + return mutatedPop + + +# creating new generation +def nextGeneration(currentGen, eliteSize, mutationRate, distanceArray): + popRanked = rankRoutes(currentGen, distanceArray) # rank routes in current gen + selectionResults = selection(popRanked, eliteSize) # determining potential parents + matingpool = matingPool(currentGen, selectionResults) # creating mating pool + children = breedPopulation(matingpool, eliteSize) # creating new gen + nextGeneration = mutatePopulation(children, mutationRate) # applying mutation to new gen + return nextGeneration + + +def geneticAlgorithm(population, popSize, eliteSize, mutationRate, generations, distanceArray): + pop = initialPopulation(popSize, population) + print("Initial distance: " + str(1 / rankRoutes(pop, distanceArray)[0][1])) + + for i in range(0, generations): + pop = nextGeneration(pop, eliteSize, mutationRate, distanceArray) + + print("Final distance: " + str(1 / rankRoutes(pop, distanceArray)[0][1])) + bestRouteIndex = rankRoutes(pop, distanceArray)[0][0] + bestRoute = pop[bestRouteIndex] + return bestRoute + + +# tutaj ma być lista kordów potencjalnych śmietników z drzewa decyzyjnego + +cityList = [] + + +# for i in range(0,25): +# cityList.append(City(x=int(random.random() * 200), y=int(random.random() * 200))) + +# geneticAlgorithm(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) + + +# plotting the progress + +def distanceFromCityToCity(cityFrom, city, array): + return get_cost(math.floor(cityFrom.x / TILESIZE), math.floor(cityFrom.y / TILESIZE), math.floor(city.x / TILESIZE), math.floor(city.y / TILESIZE), array) + +def geneticAlgorithmPlot(population, popSize, eliteSize, mutationRate, generations, array): + a_star_distances = {} + for city in population: + for target in population: + if city == target: + continue + else: + a_star_distances[str(city.x)+" "+str(city.y)+" "+str(target.x)+" "+str(target.y)] = distanceFromCityToCity(city, target, array) + + pop = initialPopulation(popSize, population) + progress = [] + progress.append(1 / rankRoutes(pop, a_star_distances)[0][1]) + print("Initial distance: " + str(1 / rankRoutes(pop, a_star_distances)[0][1])) + + for i in range(0, generations): + pop = nextGeneration(pop, eliteSize, mutationRate, a_star_distances) + progress.append(1 / rankRoutes(pop, a_star_distances)[0][1]) + + print("Final distance: " + str(1 / rankRoutes(pop, a_star_distances)[0][1])) + bestRouteIndex = rankRoutes(pop, a_star_distances)[0][0] + bestRoute = pop[bestRouteIndex] + + plt.plot(progress) + plt.ylabel('Distance') + plt.xlabel('Generation') + plt.show() + return bestRoute + +# geneticAlgorithmPlot(population=cityList, popSize=100, eliteSize=20, mutationRate=0.01, generations=1000) diff --git a/last_map.nparr b/last_map.nparr index b56b446d59aef3da1f61f3fc2970963a31e1c82a..804211f1645843921bbc20ae010aa3ce23ff832c 100644 GIT binary patch delta 145 zcmZo*Z(yI$GFgOCWAXz=mdPg=B_@6_n0QA3$dj2Y!>BM>f!P4a<^c%>0I5F`lNT@w zOgzH@&(LY+^9=$TT)HVPY^E brXIvc7X!%=YZtNVNHG(nmRtaH4>An^e$X4r diff --git a/main.py b/main.py index 136f914..e74759e 100644 --- a/main.py +++ b/main.py @@ -1,256 +1,258 @@ -import os -import sys -from random import randint -import math - -import pygame as pg -import numpy - -from game_objects.player import Player -from game_objects.aiPlayer import aiPlayer -from game_objects.trash import Trash - -from map import map -from map import map_utils -from settings import * -from path_search_algorthms import bfs -from path_search_algorthms import a_star_controller, a_star -from decision_tree import decisionTree -from NeuralNetwork import prediction -from game_objects.trash import Trash -from genetic_algorithm import TSP -from game_objects import aiPlayer -import itertools - - -def getTree(): - tree = decisionTree.tree() - decisionTree.tree_as_txt(tree) - # decisionTree.tree_to_png(tree) - decisionTree.tree_to_structure(tree) - drzewo = decisionTree.tree_from_structure('./decision_tree/tree_model') - # print("Dla losowych danych predykcja czy wziąć kosz to: ") - # dec = decisionTree.decision(drzewo, *(4,1,1,1)) - # print('---') - # print(f"decision is{dec}") - # print('---') - - return drzewo - - -class Game(): - - def __init__(self): - pg.init() - pg.font.init() - self.clock = pg.time.Clock() - self.dt = self.clock.tick(FPS) / 333.0 - self.screen = pg.display.set_mode((WIDTH, HEIGHT)) - pg.display.set_caption("Trashmaster") - self.load_data() - self.init_game() - # because dont work without data.txt - # self.init_bfs() - # self.init_a_star() - self.t = aiPlayer.aiPlayer(self.player, game=self) - - def init_game(self): - # initialize all variables and do all the setup for a new game - - self.text_display = '' - - # sprite groups and map array for calculations - (self.roadTiles, self.wallTiles, self.trashbinTiles), self.mapArray = map.get_tiles() - - # save current map - file = open('last_map.nparr', 'wb') - numpy.save(file, self.mapArray, allow_pickle=True) - file.close - - self.trashDisplay = pg.sprite.Group() - self.agentSprites = pg.sprite.Group() - # player obj - self.player = Player(self, 32, 32) - # camera obj - self.camera = map_utils.Camera(MAP_WIDTH_PX, MAP_HEIGHT_PX) - - # other - self.debug_mode = False - - def init_bfs(self): - start_node = (0, 0) - target_node = (18, 18) - find_path = bfs.BreadthSearchAlgorithm(start_node, target_node, self.mapArray) - path = find_path.bfs() - # print(path) - realPath = [] - nextNode = target_node - for i in range(len(path) - 1, 0, -1): - node = path[i] - if node[0] == nextNode: - realPath.insert(0, node[0]) - nextNode = node[1] - print(realPath) - - def init_decision_tree(self): - # logika pracy z drzewem - self.positive_decision = [] - self.negative_decision = [] - - for i in self.trashbinTiles: - atrrs_container = i.get_attributes() - x, y = i.get_coords() - dec = decisionTree.decision(getTree(), *atrrs_container) - # if dec[0] == 1: - self.positive_decision.append(i) # zmiana po to by losowało wszystkie smietniki a nie poprawne tylko, zeby ladniej bylo widac algorytm genetyczny - # else: - # self.negative_decision.append(i) - - print('positive actions') - print(len(self.positive_decision)) - # print('positive actions') - # for i in self.positive_actions: - # print('----') - # print(i) - # print('----') - self.draw() - def decsion_tree_move(self): - - for i in range(0,len(self.positive_decision)): - # print(i.get_coords()) - print('action') - - - # trash_x, trash_y = i.get_coords() - - # for ii in self.tsp_list: - temp_tsp = str(self.tsp_list[i]) - temp_tsp = temp_tsp.strip("()") - temp_tsp = temp_tsp.split(",") - trash_x = int(temp_tsp[0]) - trash_y = int(temp_tsp[1]) - - - print(trash_x, trash_y) - - action = a_star_controller.get_actions_for_target_coords(trash_x, trash_y, self) - - print(action) - self.t.startAiController(action) - - print('') - print('--rozpoczecie sortowania smietnika--') - dir = "./resources/trash_dataset/test/all" - files = os.listdir(dir) - for j in range(0, 10): - random = randint(0, 48) - file = files[random] - result = prediction.getPrediction(dir + '/' + file, 'trained_nn_20.pth') - img = pg.image.load(dir + '/' + file).convert_alpha() - img = pg.transform.scale(img, (128, 128)) - trash = Trash(img, 0, 0, 128, 128) - self.trashDisplay.add(trash) - self.text_display = result - self.draw() - # print(result + ' ' + file) - pg.time.wait(100) - self.text_display = '' - self.draw() - - # print(self.positive_actions[0]) - - # self.t.startAiController(self.positive_actions[0]) - def init_TSP(self): - - city_list =[] - - for i in self.positive_decision: - trash_x, trash_y = i.get_coords() - # city_list.append(TSP.City(x=int(trash_x), y=int(trash_y), array=self.mapArray)) - city_list.append(TSP.City(x=int(trash_x), y=int(trash_y))) - - - # dist = a_star.get_cost - self.tsp_list = TSP.geneticAlgorithmPlot(population=city_list, popSize=100, eliteSize=20, mutationRate=0.01, generations=300) - print(self.tsp_list) - - def load_data(self): - game_folder = os.path.dirname(__file__) - img_folder = os.path.join(game_folder, 'resources/textures') - - self.player_img = pg.image.load(os.path.join(img_folder, PLAYER_IMG)).convert_alpha() - self.player_img = pg.transform.scale(self.player_img, (PLAYER_WIDTH, PLAYER_HEIGHT)) - - def run(self): - # game loop - set self.playing = False to end the game - self.playing = True - self.init_decision_tree() - self.init_TSP() - self.decsion_tree_move() - - while self.playing: - self.dt = self.clock.tick(FPS) / 1000.0 - self.events() - self.update() - self.draw() - - def quit(self): - pg.quit() - sys.exit() - - def update(self): - # update portion of the game loop - self.agentSprites.update() - self.camera.update(self.player) - # pygame.display.update() - - def draw(self): - # display fps as window title - pg.display.set_caption("{:.2f}".format(self.clock.get_fps())) - - # rerender map - map.render_tiles(self.roadTiles, self.screen, self.camera) - map.render_tiles(self.wallTiles, self.screen, self.camera, self.debug_mode) - map.render_tiles(self.trashbinTiles, self.screen, self.camera) - map.render_tiles(self.trashDisplay, self.screen, self.camera) - - # draw text - text_surface = pg.font.SysFont('Comic Sans MS', 30).render(self.text_display, False, (255, 255, 255)) - self.screen.blit(text_surface, (0, 128)) - - # rerender additional sprites - for sprite in self.agentSprites: - self.screen.blit(sprite.image, self.camera.apply(sprite)) - if self.debug_mode: - pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.hit_rect), 1) - - # self.player.hud_group.draw(self.screen) - # finally update screen - pg.display.flip() - - def events(self): - for event in pg.event.get(): - if event.type == pg.QUIT: - self.quit() - if event.type == pg.KEYDOWN: - if event.key == pg.K_ESCAPE: - self.quit() - if event.key == pg.K_h: - self.debug_mode = not self.debug_mode - if event.type == pg.MOUSEBUTTONUP: - pos = pg.mouse.get_pos() - offset_x, offset_y = self.camera.offset() - clicked_coords = [math.floor(pos[0] / TILESIZE) - offset_x, math.floor(pos[1] / TILESIZE) - offset_y] - actions = a_star_controller.get_actions_by_coords(clicked_coords[0], clicked_coords[1], self) - - if (actions != None): - self.t.startAiController(actions) - - -# create the game object - -if __name__ == "__main__": - g = Game() - - g.run() +import os +import sys +from random import randint +import math + +import pygame as pg +import numpy + +from game_objects.player import Player +from game_objects.aiPlayer import aiPlayer +from game_objects.trash import Trash + +from map import map +from map import map_utils +from settings import * +from path_search_algorthms import bfs +from path_search_algorthms import a_star_controller, a_star +from decision_tree import decisionTree +from NeuralNetwork import prediction +from game_objects.trash import Trash +from genetic_algorithm import TSP +from game_objects import aiPlayer +import itertools + + +def getTree(): + tree = decisionTree.tree() + decisionTree.tree_as_txt(tree) + # decisionTree.tree_to_png(tree) + decisionTree.tree_to_structure(tree) + drzewo = decisionTree.tree_from_structure('./decision_tree/tree_model') + # print("Dla losowych danych predykcja czy wziąć kosz to: ") + # dec = decisionTree.decision(drzewo, *(4,1,1,1)) + # print('---') + # print(f"decision is{dec}") + # print('---') + + return drzewo + + +class Game(): + + def __init__(self): + pg.init() + pg.font.init() + self.clock = pg.time.Clock() + self.dt = self.clock.tick(FPS) / 333.0 + self.screen = pg.display.set_mode((WIDTH, HEIGHT)) + pg.display.set_caption("Trashmaster") + self.load_data() + self.init_game() + # because dont work without data.txt + # self.init_bfs() + # self.init_a_star() + self.t = aiPlayer.aiPlayer(self.player, game=self) + + def init_game(self): + # initialize all variables and do all the setup for a new game + + self.text_display = '' + + # sprite groups and map array for calculations + (self.roadTiles, self.wallTiles, self.trashbinTiles), self.mapArray = map.get_tiles() + + # save current map + file = open('last_map.nparr', 'wb') + numpy.save(file, self.mapArray, allow_pickle=True) + file.close + + self.trashDisplay = pg.sprite.Group() + self.agentSprites = pg.sprite.Group() + # player obj + self.player = Player(self, 32, 32) + # camera obj + self.camera = map_utils.Camera(MAP_WIDTH_PX, MAP_HEIGHT_PX) + + # other + self.debug_mode = False + + def init_bfs(self): + start_node = (0, 0) + target_node = (18, 18) + find_path = bfs.BreadthSearchAlgorithm(start_node, target_node, self.mapArray) + path = find_path.bfs() + # print(path) + realPath = [] + nextNode = target_node + for i in range(len(path) - 1, 0, -1): + node = path[i] + if node[0] == nextNode: + realPath.insert(0, node[0]) + nextNode = node[1] + print(realPath) + + def init_decision_tree(self): + # logika pracy z drzewem + self.positive_decision = [] + self.negative_decision = [] + + for i in self.trashbinTiles: + atrrs_container = i.get_attributes() + x, y = i.get_coords() + dec = decisionTree.decision(getTree(), *atrrs_container) + # if dec[0] == 1: + self.positive_decision.append(i) # zmiana po to by losowało wszystkie smietniki a nie poprawne tylko, zeby ladniej bylo widac algorytm genetyczny + # else: + # self.negative_decision.append(i) + + print('positive actions') + print(len(self.positive_decision)) + # print('positive actions') + # for i in self.positive_actions: + # print('----') + # print(i) + # print('----') + self.draw() + def decsion_tree_move(self): + + for i in range(0,len(self.positive_decision)): + # print(i.get_coords()) + print('action') + + + # trash_x, trash_y = i.get_coords() + + # for ii in self.tsp_list: + temp_tsp = str(self.tsp_list[i]) + temp_tsp = temp_tsp.strip("()") + temp_tsp = temp_tsp.split(",") + trash_x = int(temp_tsp[0]) + trash_y = int(temp_tsp[1]) + + + print(trash_x, trash_y) + + action = a_star_controller.get_actions_for_target_coords(trash_x, trash_y, self) + + print(action) + self.t.startAiController(action) + + print('') + print('--rozpoczecie sortowania smietnika--') + dir = "./resources/trash_dataset/test/all" + files = os.listdir(dir) + for j in range(0, 10): + random = randint(0, 48) + file = files[random] + result = prediction.getPrediction(dir + '/' + file, 'trained_nn_20.pth') + img = pg.image.load(dir + '/' + file).convert_alpha() + img = pg.transform.scale(img, (128, 128)) + offset_x, offset_y = self.camera.offset() + trash = Trash(img, math.floor(-offset_x * TILESIZE), math.floor(-offset_y * TILESIZE), 128, 128) + self.trashDisplay.empty() + self.trashDisplay.add(trash) + self.text_display = result + self.draw() + pg.time.wait(100) + self.text_display = '' + self.trashDisplay.empty() + self.draw() + + # print(self.positive_actions[0]) + + # self.t.startAiController(self.positive_actions[0]) + def init_TSP(self): + + city_list =[] + + for i in self.positive_decision: + trash_x, trash_y = i.get_coords() + # city_list.append(TSP.City(x=int(trash_x), y=int(trash_y), array=self.mapArray)) + city_list.append(TSP.City(x=trash_x, y=trash_y, array=self.mapArray)) + + + # dist = a_star.get_cost + self.tsp_list = TSP.geneticAlgorithmPlot(population=city_list, popSize=100, eliteSize=20, mutationRate=0.01, generations=300, array=self.mapArray) + print(self.tsp_list) + + def load_data(self): + game_folder = os.path.dirname(__file__) + img_folder = os.path.join(game_folder, 'resources/textures') + + self.player_img = pg.image.load(os.path.join(img_folder, PLAYER_IMG)).convert_alpha() + self.player_img = pg.transform.scale(self.player_img, (PLAYER_WIDTH, PLAYER_HEIGHT)) + + def run(self): + # game loop - set self.playing = False to end the game + self.playing = True + self.init_decision_tree() + self.init_TSP() + self.decsion_tree_move() + + while self.playing: + self.dt = self.clock.tick(FPS) / 1000.0 + self.events() + self.update() + self.draw() + + def quit(self): + pg.quit() + sys.exit() + + def update(self): + # update portion of the game loop + self.agentSprites.update() + self.camera.update(self.player) + # pygame.display.update() + + def draw(self): + # display fps as window title + pg.display.set_caption("{:.2f}".format(self.clock.get_fps())) + + # rerender map + map.render_tiles(self.roadTiles, self.screen, self.camera) + map.render_tiles(self.wallTiles, self.screen, self.camera, self.debug_mode) + map.render_tiles(self.trashbinTiles, self.screen, self.camera) + map.render_tiles(self.trashDisplay, self.screen, self.camera) + + # draw text + text_surface = pg.font.SysFont('Comic Sans MS', 30).render(self.text_display, False, (255, 255, 255)) + self.screen.blit(text_surface, (0, 128)) + + # rerender additional sprites + for sprite in self.agentSprites: + self.screen.blit(sprite.image, self.camera.apply(sprite)) + if self.debug_mode: + pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.hit_rect), 1) + + # self.player.hud_group.draw(self.screen) + # finally update screen + pg.display.flip() + + def events(self): + for event in pg.event.get(): + if event.type == pg.QUIT: + self.quit() + if event.type == pg.KEYDOWN: + if event.key == pg.K_ESCAPE: + self.quit() + if event.key == pg.K_h: + self.debug_mode = not self.debug_mode + if event.type == pg.MOUSEBUTTONUP: + pos = pg.mouse.get_pos() + offset_x, offset_y = self.camera.offset() + clicked_coords = [math.floor(pos[0] / TILESIZE) - offset_x, math.floor(pos[1] / TILESIZE) - offset_y] + actions = a_star_controller.get_actions_by_coords(clicked_coords[0], clicked_coords[1], self) + + if (actions != None): + self.t.startAiController(actions) + + +# create the game object + +if __name__ == "__main__": + g = Game() + + g.run() g.show_go_screen() \ No newline at end of file diff --git a/path_search_algorthms/a_star.py b/path_search_algorthms/a_star.py index cae3813..0ee756a 100644 --- a/path_search_algorthms/a_star.py +++ b/path_search_algorthms/a_star.py @@ -1,76 +1,79 @@ -from data_structures.heap import Heap -from path_search_algorthms import a_star_utils as utils - - -def get_cost(start_x: int, start_y: int, target_x: int, target_y: int, array): - actions = search_path(start_x, start_y, utils.Rotation.NONE, target_x, target_y, array) - if actions is None: - return 1 - return len(actions) - - -def search_path(start_x: int, start_y: int, agent_rotation: utils.Rotation, target_x: int, target_y: int, array): - start_node = utils.Node(start_x, start_y, agent_rotation) - target_node = utils.Node(target_x, target_y, utils.Rotation.NONE) - - # heap version - - # nodes for check - search_list = Heap() - search_list.append(start_node, 0) - - # checked nodes - searched_list: list[(int, int)] = [] - - while (search_list.length() > 0): - node: utils.Node = search_list.take_first() - - searched_list.append((node.x, node.y)) - - # check for target node - if ((node.x, node.y) == (target_x, target_y)): - return trace_path(node) - - # neightbours processing - neighbours = utils.get_neighbours(node, searched_list, array) - for neighbour in neighbours: - - # calculate new g cost for neightbour (start -> node -> neightbour) - new_neighbour_cost = node.g_cost + utils.get_neighbour_cost(node, neighbour) - - if (new_neighbour_cost < neighbour.g_cost or not search_list.contains(neighbour)): - - # replace cost and set parent node - neighbour.g_cost = new_neighbour_cost - neighbour.h_cost = utils.get_h_cost(neighbour, target_node) - neighbour.parent = node - - # add to search - if (not search_list.contains(neighbour)): - search_list.append(neighbour, neighbour.f_cost()) - - -def trace_path(end_node: utils.Node): - path = [] - node = end_node - - # set final rotation of end_node because we don't do it before - node.rotation = utils.get_needed_rotation(node.parent, node) - - while (node.parent != False): - if (node.parent == utils.Rotation.NONE): - path += "forward" - else: - path += utils.get_move(node.parent, node) - node = node.parent - - # delete move on initial tile - path.pop() - - # we found path from end, so we need to reverse it (get_move reverse move words) - path.reverse() - - # last forward to destination - path.append("forward") - - return path +from data_structures.heap import Heap +from path_search_algorthms import a_star_utils as utils + + +def get_cost(start_x: int, start_y: int, target_x: int, target_y: int, array): + actions = search_path(start_x, start_y, utils.Rotation.NONE, target_x, target_y, array) + print('length') + if actions is None: + print('0') + return 1 + print(len(actions)) + return len(actions) + + +def search_path(start_x: int, start_y: int, agent_rotation: utils.Rotation, target_x: int, target_y: int, array): + start_node = utils.Node(start_x, start_y, agent_rotation) + target_node = utils.Node(target_x, target_y, utils.Rotation.NONE) + + # heap version + + # nodes for check + search_list = Heap() + search_list.append(start_node, 0) + + # checked nodes + searched_list: list[(int, int)] = [] + + while (search_list.length() > 0): + node: utils.Node = search_list.take_first() + + searched_list.append((node.x, node.y)) + + # check for target node + if ((node.x, node.y) == (target_x, target_y)): + return trace_path(node) + + # neightbours processing + neighbours = utils.get_neighbours(node, searched_list, array) + for neighbour in neighbours: + + # calculate new g cost for neightbour (start -> node -> neightbour) + new_neighbour_cost = node.g_cost + utils.get_neighbour_cost(node, neighbour) + + if (new_neighbour_cost < neighbour.g_cost or not search_list.contains(neighbour)): + + # replace cost and set parent node + neighbour.g_cost = new_neighbour_cost + neighbour.h_cost = utils.get_h_cost(neighbour, target_node) + neighbour.parent = node + + # add to search + if (not search_list.contains(neighbour)): + search_list.append(neighbour, neighbour.f_cost()) + + +def trace_path(end_node: utils.Node): + path = [] + node = end_node + + # set final rotation of end_node because we don't do it before + node.rotation = utils.get_needed_rotation(node.parent, node) + + while (node.parent != False): + if (node.parent == utils.Rotation.NONE): + path += "forward" + else: + path += utils.get_move(node.parent, node) + node = node.parent + + # delete move on initial tile + path.pop() + + # we found path from end, so we need to reverse it (get_move reverse move words) + path.reverse() + + # last forward to destination + path.append("forward") + + return path