Compare commits

..

No commits in common. "main" and "klikanie-drzewo" have entirely different histories.

10 changed files with 82 additions and 106 deletions

1
.gitignore vendored
View File

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

3
.vscode/extensions.json vendored Normal file
View File

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

View File

@ -8,8 +8,6 @@ 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:
@ -27,6 +25,10 @@ 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
``` ```
@ -35,12 +37,9 @@ 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)

View File

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

View File

@ -1,16 +1,13 @@
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()
with open('./field', 'r', encoding='UTF-8') as file: # TODO: enable resizing field grid from 16x16 to any size
content = file.read() for x in range(256):
tiles = literal_eval(content) self.tiles.add(Tile(x, self))
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,7 +1,6 @@
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):
@ -18,32 +17,33 @@ 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])
mod = multi_sasiedzi(field[index], neighbours)[0]["Mul"] score += 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):
total_weights = sum(entity[0] for entity in population) weights = [x[0] for x in population]
weights_sum = 0
for weight in weights:
weights_sum += weight
weights = [entity[0] / total_weights for entity in population] weights = [weight/weights_sum for weight in weights]
selection = npchoice(len(population), size=2, replace=False, p=weights) mom = choices(population, cum_weights=weights, k=1)[0]
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]
parents = [population[i] for i in selection] return mom, dad
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 length is not equal to mom length") ValueError("offspring lenght 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,7 +57,6 @@ 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]
@ -74,10 +73,9 @@ 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 iteration in range(iterations): for _ in range(iterations):
population.sort(key=lambda x: x[0], reverse=True) population.sort(key=lambda x: x[0], reverse=True)
print('\n=====\n\n💪 Best individual in iteration', iteration, 'has a score of', population[0][0]) population = population[:5]
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:
@ -90,27 +88,36 @@ def genetic_algorithm(population, iterations):
return population[0] return population[0]
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)"))] 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 = []
for _ in range(100): for _ in range(10):
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, 20) best = genetic_algorithm(population, 10)
print('\n=====\n\nfinal field multiplier score is', best[0]) print('final field layout', best[1])
with open('field', 'w', encoding='utf-8') as file: print('final field multiplier score', best[0])
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, 0.85)", "przeszkadza(cebula, groch, 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,26 +11,25 @@ from PIL import Image
class Tile(pygame.sprite.Sprite): class Tile(pygame.sprite.Sprite):
def __init__(self, id, field, tile_type): def __init__(self, id, field):
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)
print('tile type set as', tile_type) # temporary solution to have vegetables act as obstacles
if self.type == 'water': if random.randint(1, 10) % FREE_TILES == 0:
self.stage = 'no_plant' vegetables = tractor_kb.query(pl.Expr("warzywo(Nazwa_warzywa)"))
self.prediction = 'water' random_vegetable = vegetables[random.randint(0, len(vegetables)-1)]['Nazwa_warzywa']
self.water_level = 100
elif self.type == 'grass': if random_vegetable in {'cebula','pietruszka','bób', 'dynia','ziemniak'}:
self.stage = 'no_plant' random_vegetable = 'marchew'
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",
@ -52,7 +51,20 @@ 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)
@ -97,6 +109,9 @@ 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,13 +165,8 @@ class Tractor(pygame.sprite.Sprite):
self.move() self.move()
def decision_tree(self): def decision_tree(self):
match (self.get_current_tile().type): action = self.make_decision()
case ('grass'): if (self.get_current_tile().type != 'grass' or self.get_current_tile().type == 'water'): action = 'nothing'
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)
@ -185,7 +180,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('bób') self.get_current_tile().set_type('marchew')
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)'):
@ -193,11 +188,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('cebula') self.get_current_tile().set_type('marchew')
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('dynia') self.get_current_tile().set_type('fasola')
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)'):
@ -217,7 +212,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('pietruszka') self.get_current_tile().set_type('marchew')
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,41 +217,3 @@ 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
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