genetic algorithm with decision tree in progress
This commit is contained in:
parent
fe3f9bf4fe
commit
5b89648f69
@ -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
215
src/agent/ga_chromosome.py
Normal 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
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user