Compare commits

..

19 Commits

Author SHA1 Message Date
8aadcfb677 Zaktualizuj 'src/dimensions.py' 2021-06-21 14:16:18 +02:00
831e599e14 Zaktualizuj 'tractor.py' 2021-06-21 14:15:45 +02:00
c21203fb72 Zaktualizuj 'node.py' 2021-06-21 14:14:44 +02:00
3fd1afdaeb Zaktualizuj 'src/colors.py' 2021-06-21 14:14:19 +02:00
4f5cf361ce Zaktualizuj 'field.py' 2021-06-21 14:14:00 +02:00
e9c11d37d2 Zaktualizuj 'plant.py' 2021-06-21 14:13:44 +02:00
e77b8d03f9 Zaktualizuj 'main.py' 2021-06-21 14:13:30 +02:00
8f0a1ed075 Zaktualizuj 'main.py' 2021-06-21 14:02:50 +02:00
bd33fa3df5 GA FIX
- END of bugfixing

with Michał Malinowski
2021-06-21 04:47:16 +02:00
5ca916873d GA FIX
- FIX bug where parents would not go to next gen

with Michał Malinowski
2021-06-21 04:43:13 +02:00
361a733102 GA END
- BUGfix
- comments
- stop var

with Michał Malinowski
2021-06-21 04:04:26 +02:00
ef5c5556ef GA implementation
- ADD comments
- ADD stop function

with Michał Malinowski
2021-06-21 03:38:21 +02:00
288d3cf30a GA implementation
- ADD crossover
- ADD mutation
- ADD next_gen preparation
- Project completed (with errors)

with Michał Malinowski
2021-06-21 03:24:07 +02:00
7a14078390 GA implementation
- ADD pretty_printer method
- crossover draft

with Michał Malinowski
2021-06-21 01:56:55 +02:00
19680a0139 GA implementation
- DONE best results
- DONE parents selection

with Michał Malinowski
2021-06-21 00:38:56 +02:00
301e05268c GA implementation
- DONE fitness function
2021-06-20 23:43:57 +02:00
6c905621ca Merge pull request 'GA implementation in env' (#1) from Paweł into master
Reviewed-on: #1
2021-06-20 18:03:50 +02:00
14795cdc5e Changed method for accuracy calculation: 2021-06-20 15:04:51 +02:00
3898a3bcab Update network model structure:
Changed model from FCNN to CNN
2021-06-20 15:00:34 +02:00
11 changed files with 489 additions and 250 deletions

View File

@ -1,5 +1,3 @@
import random
import keyboard as keyboard import keyboard as keyboard
import field as F import field as F
@ -11,18 +9,20 @@ from src import mapschema as maps
def genetic_algorithm_setup(field): def genetic_algorithm_setup(field):
population_units = ["", "w", "p", "s"] population_units = ["", "w", "p", "s"]
# new_population to be # TODO REPREZENTACJA OSOBNIKA - MACIERZ ROZKłADU PLONÓW
population_text = [] population_text = []
population_text_single = []
population_size = 10
# Populate the population_text array # Populate the population_text array
for row in range(D.GSIZE): for k in range(population_size):
population_text.append([]) population_text_single = []
for column in range(D.GSIZE): for row in range(D.GSIZE):
population_text[row].append(random.choice(population_units)) population_text_single.append([])
for column in range(D.GSIZE):
# printer population_text_single[row].append(random.choice(population_units))
for _ in population_text: population_text.append(population_text_single)
print(population_text)
""" """
Genetic algorithm parameters: Genetic algorithm parameters:
@ -31,75 +31,110 @@ def genetic_algorithm_setup(field):
""" """
# units per population in generation # units per population in generation
sol_per_pop = 8
num_parents_mating = 4
population_values = []
fitness_row = []
# population Fitness
for i in range(0, D.GSIZE):
for j in range(D.GSIZE):
fitness_row.append(local_fitness(field, i, j, population_text))
population_values.append(fitness_row)
best_outputs = [] best_outputs = []
num_generations = 10 num_generations = 100
num_parents = 4
# iterative var
generation = 0 generation = 0
stop = 0
while generation < num_generations: # TODO WARUNEK STOPU
while generation < num_generations and stop < 3:
if keyboard.is_pressed('space'): if keyboard.is_pressed('space'):
generation += 1 generation += 1
print("Generation : ", generation) print("Generation : ", generation)
# Measuring the fitness of each chromosome in the population. # Measuring the fitness of each chromosome in the population.
fitness = cal_pop_fitness(population_values) # population Fitness
fitness = []
for i in range(0, population_size):
fitness.append((i, population_fitness(population_text[i], field, population_size)))
print("Fitness") print("Fitness")
print(fitness) print(fitness)
# best_outputs.append(best_Output(new_population)) best = sorted(fitness, key=lambda tup: tup[1], reverse=True)[0:num_parents]
# The best result in the current iteration.
# print("Best result : ", best_Output(new_population))
# Leaderboard only
best_outputs.append(best[0][1])
# The best result in the current iteration.
print("Best result : ", best[0])
# TODO METODA WYBORU OSOBNIKA - RANKING
# Selecting the best parents in the population for mating. # Selecting the best parents in the population for mating.
parents = select_mating_pool(new_population, fitness, parents = [population_text[i[0]] for i in best]
num_parents_mating) parents_copy = copy.deepcopy(parents)
print("Parents") print("Parents")
print(parents) for i in range(0, len(parents)):
print('\n'.join([''.join(['{:4}'.format(item) for item in row])
for row in parents[i]]))
print("")
# Generating next generation using crossover. # Generating next generation using crossover.
offspring_crossover = crossover(parents, offspring_size=(pop_size[0] - parents.shape[0], num_weights)) offspring_x = random.randint(1, D.GSIZE - 2)
offspring_y = random.randint(1, D.GSIZE - 2)
# TODO OPERATOR KRZYŻOWANIA
offspring_crossover = crossover(parents)
print("Crossover") print("Crossover")
print(offspring_crossover) for i in range(0, len(offspring_crossover)):
print('\n'.join([''.join(['{:4}'.format(item) for item in row])
for row in offspring_crossover[i]]))
print("")
# Adding some variations to the offspring using mutation. # TODO OPERATOR MUTACJI
offspring_mutation = mutation(offspring_crossover, num_mutations=2) offspring_mutation = mutation(population_units, offspring_crossover, population_size - num_parents,
num_mutations=10)
print("Mutation") print("Mutation")
print(offspring_mutation) for i in range(0, len(offspring_mutation)):
print('\n'.join([''.join(['{:4}'.format(item) for item in row])
for row in offspring_mutation[i]]))
print("")
# Creating the new population based on the parents and offspring. population_text_copy = copy.deepcopy(population_text)
new_population[0:parents.shape[0], :] = parents unused_indexes = [i for i in range(0, population_size) if i not in [j[0] for j in best]]
new_population[parents.shape[0]:, :] = offspring_mutation # Creating next generation
population_text = []
for k in parents_copy:
population_text.append(k)
for k in range(0, len(offspring_mutation)):
population_text.append(offspring_mutation[k])
while len(population_text) < population_size:
x = random.choice(unused_indexes)
population_text.append(population_text_copy[x])
unused_indexes.remove(x)
# Getting the best solution after iterating finishing all generations. # TODO WARUNEK STOPU
# At first, the fitness is calculated for each solution in the final generation. stop = 0
fitness = cal_pop_fitness(new_population) if generation > 10:
# Then return the index of that solution corresponding to the best fitness. if best_outputs[-1] / best_outputs[-2] < 1.001:
best_match_idx = numpy.where(fitness == numpy.max(fitness)) stop += 1
if best_outputs[-1] / best_outputs[-3] < 1.001:
stop += 1
if best_outputs[-2] / best_outputs[-3] < 1.001:
stop += 1
print("Best solution : ", new_population[best_match_idx, :]) # final Fitness
print("Best solution fitness : ", fitness[best_match_idx]) fitness = []
for i in range(0, population_size):
fitness.append((i, population_fitness(population_text[i], field, population_size)))
import matplotlib.pyplot print("Final Fitness")
print(fitness)
matplotlib.pyplot.plot(best_outputs) best = sorted(fitness, key=lambda tup: tup[1])[0:num_parents]
matplotlib.pyplot.xlabel("Iteration")
matplotlib.pyplot.ylabel("Fitness")
matplotlib.pyplot.show()
# return best iteration of field print("Best solution : ", )
for i in range(0, D.GSIZE):
print(population_text[best[0][0]][i])
print("Best solution fitness : ", best[0][1])
pretty_printer(best_outputs)
# TODO REALLY return best iteration of field
return 0 return 0

View File

@ -1,63 +1,47 @@
import PIL import torch
import torchvision
import torchvision.transforms as transforms import torchvision.transforms as transforms
import torch.nn as nn
from AI import neural_network import torch.nn.functional as F
import torch.optim as optim
import numpy as np
from matplotlib.pyplot import imshow
import os
import PIL
import numpy as np
from matplotlib.pyplot import imshow
import neural_network
from matplotlib.pyplot import imshow
# wcześniej grinder.py # wcześniej grader.py
# Get accuracy for neural_network model 'network_model.pth' # Get accuracy for neural_network model 'network_model.pth'
def NN_accuracy(): def NN_accuracy():
# Create the model # Create the model
model = neural_network.Net() net = neural_network.Net()
# Load state_dict # Load state_dict
neural_network.load_network_from_structure(model) neural_network.load_network_from_structure(net)
# Create the preprocessing transformation here
transform = transforms.Compose([neural_network.Negative(), transforms.ToTensor()])
# load your image(s)
img = PIL.Image.open('../src/test/0_100.jpg')
img2 = PIL.Image.open('../src/test/1_100.jpg')
img3 = PIL.Image.open('../src/test/4_100.jpg')
img4 = PIL.Image.open('../src/test/5_100.jpg')
# Transform
input = transform(img)
input2 = transform(img2)
input3 = transform(img3)
input4 = transform(img4)
# unsqueeze batch dimension, in case you are dealing with a single image
input = input.unsqueeze(0)
input2 = input2.unsqueeze(0)
input3 = input3.unsqueeze(0)
input4 = input4.unsqueeze(0)
# Set model to eval # Set model to eval
model.eval() net.eval()
# Get prediction device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
output = model(input)
output2 = model(input2)
output3 = model(input3)
output4 = model(input4)
print(output) folderlist = os.listdir(os.path.dirname(__file__) + "\\test")
index = output.cpu().data.numpy().argmax()
print(index)
print(output2) tested = 0
index = output2.cpu().data.numpy().argmax() correct = 0
print(index)
print(output3) for folder in folderlist:
index = output3.cpu().data.numpy().argmax() for file in os.listdir(os.path.dirname(__file__) + "\\test\\" + folder):
print(index) if neural_network.result_from_network(net, os.path.dirname(__file__) + "\\test\\" + folder + "\\" + file) == folder:
correct += 1
tested += 1
else:
tested += 1
print(output4) print(correct/tested)
index = output4.cpu().data.numpy().argmax()
print(index)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,3 +1,8 @@
import copy
import random
import matplotlib
import matplotlib.pyplot
import numpy import numpy
import src.dimensions as D import src.dimensions as D
@ -5,88 +10,94 @@ import src.dimensions as D
# Genetic Algorithm methods # Genetic Algorithm methods
def local_fitness(field, x, y, plants): def local_fitness(field, x, y, plants_case):
soil_value = 0 soil_value = 0
if field[x][y].field_type == "soil": if field[x][y].field_type == "soil":
soil_value = 1 soil_value = 1
else: else:
soil_value = 0.5 soil_value = 0.5
if plants[x][y] == "": if plants_case[x][y] == "":
plant_value = 0 plant_value = 0
elif plants[x][y] == "w": elif plants_case[x][y] == "w":
plant_value = 1 plant_value = 1
elif plants[x][y] == "p": elif plants_case[x][y] == "p":
plant_value = 2 plant_value = 2
elif plants[x][y] == "s": elif plants_case[x][y] == "s":
plant_value = 3 plant_value = 3
else:
plant_value = 1
neighbour_bonus = 1 neighbour_bonus = 1
if x - 1 >= 0: if x - 1 >= 0:
if plants[x][y] == plants[x - 1][y]: if plants_case[x][y] == plants_case[x - 1][y]:
neighbour_bonus += 1 neighbour_bonus += 1
if x + 1 < D.GSIZE: if x + 1 < D.GSIZE:
if plants[x][y] == plants[x + 1][y]: if plants_case[x][y] == plants_case[x + 1][y]:
neighbour_bonus += 1 neighbour_bonus += 1
if y - 1 >= 0: if y - 1 >= 0:
if plants[x][y] == plants[x][y - 1]: if plants_case[x][y] == plants_case[x][y - 1]:
neighbour_bonus += 1 neighbour_bonus += 1
if y + 1 < D.GSIZE: if y + 1 < D.GSIZE:
if plants[x][y] == plants[x][y + 1]: if plants_case[x][y] == plants_case[x][y + 1]:
neighbour_bonus += 1 neighbour_bonus += 1
# TODO * multiculture_bonus
local_fitness_value = (soil_value + plant_value) * (0.5 * neighbour_bonus + 1) local_fitness_value = (soil_value + plant_value) * (0.5 * neighbour_bonus + 1)
return local_fitness_value return local_fitness_value
def cal_pop_fitness(pop): def population_fitness(population_text_local, field, population_size):
# Calculating the fitness value of each solution in the current population. # Calculating the fitness value of each solution in the current population.
# The fitness function calulates the sum of products between each input and its corresponding weight. # The fitness function calulates the sum of products between each input and its corresponding weight.
fitness = sum(map(sum, pop)) fitness = []
for k in range(population_size):
population_values_single = []
population_values_single_row = []
fitness_row = []
for i in range(0, D.GSIZE):
for j in range(0, D.GSIZE):
population_values_single_row.append(local_fitness(field, i, j, population_text_local))
population_values_single.append(population_values_single_row)
for i in range(D.GSIZE):
fitness_row.append(sum(population_values_single[i]))
fitness = sum(fitness_row)
return fitness return fitness
def select_mating_pool(pop, fitness, num_parents): def crossover(local_parents):
# Selecting the best individuals in the current generation as parents for producing the offspring of the next generation. ret = []
parents = numpy.empty((num_parents, pop.shape[1])) for i in range(0, len(local_parents)):
for parent_num in range(num_parents): child = copy.deepcopy(local_parents[i])
max_fitness_idx = numpy.where(fitness == numpy.max(fitness)) # Vertical randomization
max_fitness_idx = max_fitness_idx[0][0] width = random.randint(1, D.GSIZE // len(local_parents)) # width of stripes
parents[parent_num, :] = pop[max_fitness_idx, :] indexes_parents = numpy.random.permutation(range(0, len(local_parents))) # sorting of stripes
fitness[max_fitness_idx] = -99999999999 beginning = random.randint(0, len(local_parents[0]) - width * len(
return parents local_parents)) # point we start putting the stripes from
for x in indexes_parents:
child[beginning:beginning + width] = local_parents[x][beginning:beginning + width]
beginning += width
ret.append(child)
return ret
def crossover(parents, offspring_size): def mutation(population_units, offspring_crossover, num_mutants, num_mutations=10):
offspring = numpy.empty(offspring_size) for case in range(0, len(offspring_crossover)):
# The point at which crossover takes place between two parents. Usually, it is at the center. for mutation in range(0, num_mutations):
crossover_point = numpy.uint8(offspring_size[1] / 2) mutation_x = random.randint(0, D.GSIZE - 1)
mutation_y = random.randint(0, D.GSIZE - 1)
mutation_value = random.choice(population_units)
offspring_crossover[case][mutation_x][mutation_y] = mutation_value
num_mutants -= 1
for k in range(offspring_size[0]):
# Index of the first parent to mate.
parent1_idx = k % parents.shape[0]
# Index of the second parent to mate.
parent2_idx = (k + 1) % parents.shape[0]
# The new offspring will have its first half of its genes taken from the first parent.
offspring[k, 0:crossover_point] = parents[parent1_idx, 0:crossover_point]
# The new offspring will have its second half of its genes taken from the second parent.
offspring[k, crossover_point:] = parents[parent2_idx, crossover_point:]
return offspring
def mutation(offspring_crossover, num_mutations=1):
mutations_counter = numpy.uint8(offspring_crossover.shape[1] / num_mutations)
# Mutation changes a number of genes as defined by the num_mutations argument. The changes are random.
for idx in range(offspring_crossover.shape[0]):
gene_idx = mutations_counter - 1
for mutation_num in range(num_mutations):
# The random value to be added to the gene.
random_value = numpy.random.uniform(-1.0, 1.0, 1)
offspring_crossover[idx, gene_idx] = offspring_crossover[idx, gene_idx] + random_value
gene_idx = gene_idx + mutations_counter
return offspring_crossover return offspring_crossover
def best_Output(new_population): def pretty_printer(best_outputs):
return numpy.max(numpy.sum(new_population * equation_inputs, axis=1)) matplotlib.pyplot.plot(best_outputs)
matplotlib.pyplot.xlabel("Iteration")
matplotlib.pyplot.ylabel("Fitness")
matplotlib.pyplot.show()

View File

@ -1,69 +1,76 @@
import PIL
import numpy as np
import torch import torch
import torch.nn as nn
import torch.optim as optim
import torchvision import torchvision
import torchvision.transforms as transforms import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
from matplotlib.pyplot import imshow
import os
import PIL
import numpy as np
from matplotlib.pyplot import imshow from matplotlib.pyplot import imshow
def to_negative(img): def to_negative(img):
img = PIL.ImageOps.invert(img) img = PIL.ImageOps.invert(img)
return img return img
class Negative(object): class Negative(object):
def __init__(self): def __init__(self):
pass pass
def __call__(self, img): def __call__(self, img):
return to_negative(img) return to_negative(img)
def plotdigit(image):
img = np.reshape(image, (-1, 100))
imshow(img, cmap='Greys')
transform = transforms.Compose([Negative(), transforms.ToTensor()]) transform = transforms.Compose([Negative(), transforms.ToTensor()])
train_set = torchvision.datasets.ImageFolder(root='../src/train', transform=transform) train_set = torchvision.datasets.ImageFolder(root='train', transform=transform)
classes = ("apple", "potato") classes = ("pepper", "potato", "strawberry", "tomato")
BATCH_SIZE = 2 BATCH_SIZE = 4
train_loader = torch.utils.data.DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True, num_workers=0) train_loader = torch.utils.data.DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True, num_workers=0)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
class Net(nn.Module): class Net(nn.Module):
def __init__(self): def __init__(self):
super(Net, self).__init__() super().__init__()
self.flatten = nn.Flatten() self.network = nn.Sequential(
self.linear_relu_stack = nn.Sequential( nn.Conv2d(3, 32, kernel_size=3, padding=1), #3 channels to 32 channels
nn.Linear(3 * 100 * 100, 512),
nn.ReLU(), nn.ReLU(),
nn.Linear(512, 512), nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
nn.ReLU(), nn.ReLU(),
nn.Linear(512, 2), nn.MaxPool2d(2, 2), # output: 64 channels x 50 x 50 image size - decrease
nn.ReLU()
)
self.linear_relu_stack = self.linear_relu_stack.to(device)
def forward(self, x): nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
x = self.flatten(x).to(device) nn.ReLU(),
logits = self.linear_relu_stack(x).to(device) nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1), #increase power of model
return logits nn.ReLU(),
nn.MaxPool2d(2, 2), # output: 128 x 25 x 25
nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.Conv2d(256, 256, kernel_size=3, stride=1, padding=1),
nn.ReLU(),
nn.MaxPool2d(5, 5), # output: 256 x 5 x 5
nn.Flatten(), #a single vector 256*5*5,
nn.Linear(256*5*5, 1024),
nn.ReLU(),
nn.Linear(1024, 512),
nn.ReLU(),
nn.Linear(512, 4))
def forward(self, xb):
return self.network(xb)
def training_network(): def training_network():
net = Net() net = Net()
net = net.to(device) net = net.to(device)
criterion = nn.CrossEntropyLoss() criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
for epoch in range(4): for epoch in range(10):
running_loss = 0.0 running_loss = 0.0
for i, data in enumerate(train_loader, 0): for i, data in enumerate(train_loader, 0):
inputs, labels = data[0].to(device), data[1].to(device) inputs, labels = data[0].to(device), data[1].to(device)
@ -72,34 +79,33 @@ def training_network():
loss = criterion(outputs, labels) loss = criterion(outputs, labels)
loss.backward() loss.backward()
optimizer.step() optimizer.step()
running_loss += loss.item() running_loss += loss.item()
if i % 2000 == 1999: if i % 200 == 199:
print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss)) print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss))
running_loss = 0.0 running_loss = 0.0
print("Finished training") print("Finished training")
save_network_to_file(net) save_network_to_file(net)
def result_from_network(net, loaded_image): def result_from_network(net, loaded_image):
image = PIL.Image.open(loaded_image) image = PIL.Image.open(loaded_image)
pil_to_tensor = transforms.ToTensor()(image.convert("RGB")).unsqueeze_(0) pil_to_tensor = transforms.Compose([Negative(), transforms.ToTensor()])(image.convert("RGB")).unsqueeze_(0)
outputs = net(pil_to_tensor.to(device)) outputs = net(pil_to_tensor)
return classes[torch.max(outputs, 1)[1]] return classes[torch.max(outputs, 1)[1]]
def save_network_to_file(network): def save_network_to_file(network):
torch.save(network.state_dict(), 'network_model.pth') torch.save(network.state_dict(), 'network_model.pth')
print("Network saved to file") print("Network saved to file")
def load_network_from_structure(network): def load_network_from_structure(network):
network.load_state_dict(torch.load('network_model.pth')) network.load_state_dict(torch.load('network_model.pth'))
# Create network_model.pth
if __name__ == "__main__": if __name__ == "__main__":
print(torch.cuda.is_available()) print(torch.cuda.is_available())
training_network() training_network()

View File

@ -1,9 +1,7 @@
import pygame import pygame
from src.colors import * from src.colors import *
from src.dimensions import * from src.dimensions import *
class Field(pygame.sprite.Sprite): class Field(pygame.sprite.Sprite):
def __init__(self, row, column, field_type): def __init__(self, row, column, field_type):
super(Field, self).__init__() super(Field, self).__init__()
@ -26,22 +24,62 @@ class Field(pygame.sprite.Sprite):
self.position = [row, column] self.position = [row, column]
self.hydration = 0 self.hydration = 0
self.planted = 0 self.planted = 0
self.fertility = 1 self.fertility = 0
self.tractor_there = False self.tractor_there = False
def hydrate(self): def hydrate(self):
if self.field_type == "soil" and self.hydration <= 5: if self.field_type == "soil" and self.hydration <= 5:
self.hydration += 1 self.hydration += 1
if self.fertility == 1:
# color field to it's hydration value if self.hydration == 0:
self.surf.fill(eval('BROWN' + str(self.hydration))) self.surf.fill(REDDISH0)
self.fertility = 0
if self.hydration == 1:
self.surf.fill(REDDISH1)
if self.hydration == 2:
self.surf.fill(REDDISH2)
if self.hydration == 3:
self.surf.fill(REDDISH3)
if self.hydration == 4 or self.hydration == 5:
self.surf.fill(REDDISH4)
else:
if self.hydration == 0:
self.surf.fill(BROWN0)
if self.hydration == 1:
self.surf.fill(BROWN1)
if self.hydration == 2:
self.surf.fill(BROWN2)
if self.hydration == 3:
self.surf.fill(BROWN3)
if self.hydration == 4 or self.hydration == 5:
self.surf.fill(BROWN4)
def dehydrate(self): def dehydrate(self):
if self.field_type == "soil" and self.hydration > 0: if self.field_type == "soil" and self.hydration > 0:
self.hydration -= 1 self.hydration -= 1
if self.fertility == 1:
# color field to it's hydration value if self.hydration == 0:
self.surf.fill(eval('BROWN' + str(self.hydration))) self.surf.fill(REDDISH0)
self.fertility = 0
if self.hydration == 1:
self.surf.fill(REDDISH1)
if self.hydration == 2:
self.surf.fill(REDDISH2)
if self.hydration == 3:
self.surf.fill(REDDISH3)
if self.hydration == 4 or self.hydration == 5:
self.surf.fill(REDDISH4)
else:
if self.hydration == 0:
self.surf.fill(BROWN0)
if self.hydration == 1:
self.surf.fill(BROWN1)
if self.hydration == 2:
self.surf.fill(BROWN2)
if self.hydration == 3:
self.surf.fill(BROWN3)
if self.hydration == 4 or self.hydration == 5:
self.surf.fill(BROWN4)
def free(self): def free(self):
self.planted = 0 self.planted = 0

43
main.py
View File

@ -10,12 +10,15 @@ from pygame.locals import (
QUIT QUIT
) )
# Import other files from project # Import other files from project
import field as F import field as F
import node as N import node as N
import plant as P import plant as P
import src.colors as C import src.colors as C
import src.dimensions as D import src.dimensions as D
import AI.GeneticAlgorithm as ga
import AI.neural_network as nn
import tractor as T import tractor as T
from src import mapschema as maps from src import mapschema as maps
@ -44,6 +47,16 @@ if __name__ == "__main__":
field[row].append(fieldbit) field[row].append(fieldbit)
# genetic_algorithm_setup(field) # genetic_algorithm_setup(field)
num_of_plants = 0
plant_pops = []
best_plant_pop = []
goal_gen = 100
best_plant_pop, plant_pops, num_of_plants, fitness = ga.genetic_algorithm_setup(field, plant_pops, goal_gen)
net = nn.Net()
nn.load_network_from_structure(net)
net.eval()
# Create Tractor object # Create Tractor object
tractor = T.Tractor(field, [0, 0]) tractor = T.Tractor(field, [0, 0])
@ -58,9 +71,11 @@ if __name__ == "__main__":
for row in range(D.GSIZE): for row in range(D.GSIZE):
plants.append([]) plants.append([])
for column in range(D.GSIZE): for column in range(D.GSIZE):
if mapschema[column][row] != 0: if best_plant_pop[column][row] != "":
plantbit = P.Plant(field[row][column], mapschema[column][row]) plantbit = P.Plant(field[row][column], best_plant_pop[column][row])
plants[row].append(plantbit) plants[row].append(plantbit)
else:
plants[row].append(0)
# Create list for tractor instructions # Create list for tractor instructions
path = [] path = []
@ -77,7 +92,6 @@ if __name__ == "__main__":
# Main loop # Main loop
while RUNNING: while RUNNING:
# Look at every event in the queue
for event in pygame.event.get(): for event in pygame.event.get():
# Did the user hit a key? # Did the user hit a key?
if event.type == KEYDOWN: if event.type == KEYDOWN:
@ -105,19 +119,11 @@ if __name__ == "__main__":
tractor.rotate_right() tractor.rotate_right()
elif path[0] == "hydrate": elif path[0] == "hydrate":
tractor.hydrate(field) tractor.hydrate(field)
elif path[0] == "fertilize":
if plants[tractor.position[1]][tractor.position[0]]:
tractor.fertilize(field, plants, nn.result_from_network(net, plants[tractor.position[0]][tractor.position[1]].testimage))
path.pop(0) path.pop(0)
# Get all keys pressed at a time CURRENTLY UNUSED
pressed_keys = pygame.key.get_pressed()
# control tractor with pressed keys CURRENTLY UNUSED
if pressed_keys[K_UP]:
tractor.move()
elif pressed_keys[K_LEFT]:
tractor.rotate_left()
elif pressed_keys[K_RIGHT]:
tractor.rotate_right()
# Set the screen background # Set the screen background
screen.fill(C.DBROWN) screen.fill(C.DBROWN)
@ -133,9 +139,10 @@ if __name__ == "__main__":
# Plants grow with every 10th tick, then they are drawn # Plants grow with every 10th tick, then they are drawn
for row in plants: for row in plants:
for plant in row: for plant in row:
plant.tick() if plant != 0:
plant.grow() plant.tick()
screen.blit(plant.surf, plant.rect) plant.grow()
screen.blit(plant.surf, plant.rect)
# Field are drying with every 100th tick # Field are drying with every 100th tick
if TICKER == 0: if TICKER == 0:
@ -150,4 +157,4 @@ if __name__ == "__main__":
pygame.display.flip() pygame.display.flip()
# Ensure program maintains a stable framerate # Ensure program maintains a stable framerate
clock.tick(8) clock.tick(35)

56
node.py
View File

@ -137,10 +137,12 @@ class Node:
closedList.append(currentNode) closedList.append(currentNode)
if currentNode.field[currentNode.position[0]][currentNode.position[1]].planted and \ if currentNode.field[currentNode.position[0]][currentNode.position[1]].planted and \
currentNode.field[currentNode.position[0]][currentNode.position[1]].field_type == "soil" and \
currentNode.field[currentNode.position[0]][currentNode.position[1]].hydration < 2: currentNode.field[currentNode.position[0]][currentNode.position[1]].hydration < 2:
path = [] path = []
for _ in range(currentNode.field[currentNode.position[0]][currentNode.position[1]].hydration, 4): for _ in range(currentNode.field[currentNode.position[0]][currentNode.position[1]].hydration, 4):
path.append("hydrate") path.append("hydrate")
path.append("fertilize")
current = currentNode current = currentNode
while current is not None: while current is not None:
path.append(current.action) path.append(current.action)
@ -174,3 +176,57 @@ class Node:
continue continue
heapq.heappush(openList, child) heapq.heappush(openList, child)
def findPathToPlantSpot(self, goals):
startNode = Node(self.field, self.position, self.rotation)
openList = []
closedList = []
startNode.parent = None
heapq.heappush(openList, startNode)
while len(openList) > 0:
currentNode = heapq.heappop(openList)
closedList.append(currentNode)
if not currentNode.field[currentNode.position[0]][currentNode.position[1]].planted and \
goals[currentNode.position[0]][currentNode.position[1]] != "":
path = []
path.append("plant")
current = currentNode
while current is not None:
path.append(current.action)
current = current.parent
return path[::-1]
children = succesor(currentNode)
perm = 0
for child in children:
for closedChild in closedList:
if child.position == closedChild.position and child.rotation == closedChild.rotation and child.action == closedChild.action:
perm = 1
break
if perm == 1:
perm = 0
continue
child.parent = currentNode
child.startCost = currentNode.startCost + child.field[child.position[0]][child.position[1]].moveCost
child.heuristic = abs(startNode.position[0] - child.position[0]) + abs(
startNode.position[1] - child.position[1])
child.totalCost = child.startCost + child.heuristic
for openNode in openList:
if child.position == openNode.position and child.rotation == openNode.rotation and child.action == openNode.action and child.startCost >= openNode.startCost:
perm = 1
break
if perm == 1:
perm = 0
continue
heapq.heappush(openList, child)

110
plant.py
View File

@ -1,29 +1,32 @@
import os
import random
from AI.decision_tree import * from AI.decision_tree import *
from src.dimensions import * from src.dimensions import *
from src.sprites import * from src.sprites import *
from src.colors import *
path = os.path.dirname(__file__) + "\\src\\test\\"
class Plant(pygame.sprite.Sprite): class Plant(pygame.sprite.Sprite):
def __init__(self, field, species): def __init__(self, field, species):
super(Plant, self).__init__()
self.species = species self.species = species
if self.species == "wheat": if self.species == "tomato":
self.growth_speed = 1.5
self.humidity_needed = 2
self.img0 = wheat_img_0 self.img0 = wheat_img_0
self.img1 = wheat_img_1 self.img1 = wheat_img_1
self.img2 = wheat_img_2 self.img2 = wheat_img_2
self.img3 = wheat_img_3 self.img3 = wheat_img_3
elif self.species == "potato": elif self.species == "potato":
self.growth_speed = 1
self.humidity_needed = 1
self.img0 = potato_img_0 self.img0 = potato_img_0
self.img1 = potato_img_1 self.img1 = potato_img_1
self.img2 = potato_img_2 self.img2 = potato_img_2
self.img3 = potato_img_3 self.img3 = potato_img_3
elif self.species == "strawberry": elif self.species == "strawberry":
self.growth_speed = 0.8 self.img0 = strawberry_img_0
self.humidity_needed = 1 self.img1 = strawberry_img_1
self.img2 = strawberry_img_2
self.img3 = strawberry_img_3
elif self.species == "pepper":
self.img0 = strawberry_img_0 self.img0 = strawberry_img_0
self.img1 = strawberry_img_1 self.img1 = strawberry_img_1
self.img2 = strawberry_img_2 self.img2 = strawberry_img_2
@ -38,9 +41,94 @@ class Plant(pygame.sprite.Sprite):
field.planted = True field.planted = True
self.tickscount = 0 self.tickscount = 0
self.ticks = 0 self.ticks = 0
self.path = path + self.species + "\\"
self.testimage = self.path + random.choice(os.listdir(self.path))
def dtree(self): def dtree(self):
decision_tree(self) if self.field.hydration == 4:
if self.is_healthy == 1:
if self.field.tractor_there == 0:
if self.ticks == 0:
return 0
elif self.ticks == 1:
return 1
elif self.field.tractor_there == 1:
return 0
elif self.is_healthy == 0:
return 0
elif self.field.hydration == 2:
if self.species == "pepper":
if self.ticks == 1:
if self.is_healthy == 1:
return 1
elif self.is_healthy == 0:
return 0
elif self.ticks == 0:
return 0
elif self.species == "potato":
return 0
elif self.species == "tomato":
return 0
elif self.species == "strawberry":
return 0
elif self.field.hydration == 1:
if self.species == "potato":
return 0
elif self.species == "strawberry":
if self.ticks == 1:
return -1
elif self.ticks == 0:
return 0
elif self.species == "tomato":
return 0
elif self.species == "pepper":
if self.is_healthy == 0:
return 0
elif self.is_healthy == 1:
if self.field.tractor_there == 0:
if self.ticks == 0:
return 0
elif self.ticks == 1:
return 1
elif self.field.tractor_there == 1:
return 0
elif self.field.hydration == 3:
if self.ticks == 1:
if self.field.tractor_there == 0:
if self.is_healthy == 1:
if self.species == "potato":
if self.field.fertility == 1:
return 1
elif self.field.fertility == 0:
return 0
elif self.species == "strawberry":
return 1
elif self.species == "pepper":
return 1
elif self.species == "tomato":
return 1
elif self.is_healthy == 0:
return 0
elif self.field.tractor_there == 1:
return 0
elif self.ticks == 0:
return 0
elif self.field.hydration == 5:
if self.field.tractor_there == 1:
return 0
elif self.field.tractor_there == 0:
if self.is_healthy == 0:
return 0
elif self.is_healthy == 1:
if self.ticks == 1:
return 1
elif self.ticks == 0:
return 0
elif self.field.hydration == 0:
if self.ticks == 0:
return 0
elif self.ticks == 1:
return -1
def update(self): def update(self):
if self.growth == 0: if self.growth == 0:
@ -63,6 +151,7 @@ class Plant(pygame.sprite.Sprite):
self.growth = 4 self.growth = 4
if self.growth < 0: if self.growth < 0:
self.growth = 0 self.growth = 0
self.update() self.update()
def tick(self): def tick(self):
@ -70,3 +159,6 @@ class Plant(pygame.sprite.Sprite):
if self.tickscount >= 25: if self.tickscount >= 25:
self.tickscount = 0 self.tickscount = 0
self.ticks = 1 self.ticks = 1
def remove(self):
self.field.planted = False

View File

@ -7,6 +7,14 @@ BROWN2 = (140, 110, 55)
BROWN3 = (110, 85, 40) BROWN3 = (110, 85, 40)
BROWN4 = (80, 60, 20) BROWN4 = (80, 60, 20)
BROWN5 = (80, 60, 20) BROWN5 = (80, 60, 20)
REDDISH0 = (230, 150, 90)
REDDISH1 = (210, 130, 70)
REDDISH2 = (190, 110, 55)
REDDISH3 = (160, 85, 40)
REDDISH4 = (130, 60, 20)
REDDISH5 = (130, 60, 20)
DBROWN = (65, 50, 20) DBROWN = (65, 50, 20)
LBROWN = (108, 97, 62) LBROWN = (108, 97, 62)
BLUE = (18, 93, 156) BLUE = (18, 93, 156)

View File

@ -2,12 +2,12 @@
GSIZE = 10 GSIZE = 10
# This sets the WIDTH and HEIGHT of each grid location # This sets the WIDTH and HEIGHT of each grid location
WIDTH = 35 WIDTH = 80
HEIGHT = 35 HEIGHT = 80
# This sets the margin between each cell # This sets the margin between each cell
MARGIN = 5 MARGIN = 5
# Window size # Window size
SCREEN_WIDTH = GSIZE * (WIDTH + MARGIN) + MARGIN SCREEN_WIDTH = GSIZE * (WIDTH + MARGIN) + MARGIN
SCREEN_HEIGHT = GSIZE * (HEIGHT + MARGIN) + MARGIN SCREEN_HEIGHT = GSIZE * (HEIGHT + MARGIN) + MARGIN + 100

View File

@ -1,7 +1,6 @@
from pygame.locals import (K_c)
from src.dimensions import * from src.dimensions import *
from src.sprites import * from src.sprites import *
from plant import *
class Tractor(pygame.sprite.Sprite): class Tractor(pygame.sprite.Sprite):
@ -73,10 +72,13 @@ class Tractor(pygame.sprite.Sprite):
field[self.position[0]][self.position[1]].hydrate() field[self.position[0]][self.position[1]].hydrate()
def cut(self, field, pressed_keys): def cut(self, field, pressed_keys):
if pressed_keys[K_c]: field[self.position[0]][self.position[1]].free()
field[self.position[0]][self.position[1]].free()
def plant(self, field, plant, pressed_keys): def plant(self, plant_map, plants):
if field.planted == 0: print(plant_map[self.position[0]][self.position[1]])
field.planted = plant plant = Plant(self.field[self.position[0]][self.position[1]], plant_map[self.position[0]][self.position[1]])
plant.field = field plants.append(plant)
def fertilize(self, field, plants, type):
if plants[self.position[0]][self.position[1]].species == type:
field[self.position[0]][self.position[1]].fertility = 1