import copy import json import random from displayControler import NUM_X, NUM_Y # Definiowanie stałych dla roślin i plonów plants = ['corn', 'potato', 'tomato', 'carrot'] initial_yields = {'corn': 38, 'potato': 40, 'tomato': 43, 'carrot': 45} yield_reduction = { 'corn': {'corn': None, 'potato': -4, 'tomato': -2, 'carrot': -4}, 'potato': {'corn': None, 'potato': -5, 'tomato': -5, 'carrot': -2}, 'tomato': {'corn': -5, 'potato': -3, 'tomato': -7, 'carrot': None}, 'carrot': {'corn': -3, 'potato': -6, 'tomato': -4, 'carrot': -9} } yield_multiplier = {'corn': 1.25, 'potato': 1.19, 'tomato': 1.22, 'carrot': 1.15} # Generowanie listy 20x12 z losowo rozmieszczonymi roślinami def generate_garden(rows=20, cols=12): return [[random.choice(plants) for _ in range(cols)] for _ in range(rows)] # Funkcja do obliczania liczby plonów def calculate_yields(garden): rows = len(garden) cols = len(garden[0]) total_yields = 0 for i in range(rows): for j in range(cols): plant = garden[i][j] yield_count = initial_yields[plant] # Sprawdzanie sąsiadów neighbors = [ (i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1) ] neighbor_flag = False for ni, nj in neighbors: if 0 <= ni < rows and 0 <= nj < cols: neighbor_plant = garden[ni][nj] if yield_reduction[plant][neighbor_plant] is not None: # jeśli jest wartość None to plony dla tej rośliny będą wyzerowane yield_count += yield_reduction[plant][neighbor_plant] else: neighbor_flag = True if not neighbor_flag: yield_count *= yield_multiplier[plant] total_yields += yield_count return total_yields # Funkcja do generowania planszy/ogrodu i zapisywania go jako lista z liczbą plonów def generate_garden_with_yields(rows=NUM_Y, cols=NUM_X): garden = generate_garden(rows, cols) total_yields = calculate_yields(garden) return [garden, total_yields] # Funkcja do generowania linii cięcia i zapisywania jej jako liczba roślin w kolumnie z pierwszej planszy/ogrodu def line(): path = [] flag = False x = random.randint(4, 8) position = (0, x) path.append(position) while not flag: # wybór punktu dopóki nie wybierze się skrajnego # prawdopodobieństwo "ruchu" -> 0.6: w prawo, 0.2: w góre, 0.2: w dół p = [(position[0] + 1, position[1]), (position[0], position[1] + 1), (position[0], position[1] - 1)] w = [0.6, 0.2, 0.2] position2 = random.choices(p, w)[0] if position2 not in path: # sprawdzenie czy dany punkt nie był już wybrany aby nie zapętlać się path.append(position2) position = position2 if position[0] == NUM_X or position[1] == 0 or position[1] == NUM_Y: # sprawdzenie czy osiągnięto skrajny punkt flag = True info = [] # przeformatowanie sposobu zapisu na liczbę roślin w kolumnie, które będzię się dzidziczyło z pierwszej planszy/ogrodu for i in range(len(path) - 1): if path[i + 1][0] - path[i][0] == 1: info.append(NUM_Y - path[i][1]) if len(info) < NUM_X: # uzupełnienie informacji o dziedziczeniu z planszy/ogrodu if path[-1:][0][1] == 0: x = NUM_Y else: x = 0 while len(info) < NUM_X: info.append(x) # return path, info return info # Funkcja do generowania potomstwa def divide_gardens(garden1, garden2): info = line() new_garden1 = [[] for _ in range(NUM_Y)] new_garden2 = [[] for _ in range(NUM_Y)] for i in range(NUM_X): for j in range(NUM_Y): # do utworzonych kolumn w nowych planszach/ogrodach dodajemy dziedziczone rośliny if j < info[i]: new_garden1[j].append(garden1[j][i]) new_garden2[j].append(garden2[j][i]) else: new_garden1[j].append(garden2[j][i]) new_garden2[j].append(garden1[j][i]) return [new_garden1, calculate_yields(new_garden1)], [new_garden2, calculate_yields(new_garden2)] # Funkcja do mutacji danej planszy/ogrodu def mutation(garden, not_used): new_garden = copy.deepcopy(garden) for i in range(NUM_X): x = random.randint(0, 11) # wybieramy, w którym wierszu w i-tej kolumnie zmieniamy roślinę na inną other_plants = [plant for plant in plants if plant != new_garden[x][i]] new_garden[x][i] = random.choice(other_plants) return [new_garden, calculate_yields(new_garden)] # Funkcja do generowania pierwszego pokolenia def generate(n): generation = [] for i in range(n * 3): generation.append(generate_garden_with_yields()) generation.sort(reverse=True, key=lambda x: x[1]) return generation[:n] # Funkcja do implementacji ruletki (sposobu wyboru) - sumuje wszystkie plony generacji def sum_yields(x): s = 0 for i in range(len(x)): s += x[i][1] return s if __name__ == '__main__': roulette = True attemps = 20 iterat = 2500 population = 120 best = [] for a in range(attemps): generation = generate(population) print(generation[0][1]) for i in range(iterat): # ile iteracji - nowych pokoleń print(a, i) new_generation = generation[:(population // 7)] # dziedziczenie x najlepszych osobników j = 0 while j < ( population - ( population // 7)): # dobór reszty osobników do pełnej liczby populacji danego pokolenia if roulette: # zasada ruletki -> "2 rzuty kulką" s = sum_yields(generation) # suma wszystkich plnów całego pokolenia z = [] if s == 0: # wtedy każdy osobnik ma takie same szanse z.append(random.randint(0, population - 1)) z.append(random.randint(0, population - 1)) else: weights = [] # wagi prawdopodobieństwa dla każdego osobnika generacji pos = [] # numery od 0 do 49 odpowiadające numerom osobnikom w generacji for i in range(population): weights.append(generation[i][1] / s) pos.append(i) z.append(random.choices(pos, weights)[0]) # wybranie osobnika według wag prawdopodobieństwa z.append(random.choices(pos, weights)[0]) # wybranie osobnika według wag prawdopodobieństwa else: # metoda rankingu z = random.sample(range(0, int(population // 1.7)), 2) # krzyzowanie 90% szans, mutacja 10% szans function = [divide_gardens, mutation] weight = [0.9, 0.1] fun = random.choices(function, weight)[0] h = fun(generation[z[0]][0], generation[z[1]][0]) if len(h[0]) == 2: new_generation.append(h[0]) new_generation.append(h[1]) j += 2 else: new_generation.append(h) j += 1 new_generation.sort(reverse=True, key=lambda x: x[1]) # sortowanie malejąco listy według wartości plonów generation = new_generation[:population] best.append(generation[0]) best.sort(reverse=True, key=lambda x: x[1]) # Zapis do pliku # for i in range(len(best)): # print(best[i][1], calculate_yields(best[i][0])) # # # with open(f'pole2_pop{population}_iter{iterat}_{roulette}.json', 'w') as file: # zapis planszy/ogrodu do pliku json # json.dump(best[0][0], file, indent=4) # # print("Dane zapisane do pliku") # # Odczyt z pliku # with open(f'pole2_pop{population}_iter{iterat}_{roulette}.json', 'r') as file: # garden_data = json.load(file) # # print("Odczytane dane ogrodu:") # for row in garden_data: # print(row) # # print(calculate_yields(garden_data)) # if best[0][0] == garden_data: # print("POPRAWNE: ", calculate_yields(garden_data), calculate_yields(best[0][0]))