Compare commits

...

10 Commits

Author SHA1 Message Date
Wojciech Kubicki
b761c83ee3 Merge branch 'main' of https://git.wmi.amu.edu.pl/s483780/inteligenty-traktor 2024-06-10 15:38:10 +02:00
Wojciech Kubicki
790438a9a2 fix: apply decision tree for choosing new crops 2024-06-10 15:36:47 +02:00
84699d2824 Update README.md 2024-06-10 15:36:04 +02:00
Adam Mikolajczak
f0970e414b fix: more examples to the learning set of decision tree 2024-06-10 15:07:49 +02:00
Adam Mikolajczak
d765a4f818 fix: pietruszka problem
adde even more examples to the learning set of decision tree. :)
2024-06-10 14:45:30 +02:00
Adam Mikolajczak
e053757bcf fix: ziemniaki problem
Added more examples to the learning set of decision tree.
2024-06-10 14:34:38 +02:00
Adam Mikolajczak
1856cd5fca fix: More exmaples with dynia added to the decision tree learning set 2024-06-10 14:18:22 +02:00
Wojciech Kubicki
a2c0137ddd fix: add missing prediction attribute to Tile class 2024-06-09 18:45:52 +02:00
Wojciech Kubicki
7c1814630a merge genetic algorithm with main 2024-06-09 17:10:52 +02:00
Wojciech Kubicki
77d559a63e feat: update field generation and load layouts in main program 2024-06-09 16:31:11 +02:00
10 changed files with 106 additions and 82 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
__pycache__/ __pycache__/
.DS_Store .DS_Store
.env .env
src/field

View File

@ -1,3 +0,0 @@
{
"recommendations": ["sbsnippets.pytorch-snippets"]
}

View File

@ -8,6 +8,8 @@ Wymagane biblioteki do pobrania:
pip install pygame pip install pygame
pip install python-dotenv pip install python-dotenv
pip install pytholog pip install pytholog
pip install torch
pip install sklearn
``` ```
Stwórz plik `.env` w głównym folderze projektu o poniższej treści: Stwórz plik `.env` w głównym folderze projektu o poniższej treści:
@ -25,10 +27,6 @@ STARTING_DIRECTION = north
START_X = 0 START_X = 0
START_Y = 0 START_Y = 0
# coordinates of destination tile
FINAL_X = 15
FINAL_Y = 15
# tiles without plants modifier # tiles without plants modifier
FREE_TILES = 2 FREE_TILES = 2
``` ```
@ -37,9 +35,12 @@ Uruchom środowisko używając komend:
``` ```
cd src cd src
python generate_field.py
python main.py python main.py
``` ```
Skrypt `generate_field.py` musi zostać przy pierwszym uruchomieniu, aby wygenerować pole. Kolejne wykonania skryptu nie są wymagane.
## 🧑‍🌾 Członkowie grupy ## 🧑‍🌾 Członkowie grupy
- Wojciech Kubicki (483780) - Wojciech Kubicki (483780)

1
src/.~lock.tree.csv# Normal file
View File

@ -0,0 +1 @@
,adam,adam-thinkpad,10.06.2024 15:05,file:///home/adam/.config/libreoffice/4;

View File

@ -1,13 +1,16 @@
import pygame import pygame
from tile import Tile from tile import Tile
from tractor import Tractor from tractor import Tractor
from ast import literal_eval
class Field: class Field:
def __init__(self): def __init__(self):
self.tiles = pygame.sprite.Group() self.tiles = pygame.sprite.Group()
# TODO: enable resizing field grid from 16x16 to any size with open('./field', 'r', encoding='UTF-8') as file:
for x in range(256): content = file.read()
self.tiles.add(Tile(x, self)) tiles = literal_eval(content)
for x in range(len(tiles)):
self.tiles.add(Tile(x, self, tiles[x]))
self.tractor = Tractor(self) self.tractor = Tractor(self)

View File

@ -1,6 +1,7 @@
from random import randint, choices, random from random import randint, choices, random
from kb import tractor_kb, multi_sasiedzi from kb import tractor_kb, multi_sasiedzi
import pytholog as pl import pytholog as pl
from numpy.random import choice as npchoice
def score_field(field): def score_field(field):
@ -17,33 +18,32 @@ def score_field(field):
if index % 16 != 0 and field[index-1] != 'water': if index % 16 != 0 and field[index-1] != 'water':
neighbours.append(field[index-1]) neighbours.append(field[index-1])
score += multi_sasiedzi(field[index], neighbours)[0]["Mul"] mod = multi_sasiedzi(field[index], neighbours)[0]["Mul"]
if mod > 10:
print(mod, '= multi(', field[index], ', ', neighbours, ')')
score += mod
score = score / 256
return score return score
def choose_parents(population): def choose_parents(population):
weights = [x[0] for x in population] total_weights = sum(entity[0] for entity in population)
weights_sum = 0
for weight in weights:
weights_sum += weight
weights = [weight/weights_sum for weight in weights] weights = [entity[0] / total_weights for entity in population]
mom = choices(population, cum_weights=weights, k=1)[0] selection = npchoice(len(population), size=2, replace=False, p=weights)
remaining_elements = [el for el in population if el != mom]
remaining_weights = [weights[population.index(el)] for el in remaining_elements]
dad = choices(remaining_elements, weights=remaining_weights, k=1)[0]
return mom, dad parents = [population[i] for i in selection]
return parents[0], parents[1]
def breed_and_mutate(mom, dad): def breed_and_mutate(mom, dad):
crossover_point = randint(1, len(mom[1]) - 2) crossover_point = randint(1, len(mom[1]) - 2)
offspring = mom[1][:crossover_point] + dad[1][crossover_point:] offspring = mom[1][:crossover_point] + dad[1][crossover_point:]
if len(offspring) != len(mom): if len(offspring) != len(mom):
ValueError("offspring lenght is not equal to mom length") ValueError("offspring length is not equal to mom length")
if random() < 0.1: if random() < 0.1:
mutation_index = randint(0, len(offspring) - 1) mutation_index = randint(0, len(offspring) - 1)
@ -57,6 +57,7 @@ def breed_and_mutate(mom, dad):
offspring[mutation_index] = mutation offspring[mutation_index] = mutation
offspring_score = score_field(offspring) offspring_score = score_field(offspring)
# print('offspring score', offspring_score, 'for parents', mom[0], 'and', dad[0])
return [offspring_score, offspring] return [offspring_score, offspring]
@ -73,9 +74,10 @@ def genetic_algorithm(population, iterations):
for entity in population: for entity in population:
entity[0] = score_field(entity[1]) entity[0] = score_field(entity[1])
for _ in range(iterations): for iteration in range(iterations):
population.sort(key=lambda x: x[0], reverse=True) population.sort(key=lambda x: x[0], reverse=True)
population = population[:5] print('\n=====\n\n💪 Best individual in iteration', iteration, 'has a score of', population[0][0])
population = population[:population_size//2]
new_offspring = [] new_offspring = []
while len(population) + len(new_offspring) < population_size: while len(population) + len(new_offspring) < population_size:
@ -88,36 +90,27 @@ def genetic_algorithm(population, iterations):
return population[0] return population[0]
vegetables = [x['Nazwa_warzywa'] for x in tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))]
# water tiles locations
# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
# _ _ X X _ _ _ _ _ _ X X X _ _ _
# _ X X X _ _ _ _ _ X X X _ _ _ _
# _ _ X _ _ _ _ _ _ _ _ _ _ _ _ _
# _ _ X _ _ _ _ X X _ X X _ _ _ _
# _ _ _ _ _ _ X X X X X X _ _ _ _
# _ _ _ _ _ _ X X _ _ _ _ _ _ _ _
# _ _ _ _ _ _ _ X X _ _ _ _ _ _ _
# _ _ _ _ X _ _ _ _ _ _ _ _ _ _ _
# _ _ _ _ X X _ _ _ _ _ _ _ _ _ _
# _ _ _ _ X _ _ _ _ _ X _ _ _ _ _
# _ _ _ _ _ _ _ _ X X X X _ _ _ _
# _ _ _ X _ _ _ _ _ X X X _ _ _ _
# _ X _ _ _ _ _ _ _ _ _ _ _ _ _ _
# _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
water_tile_indexes = [37, 38, 45, 46, 47, 53, 54, 55, 61, 62, 63, 71, 88, 93, 94, 96, 97, 109, 110, 111, 112, 113, 114, 126, 127, 144, 145, 158, 175, 176, 192, 198, 213, 214, 215, 216, 225, 231, 232, 233, 240]
population = [] population = []
# each field has unmutable locations of water and grass tiles
water_tile_indexes = [1, 2, 3, 34, 37, 44, 45, 53, 60, 61, 69, 81, 82, 83, 84, 119, 120, 121, 136, 152, 187, 194, 202, 203, 204, 210, 219, 226, 227, 228]
grass_tile_indexes = [0, 39, 40, 56, 71, 72, 73, 86, 88, 114, 115, 130, 146, 147, 163, 164, 166, 167, 180, 181, 182, 231, 232, 233]
vegetables = [x['Nazwa_warzywa'] for x in tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))]
for _ in range(10): for _ in range(100):
field = [vegetables[randint(0, 24)] for _ in range(256)] field = [vegetables[randint(0, 24)] for _ in range(256)]
for index in water_tile_indexes: for index in water_tile_indexes:
field[index] = "water" field[index] = "water"
for index in grass_tile_indexes:
field[index] = "grass"
# entities of the population are stored with two properties # entities of the population are stored with two properties
# the first being the average score of the field # the first being the average score of the field
# and the second being the layout of the field # and the second being the layout of the field
population.append([0, field]) population.append([0, field])
best = genetic_algorithm(population, 10) best = genetic_algorithm(population, 20)
print('final field layout', best[1]) print('\n=====\n\nfinal field multiplier score is', best[0])
print('final field multiplier score', best[0]) with open('field', 'w', encoding='utf-8') as file:
file.write(str(best[1]))
file.close
print('final field layout saved to file "field" in the current working directory\n')

View File

@ -370,7 +370,7 @@ tractor_kb([
"przeszkadza(burak, szpinak, 0.85)", "przeszkadza(burak, szpinak, 0.85)",
"przeszkadza(burak, ziemniak, 0.85)", "przeszkadza(burak, ziemniak, 0.85)",
"przeszkadza(cebula, fasola, 0.80)", "przeszkadza(cebula, fasola, 0.80)",
"przeszkadza(cebula, groch, 85)", "przeszkadza(cebula, groch, 0.85)",
"przeszkadza(cebula, kalafior, 0.70)", "przeszkadza(cebula, kalafior, 0.70)",
"przeszkadza(cebula, kapusta, 0.75)", "przeszkadza(cebula, kapusta, 0.75)",
"przeszkadza(cebula, marchew, 0.85)", "przeszkadza(cebula, marchew, 0.85)",

View File

@ -11,25 +11,26 @@ from PIL import Image
class Tile(pygame.sprite.Sprite): class Tile(pygame.sprite.Sprite):
def __init__(self, id, field): def __init__(self, id, field, tile_type):
super().__init__() super().__init__()
self.id = id self.id = id
x = id%16 x = id%16
y = id//16 y = id//16
self.field = field self.field = field
self.set_type(tile_type)
# temporary solution to have vegetables act as obstacles print('tile type set as', tile_type)
if random.randint(1, 10) % FREE_TILES == 0: if self.type == 'water':
vegetables = tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)")) self.stage = 'no_plant'
random_vegetable = vegetables[random.randint(0, len(vegetables)-1)]['Nazwa_warzywa'] self.prediction = 'water'
self.water_level = 100
if random_vegetable in {'cebula','pietruszka','bób', 'dynia','ziemniak'}: elif self.type == 'grass':
random_vegetable = 'marchew' self.stage = 'no_plant'
self.prediction = 'grass'
self.set_type(random_vegetable)
self.water_level = random.randint(1, 5) * 10 self.water_level = random.randint(1, 5) * 10
else:
self.stage = 'planted' # wczesniej to była self.faza = 'posadzono' ale stwierdzilem ze lepiej po angielsku??? self.stage = 'planted' # wczesniej to była self.faza = 'posadzono' ale stwierdzilem ze lepiej po angielsku???
self.water_level = random.randint(1, 5) * 10
classes = [ classes = [
"bób", "brokuł", "brukselka", "burak", "cebula", "bób", "brokuł", "brukselka", "burak", "cebula",
@ -51,20 +52,7 @@ class Tile(pygame.sprite.Sprite):
]) ])
self.prediction = self.predict(model, image_transforms, self.image_path, classes) self.prediction = self.predict(model, image_transforms, self.image_path, classes)
else:
if random.randint(1, 10) % 3 == 0:
self.set_type('water')
self.water_level = 100
self.stage = 'no_plant'
self.prediction = 'water'
else:
self.set_type('grass')
self.water_level = random.randint(1, 5) * 10
self.stage = 'no_plant'
self.prediction = 'grass'
self.rect = self.image.get_rect() self.rect = self.image.get_rect()
self.rect.topleft = (x * TILE_SIZE, y * TILE_SIZE) self.rect.topleft = (x * TILE_SIZE, y * TILE_SIZE)
@ -109,9 +97,6 @@ class Tile(pygame.sprite.Sprite):
result = classes[predicted.item()] result = classes[predicted.item()]
if result == "ziemniak":
result = 'marchew'
return result return result

View File

@ -165,8 +165,13 @@ class Tractor(pygame.sprite.Sprite):
self.move() self.move()
def decision_tree(self): def decision_tree(self):
action = self.make_decision() match (self.get_current_tile().type):
if (self.get_current_tile().type != 'grass' or self.get_current_tile().type == 'water'): action = 'nothing' case ('grass'):
action = self.make_decision()
case ('water'):
action = 'nothing'
case _:
action = 'water'
self.prev_action = action self.prev_action = action
print("Decyzja podjęta przez drzewo decyzyjne: ", action) print("Decyzja podjęta przez drzewo decyzyjne: ", action)
@ -180,7 +185,7 @@ class Tractor(pygame.sprite.Sprite):
case ('water'): case ('water'):
self.get_current_tile().water_level += 10 self.get_current_tile().water_level += 10
case ('plant(bób)'): case ('plant(bób)'):
self.get_current_tile().set_type('marchew') self.get_current_tile().set_type('bób')
case ('plant(brokuł)'): case ('plant(brokuł)'):
self.get_current_tile().set_type('brokuł') self.get_current_tile().set_type('brokuł')
case ('plant(brukselka)'): case ('plant(brukselka)'):
@ -188,11 +193,11 @@ class Tractor(pygame.sprite.Sprite):
case ('plant(burak)'): case ('plant(burak)'):
self.get_current_tile().set_type('burak') self.get_current_tile().set_type('burak')
case ('plant(cebula)'): case ('plant(cebula)'):
self.get_current_tile().set_type('marchew') self.get_current_tile().set_type('cebula')
case ('plant(cukinia)'): case ('plant(cukinia)'):
self.get_current_tile().set_type('cukinia') self.get_current_tile().set_type('cukinia')
case ('plant(dynia)'): case ('plant(dynia)'):
self.get_current_tile().set_type('fasola') self.get_current_tile().set_type('dynia')
case ('plant(fasola)'): case ('plant(fasola)'):
self.get_current_tile().set_type('fasola') self.get_current_tile().set_type('fasola')
case ('plant(groch)'): case ('plant(groch)'):
@ -212,7 +217,7 @@ class Tractor(pygame.sprite.Sprite):
case ('plant(papryka)'): case ('plant(papryka)'):
self.get_current_tile().set_type('papryka') self.get_current_tile().set_type('papryka')
case ('plant(pietruszka)'): case ('plant(pietruszka)'):
self.get_current_tile().set_type('marchew') self.get_current_tile().set_type('pietruszka')
case ('plant(pomidor)'): case ('plant(pomidor)'):
self.get_current_tile().set_type('pomidor') self.get_current_tile().set_type('pomidor')
case ('plant(por)'): case ('plant(por)'):

View File

@ -217,3 +217,41 @@ cebula,40,growing,szpinak,grass,kapusta,szpinak,move
cebula,50,growing,water,szpinak,kalarepa,grass,move cebula,50,growing,water,szpinak,kalarepa,grass,move
cebula,10,growing,szpinak,grass,marchew,grass,move cebula,10,growing,szpinak,grass,marchew,grass,move
cebula,20,growing,grass,cebula,burak,grass,move cebula,20,growing,grass,cebula,burak,grass,move
grass,10,no_plant,szpinak,dynia,szpinak,water,plant(seler)
grass,10,no_plant,marchew,dynia,grass,water,plant(seler)
grass,10,no_plant,water,dynia,cebula,cebula,plant(seler)
grass,10,no_plant,ogórek,dynia,cebula,grass,plant(seler)
grass,10,no_plant,szpinak,dynia,fasola,grass,plant(seler)
ziemniak,40,planted,water,grass,szpinak,grass,move
ziemniak,50,grown,szpinak,szpinak,grass,grass,move
ziemniak,10,planted,water,ziemniak,seler,water,move
ziemniak,20,planted,szpinak,szpinak,grass,seler,move
ziemniak,30,planted,grass,water,ziemniak,grass,move
ziemniak,40,planted,growing,grass,grass,burak,move
ziemniak,50,grown,growing,szpinak,water,grass,move
ziemniak,10,planted,growing,water,szpinak,marchew,move
ziemniak,20,planted,growing,szpinak,grass,kapusta,move
cukinia,50,grown,brukselka,water,grass,jarmuż,move
dynia,0,grown,burak,grass,pietruszka,kalafior,move
grass,10,grown,cebula,grass,pietruszka,kalarepa,move
grass,20,grown,cukinia,groch,pietruszka,kapusta,move
jarmuż,30,grown,grass,water,pietruszka,brokuł,move
kalafior,40,grown,fasola,pietruszka,water,brukselka,move
grass,10,grown,cebula,pietruszka,grass,kalarepa,move
grass,20,grown,cukinia,pietruszka,groch,kapusta,move
jarmuż,30,grown,grass,pietruszka,water,brokuł,move
kalafior,40,grown,fasola,kalafior,water,brukselka,move
bób,40,planted,jarmuż,grass,water,bób,move
brokuł,10,growing,kalafior,brokuł,bób,kalafior,move
brukselka,20,growing,water,brukselka,grass,bób,move
burak,30,planted,bób,burak,brukselka,bób,move
cebula,40,growing,brokuł,bób,burak,bób,move
cukinia,40,growing,grass,bób,water,grass,move
dynia,10,planted,grass,grass,cukinia,kalafior,move
grass,40,planted,jarmuż,grass,water,bób,move
grass,10,growing,kalafior,brokuł,bób,kalafior,move
grass,20,growing,water,bób,grass,bób,move
grass,30,planted,bób,burak,brukselka,bób,move
grass,40,growing,brokuł,bób,burak,bób,move
grass,40,growing,grass,bób,water,grass,move
grass,10,planted,bób,grass,cukinia,kalafior,move

1 tile_type water_level plant_stage neighbor_N neighbor_E neighbor_W neighbor_S action
217 cebula 50 growing water szpinak kalarepa grass move
218 cebula 10 growing szpinak grass marchew grass move
219 cebula 20 growing grass cebula burak grass move
220 grass 10 no_plant szpinak dynia szpinak water plant(seler)
221 grass 10 no_plant marchew dynia grass water plant(seler)
222 grass 10 no_plant water dynia cebula cebula plant(seler)
223 grass 10 no_plant ogórek dynia cebula grass plant(seler)
224 grass 10 no_plant szpinak dynia fasola grass plant(seler)
225 ziemniak 40 planted water grass szpinak grass move
226 ziemniak 50 grown szpinak szpinak grass grass move
227 ziemniak 10 planted water ziemniak seler water move
228 ziemniak 20 planted szpinak szpinak grass seler move
229 ziemniak 30 planted grass water ziemniak grass move
230 ziemniak 40 planted growing grass grass burak move
231 ziemniak 50 grown growing szpinak water grass move
232 ziemniak 10 planted growing water szpinak marchew move
233 ziemniak 20 planted growing szpinak grass kapusta move
234 cukinia 50 grown brukselka water grass jarmuż move
235 dynia 0 grown burak grass pietruszka kalafior move
236 grass 10 grown cebula grass pietruszka kalarepa move
237 grass 20 grown cukinia groch pietruszka kapusta move
238 jarmuż 30 grown grass water pietruszka brokuł move
239 kalafior 40 grown fasola pietruszka water brukselka move
240 grass 10 grown cebula pietruszka grass kalarepa move
241 grass 20 grown cukinia pietruszka groch kapusta move
242 jarmuż 30 grown grass pietruszka water brokuł move
243 kalafior 40 grown fasola kalafior water brukselka move
244 bób 40 planted jarmuż grass water bób move
245 brokuł 10 growing kalafior brokuł bób kalafior move
246 brukselka 20 growing water brukselka grass bób move
247 burak 30 planted bób burak brukselka bób move
248 cebula 40 growing brokuł bób burak bób move
249 cukinia 40 growing grass bób water grass move
250 dynia 10 planted grass grass cukinia kalafior move
251 grass 40 planted jarmuż grass water bób move
252 grass 10 growing kalafior brokuł bób kalafior move
253 grass 20 growing water bób grass bób move
254 grass 30 planted bób burak brukselka bób move
255 grass 40 growing brokuł bób burak bób move
256 grass 40 growing grass bób water grass move
257 grass 10 planted bób grass cukinia kalafior move