Skip to content

Commit

Permalink
Co-authored-by: Håvard Fossdal <[email protected]>
Browse files Browse the repository at this point in the history
Co-authored-by: oystkva <[email protected]>
feat: added methods geneticAlgoritm
  • Loading branch information
SFossdal authored and oystkva committed Apr 29, 2024
1 parent 98b33b4 commit 03789ff
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 34 deletions.
11 changes: 11 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
from src.agents.heuristic import (
utility
)

from src.agents.heuristic_trainer import train
from src.agents.geneticAlgAgentJon import GeneticAlgAgentJM


def test():
# algAgent = GeneticAlgAgentJM()
# algAgent.number_of_selection(2)
Expand Down Expand Up @@ -35,6 +37,7 @@ def test():
# print(utility(boards, 0, -1, 0, 0, 0))
# boards.printBoard()

<<<<<<< HEAD
# board = Tetris()
# manager = TetrisGameManager(board)
# agent = create_agent("heuristic")
Expand All @@ -57,3 +60,11 @@ def test():
#train()

>>>>>>> c14418b (feat: :rocket: genetic agent class and it's training algorithm commenced)
=======
board = Tetris()
# manager = TetrisGameManager(board)
# agent = create_agent("heuristic")
agents = train_genetic_algorithm(10)

# manager.startDemo(agent)
>>>>>>> fa9eeb9 (Co-authored-by: Håvard Fossdal <HFossdal@users.noreply.github.com>)
93 changes: 71 additions & 22 deletions src/agents/geneticAlgAgent.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
# TODO Create a fitness function
# TODO Create a genetic algorithm based on the
import random
import numpy as np
import operator
from math import sqrt
from src.agents.agent import Agent, play_game
from src.game.tetris import Action, Tetris, transition_model, get_all_actions
from src.agents.heuristic import utility


class geneticAgent(Agent):
class GeneticAgent(Agent):

NUMBER_OF_GAMES = 10

def __init__(self):
self.weight_vector = [random.uniform(-2.00, 2.00) for _ in range(4)]
self.weight_vector = [random.uniform(-2.00, 2.00) for _ in range(5)]

def result(self, board: Tetris) -> list[Action]:
possible_boards = board.getPossibleBoards()
Expand Down Expand Up @@ -52,33 +54,74 @@ def _fitness(self, board: Tetris) -> float:
return fitness

def _normalize_weights(self):
self.weight_vector = sqrt(sum([v**2 for v in self.get_weight_vector()]))
## TODO: Fix this function

self.weight_vector = [x/sqrt(sum([i**2 for i in self.weight_vector])) for x in self.weight_vector]


def mutate_child(self):
for i in range(5):
if random.random() < 0.05:
self.get_weight_vector()[i] += random.uniform(-0.20, 0.20)

def _crossover(self, parent1: geneticAgent, parent2: geneticAgen) -> geneticAgent:
for i in range(len(parent1)):
self.weight_vector[i] = ((parent1[i]*parent1.get_weight_vector()[i] + parent2[i]*parent2.get_weight_vector()[i]))
def _crossover(self, parent1: tuple[float, 'GeneticAgent'], parent2:
tuple[float, 'GeneticAgent'] ) -> None:
for i in range(len(self.get_weight_vector())):
self.weight_vector[i] = ((parent1[0]*parent1[1].get_weight_vector()[i] + parent2[0]*parent2[1].get_weight_vector()[i]))





def average_weight_values(agents: list[float, GeneticAgent]) -> float:
sum_of_weights = 0
for agent in agents:
sum_of_weights += sum(agent[1].get_weight_vector())/len(agent[1].get_weight_vector())
return sum_of_weights/len(agents)



def train_genetic_algorithm(init_population_size: int) -> list[tuple[float, geneticAgent]]:
def train_genetic_algorithm(init_population_size: int, tol = 1e-6) -> list[tuple[float, GeneticAgent]]:
candidates = [] # List of genetic agents on the form (fitness, agent)

for _ in range(init_population_size):
candidate = geneticAgent()
candidate_fitness = np.array([])

print("Starting genetic algorithm")
for i in range(init_population_size):
print("Creating candidate ", i)
candidate = GeneticAgent()
board = Tetris()
fitness = candidate._fitness(board)
candidates.append((fitness, candidate))
# Sort the candidates based on their fitness
print("Initial population done")
child_candidates = []

while len(child_candidates) < 0.3*init_population_size:
random_indices = select_random_parents(init_population_size)
parent_candidates = []
for i in random_indices:
parent_candidates.append(candidates[i])
parent_candidates.sort(reverse=True)
child_candidates.append(make_offspring(board, parent_candidates[0], parent_candidates[1]))
tolerance = average_weight_values(candidates)
iterations = 0
print("Starting iterations")
while abs(tolerance) > tol:
iterations += 1
print("Tolerance: ", tolerance)
print("Starting new generation")
while len(child_candidates) < 0.3*init_population_size:
random_indices = select_random_parents(init_population_size)
parent_candidates = []
for i in random_indices:
parent_candidates.append((candidates[i][0], candidates[i][1]))
parent_candidates = sorted(parent_candidates, key=operator.itemgetter(0), reverse=True)
print(len(parent_candidates))
child_tuple = make_offspring(board, parent_candidates[0], parent_candidates[1])
child_candidates.append((child_tuple))
tolerance = average_weight_values(candidates)
candidates = sorted(candidates, key=operator.itemgetter(0), reverse=True)
candiates = candiates[:init_population_size*0.7+1]
for child in child_candidates:
candidates.append(child)
tolerance -= average_weight_values(candidates)
print("Generation done")
print("-------------------")
print(iterations, " iterations done")
candidates = sorted(candidates, key=operator.itemgetter(0), reverse=True)
print("Best candidates weights: [", candidate[0].get_weight_vector()[0], ", ", candidate[0].get_weight_vector()[1], ", ", candidate[0].get_weight_vector()[2], ", ", candidate[0].get_weight_vector()[3], "]")

return candidates

Expand All @@ -92,19 +135,25 @@ def select_random_parents(init_population_size: int) -> list[int]:
list of indices of unique selected agents.
"""
random_selection = []
while len(random_selection) < (init_population_size/10):
while len(random_selection) < max(2, init_population_size/10):
random_index = random.randint(0, init_population_size - 1)
if random_index not in random_selection:
random_selection.append(random_index)
return random_selection



def make_offspring(board: Tetris, parent1: tuple[float, geneticAgent], parent2: tuple[float, geneticAgent]) -> tuple[float, geneticAgent]:
child = geneticAgent()
def make_offspring(board: Tetris, parent1: tuple[float, GeneticAgent], parent2: tuple[float, GeneticAgent]) -> tuple[float, GeneticAgent]:
child = GeneticAgent()
child.weight_vector = child._crossover(parent1, parent2)
child.mutate_child()
child._normalize_weights()
child_fitness = child._fitness(board)

return (child_fitness, child)


# def mutate_child(child: geneticAgent) -> geneticAgent:
# for i in range(len(child.get_weight_vector())):
# if random.random() < 0.05:
# child.get_weight_vector()[i] += random.uniform(-0.20, 0.20)
# return child
13 changes: 1 addition & 12 deletions src/agents/heuristic_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,5 @@ def result(self, board: Tetris) -> list[Action]:

# Find the actions needed to transform the current board to the new board
actions = []
<<<<<<< HEAD
actions = transition_model(board, best_board)
return actions

=======
try:
actions = transition_model(board, best_board)
return actions
except:
return actions


>>>>>>> c14418b (feat: :rocket: genetic agent class and it's training algorithm commenced)
return actions

0 comments on commit 03789ff

Please sign in to comment.