genetic algorithm with decision tree in progress

This commit is contained in:
tubks 2021-06-16 03:45:23 +02:00
parent fe3f9bf4fe
commit 5b89648f69
3 changed files with 225 additions and 6 deletions

View File

@ -5,7 +5,7 @@ from mesa.visualization.ModularVisualization import ModularServer
#from src.decisiontree import create_model #from src.decisiontree import create_model
from src.direction import Direction from src.direction import Direction
from collections import defaultdict from collections import defaultdict
import src.agent.ga_chromosome as ga
def player_representation(agent): def player_representation(agent):
portrayal = {"Shape": "sprites/heroE.png", portrayal = {"Shape": "sprites/heroE.png",
@ -55,10 +55,10 @@ class PlayerStats(TextElement):
# return model.player.describe_situation(model.player.opponent, model.player.strategy) # return model.player.describe_situation(model.player.opponent, model.player.strategy)
# else: # else:
# return "Not fighting" # return "Not fighting"
ga.create_model()
server = ModularServer(GameMap, server = ModularServer(GameMap,
[grid,PlayerStats()], [grid,PlayerStats()],
"Map", "Map",
{"x": 10, "y": 10}) {"x": 10, "y": 10})
#create_model()
server.port = 8081 server.port = 8081
server.launch() server.launch()

215
src/agent/ga_chromosome.py Normal file
View File

@ -0,0 +1,215 @@
import numpy.random
import random
import pandas as pd
import os
import rpy2.robjects as robjects
from rpy2.robjects.packages import importr
from rpy2.robjects import pandas2ri
from rpy2.robjects.conversion import localconverter
from rpy2.robjects.packages import importr
from src.nominalize import nominalize
from src.decisiontree import create_model
MAX_COMBAT_TIME = 20
attack_types=["MELEE", "RANGED","MAGIC"]
class EnemyStats:
def __init__(self):
self.strength = random.randint(1, 7)
self.agility = random.randint(1, 7)
self.wisdom = random.randint(1, 7)
self.max_health = random.randint(5, 30)
self.health=self.max_health
self.melee_wep_damage = 1
self.ranged_wep_damage = 1
self.magic_wep_damage = 2
self.armor_defence = 0
self.armor_magic_protection = 1
self.attack_type=random.choice(attack_types)
def meleeAttack(self, opponent):
attackValue = self.strength + random.randint(1, 6)
defenseValue = opponent.strength + opponent.armor_defence
damage = attackValue - defenseValue
if damage > 0:
opponent.health -= (damage + self.melee_wep_damage)
def rangeAttack(self, opponent):
attackValue = self.agility + random.randint(1, 6)
defenseValue = opponent.agility
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.ranged_wep_damage - opponent.armor_defence > 0):
opponent.health -= (damage + self.ranged_wep_damage - opponent.armor_defence)
def magicAttack(self, opponent):
attackValue = self.wisdom + random.randint(1, 6)
defenseValue = opponent.wisdom
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.magic_wep_damage - opponent.armor_magic_protection > 0):
opponent.health -= (damage + self.magic_wep_damage - opponent.armor_magic_protection)
def reset(self):
self.health = self.max_health
def try_combat(my_seed, p, e, player_att_type, enemy_att_type):
random.seed(my_seed)
current_iteration = 0
while True:
if player_att_type == 0:
p.meleeAttack(e)
elif player_att_type == 1:
p.rangeAttack(e)
else:
p.magicAttack(e)
if e.health<=0:
return p.health
if enemy_att_type == 0:
e.meleeAttack(p)
elif enemy_att_type == 1:
e.rangeAttack(p)
else:
e.magicAttack(p)
if p.health<=0:
return 0
current_iteration += 1
if current_iteration >= MAX_COMBAT_TIME:
return 0
p.reset()
e.reset()
class PlayerStats(EnemyStats):
def __init__(self, s, a, w):
self.strength = 1+s
self.agility = 1+a
self.wisdom = 1+w
self.max_health = 50
self.health = 50
self.melee_wep_damage = 1
self.ranged_wep_damage = 1
self.magic_wep_damage = 2
self.armor_defence = 0
self.armor_magic_protection = 0
def predict_strategy(self, opponent):
testcase = pd.DataFrame({'p_strength': nominalize(self.strength,7),
'p_agility':nominalize(self.agility, 7),
'p_wisdom':nominalize(self.wisdom,7),
'p_health':nominalize(self.health,50),
'p_melee_damage':nominalize(self.melee_wep_damage, 10),
'p_ranged_damage':nominalize(self.ranged_wep_damage,10),
'p_magic_damage':nominalize(self.magic_wep_damage,10),
'p_armor_defence':nominalize(self.armor_defence,5),
'p_armor_magic_protection':nominalize(self.armor_magic_protection,5),
'e_strength':nominalize(opponent.strength, 10),
'e_agility':nominalize(opponent.agility, 10),
'e_wisdom':nominalize(opponent.wisdom,10),
'e_health':nominalize(opponent.health, 50),
'e_damage':nominalize(opponent.melee_wep_damage,10),
'e_armor_defence':nominalize(opponent.armor_defence, 5),
'e_armor_magic_protection':nominalize(opponent.armor_magic_protection, 5),
'e_attack_type':opponent.attack_type.upper(),
'strategy':"PASS"}, index=[1])
with localconverter(robjects.default_converter + pandas2ri.converter):
r_dataframe = robjects.conversion.py2rpy(testcase)
robjects.globalenv['r_dataframe']=r_dataframe
result=robjects.r('predict(fights.id3, r_dataframe)')
return result[0]
def fitness_function(chromosome):
s=chromosome.count(1)
a=chromosome.count(2)
w=chromosome.count(3)
p=PlayerStats(s, a, w)
# wins=[0,0,0]
# current_seed=os.urandom(16)
# for i in range(3):
# random.seed(current_seed)
# while p.health>0:
# e=EnemyStats()
# try_combat(current_seed, p, e, i, e.attack_type) #walka iles razy
# if p.health>0:
# wins[i]+=1
# p.reset()
# return max(wins)
wins=0
while p.health > 0:
e=EnemyStats()
player_attack=p.predict_strategy(e)
try_combat(os.urandom(16), p, e, attack_types.index(player_attack), attack_types.index(e.attack_type)) #walka iles razy
if p.health>0:
wins+=1
return wins
# tournament selection
def selection(pop, scores, k=3):
# first random selection
selection_ix = numpy.random.randint(len(pop))
for ix in numpy.random.randint(0, len(pop), k-1):
# check if better (e.g. perform a tournament)
if scores[ix] > scores[selection_ix]:
selection_ix = ix
return pop[selection_ix]
# crossover two parents to create two children
def crossover(p1, p2, r_cross):
# children are copies of parents by default
c1, c2 = p1.copy(), p2.copy()
# check for recombination
if numpy.random.rand() < r_cross:
# select crossover point that is not on the end of the string
pt = numpy.random.randint(1, len(p1)-2)
# perform crossover
c1 = p1[:pt] + p2[pt:]
c2 = p2[:pt] + p1[pt:]
return [c1, c2]
# mutation operator
def mutation(bitstring, r_mut):
for i in range(len(bitstring)):
# check for a mutation
if numpy.random.rand() < r_mut:
# flip the bit
bitstring[i] = random.randint(1,4)
# genetic algorithm
def genetic_algorithm(objective, n_bits, n_iter, n_pop, r_cross, r_mut):
# initial population of random bitstring
pop = [numpy.random.randint(1, 4, n_bits).tolist() for _ in range(n_pop)] # tworzy sie lista n_pop list szesciocyfrowych
# keep track of best solution
best, best_eval = 0, objective(pop[0])
# enumerate generations
for gen in range(n_iter):
# evaluate all candidates in the population
scores = [objective(c) for c in pop]
# check for new best solution
for i in range(n_pop):
if scores[i] > best_eval:
best, best_eval = pop[i], scores[i]
print(">%d, new best f(%s) = %d" % (gen, pop[i], scores[i]))
# select parents
selected = [selection(pop, scores) for _ in range(n_pop)]
# create the next generation
children = list()
for i in range(0, n_pop, 2):
# get selected parents in pairs
p1, p2 = selected[i], selected[i+1]
# crossover and mutation
for c in crossover(p1, p2, r_cross):
# mutation
mutation(c, r_mut)
# store for next generation
children.append(c)
# replace population
pop = children
return [best, best_eval]
# define the total iterations
n_iter = 10
# bits
n_bits = 6
# define the population size
n_pop = 20
# crossover rate
r_cross = 0.9
# mutation rate
r_mut = 0.05

View File

@ -1,6 +1,6 @@
from mesa import Model from mesa import Model
from mesa.datacollection import DataCollector from mesa.datacollection import DataCollector
import src.agent.ga_chromosome as ga
from src.agent.hero import Player from src.agent.hero import Player
from src.agent.model.dice.dice import roll_the_dice from src.agent.model.dice.dice import roll_the_dice
@ -30,7 +30,11 @@ class GameMap(Model):
self.boxes_number = boxes_number self.boxes_number = boxes_number
self.creatures_number = creatures_number self.creatures_number = creatures_number
self.running = True self.running = True
self.player = Player(1000, self, "Janusz", 5, 5, 5, 50, 50, WM1, A1, 0, WR1, S1, self.listOfChests) best, score = ga.genetic_algorithm(ga.fitness_function, ga.n_bits, ga.n_iter, ga.n_pop, ga.r_cross, ga.r_mut)
s=1+best.count(1)
a=1+best.count(2)
w=1+best.count(3)
self.player = Player(1000, self, "Janusz", s, a, w, 50, 50, WM1, A1, 0, WR1, S1, self.listOfChests)
self.schedule.add(self.player) self.schedule.add(self.player)
x = self.random.randrange(self.grid.width) x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height) y = self.random.randrange(self.grid.height)
@ -51,7 +55,7 @@ class GameMap(Model):
self.boxes_number + self.creatures_number-20): # taki range, żeby każdy agent miał poprawne unique_id self.boxes_number + self.creatures_number-20): # taki range, żeby każdy agent miał poprawne unique_id
# creature = Creature(i, self) # creature = Creature(i, self)
creature = Creature(i, self, "Goblin", creature = Creature(i, self, "Goblin",
roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), 15, roll_the_dice(3),
WM2, A2, roll_the_dice(5)) WM2, A2, roll_the_dice(5))
x = self.random.randrange(self.grid.width) x = self.random.randrange(self.grid.width)
@ -63,7 +67,7 @@ class GameMap(Model):
pass pass
for i in range(self.boxes_number + self.creatures_number-20, self.creatures_number): # taki range, żeby każdy agent miał poprawne unique_id for i in range(self.boxes_number + self.creatures_number-20, self.creatures_number): # taki range, żeby każdy agent miał poprawne unique_id
creature = Creature(i, self, "Skeleton", creature = Creature(i, self, "Skeleton",
roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), 15, roll_the_dice(7),
WR4, A8, roll_the_dice(10)) WR4, A8, roll_the_dice(10))
x = self.random.randrange(self.grid.width) x = self.random.randrange(self.grid.width)