First steps in GA
This commit is contained in:
parent
264aa2969c
commit
30e1db94bf
94
src/AI/GA.py
Normal file
94
src/AI/GA.py
Normal file
@ -0,0 +1,94 @@
|
||||
import random
|
||||
import numpy
|
||||
|
||||
from src.AI.Affinities import Affinities
|
||||
from src.entities.Enums import Classifiers
|
||||
from src.entities.Player import Player
|
||||
|
||||
|
||||
def geneticAlgorithm(map, iter, solutions):
|
||||
"""
|
||||
This algorithm will attempt to find the best affinities for player's goal choices.
|
||||
|
||||
:param map: Map with all entities
|
||||
:param iter: Generations count
|
||||
:param solutions: Solutions per generation
|
||||
"""
|
||||
# Based on 4 weights, that are affinities tied to the player
|
||||
weightsCount = 4
|
||||
populationSize = (solutions, weightsCount)
|
||||
|
||||
# Initialize the first population with random values
|
||||
initialPopulation = numpy.random.uniform(low=0.0, high=1.0, size=populationSize)
|
||||
population = initialPopulation
|
||||
for i in range(iter):
|
||||
fitness = []
|
||||
for player in population:
|
||||
fitness.append(doSimulation(player, map))
|
||||
|
||||
|
||||
def doSimulation(weights, map):
|
||||
"""
|
||||
Runs the simulation. Returns fitness.
|
||||
|
||||
:param weights: A list of weights for players.
|
||||
:param map: Map object
|
||||
"""
|
||||
player = Player((6, 2), map.tileSize, Affinities(weights[0], weights[1], weights[2], weights[3]))
|
||||
player.disableMovementTime()
|
||||
while player.alive:
|
||||
if player.movementTarget is None:
|
||||
target = pickEntity(player, map)
|
||||
player.gotoToTarget(target, map)
|
||||
player.update()
|
||||
fitness = player.movePoints
|
||||
player.kill()
|
||||
del player
|
||||
map.respawn()
|
||||
print(fitness)
|
||||
return fitness
|
||||
|
||||
|
||||
def pickEntity(player, map):
|
||||
"""
|
||||
Select an entity to become the next goal for the player. The entity is determined by
|
||||
player's affinities and the distances between the player and entities.
|
||||
|
||||
:param player: Player object
|
||||
:param map: Map object
|
||||
:type map: Map
|
||||
:type player: Player
|
||||
"""
|
||||
foods = map.getInteractablesByClassifier(Classifiers.FOOD)
|
||||
waters = map.getInteractablesByClassifier(Classifiers.WATER)
|
||||
rests = map.getInteractablesByClassifier(Classifiers.REST)
|
||||
|
||||
walkingAffinity = player.affinities.walking
|
||||
weights = player.affinities.getWeigths()
|
||||
# Determine the weight of all entities based on the formula:
|
||||
# typeWeight * (walkingAffinity / distance to entity) / affectedStat
|
||||
foodsWeights = []
|
||||
hunger = player.statistics.hunger
|
||||
for food in foods:
|
||||
distance = abs(player.x - food.x) + abs(player.y - food.y)
|
||||
typeWeight = weights[0]
|
||||
foodsWeights.append((typeWeight * (walkingAffinity / distance)) * hunger)
|
||||
|
||||
watersWeights = []
|
||||
thirst = player.statistics.thirst
|
||||
for water in waters:
|
||||
distance = abs(player.x - water.x) + abs(player.y - water.y)
|
||||
typeWeight = weights[1]
|
||||
watersWeights.append((typeWeight * (walkingAffinity / distance)) * thirst)
|
||||
|
||||
restsWeights = []
|
||||
stamina = player.statistics.stamina
|
||||
for rest in rests:
|
||||
distance = abs(player.x - rest.x) + abs(player.y - rest.y)
|
||||
typeWeight = weights[2]
|
||||
restsWeights.append((typeWeight * (walkingAffinity / distance)) / stamina)
|
||||
|
||||
finalEntities = foods + waters + rests
|
||||
finalWeights = foodsWeights + watersWeights + restsWeights
|
||||
|
||||
return random.choices(finalEntities, finalWeights)[0]
|
Loading…
Reference in New Issue
Block a user