Merge branch 'joarad'

This commit is contained in:
tubks 2021-06-22 22:21:20 +02:00
commit 1494a717f6
52 changed files with 1156 additions and 548 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.idea

View File

@ -1,69 +0,0 @@
#Funkcja konwertujaca wspolrzedne nastepnego pola do odwiedzenia
#na kolejke akcji do wykonania
# tl - turn left, tr - turn right, fwd - forward, op - open
#queue - kolejka akcji do zrobienia, pole klasy Player
#path - kolejka pol do odwiedzenia, pole klasy Player
#pole to element wziety z kolejki path
def actionPlanner(self,pole):
x0 = self.pos[0]
y0 = self.pos[1]
x = pole[0]
y = pole[1]
if (x > x0):
if (self.direction == 1):
self.queue.insert("fwd")
elif (self.direction == 0):
self.queue.insert("tr")
self.queue.insert("fwd")
elif (self.direction == 2):
self.queue.insert("tl")
self.queue.insert("fwd")
else:
self.queue.insert("tr")
self.queue.insert("tr")
self.queue.insert("fwd")
elif (x < x0):
if (self.direction == 3):
self.queue.insert("fwd")
elif (self.direction == 0):
self.queue.insert("tl")
self.queue.insert("fwd")
elif (self.direction == 2):
self.queue.insert("tr")
self.queue.insert("fwd")
else:
self.queue.insert("tr")
self.queue.insert("tr")
self.queue.insert("fwd")
else:
if (y > y0):
if (self.direction == 0):
self.queue.insert("fwd")
elif (self.direction == 1):
self.queue.insert("tl")
self.queue.insert("fwd")
elif (self.direction == 3):
self.queue.insert("tr")
self.queue.insert("fwd")
else:
self.queue.insert("tr")
self.queue.insert("tr")
self.queue.insert("fwd")
else:
if (self.direction == 2):
self.queue.insert("fwd")
elif (self.direction == 3):
self.queue.insert("tl")
self.queue.insert("fwd")
elif (self.direction == 1):
self.queue.insert("tr")
self.queue.insert("fwd")
else:
self.queue.insert("tr")
self.queue.insert("tr")
self.queue.insert("fwd")
if (self.path.empty()):
self.queue.insert("op")

319
hero.py
View File

@ -1,319 +0,0 @@
from mesa import Agent
from othercharacters import dice, Box, Creature, Armor, Weapon
class Player(Creature):
def __init__(self, unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g, w2, w3):
super().__init__(unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g)
self.name = n
self.strength = s
self.agility = a
self.wisdom = w
self.maxHealth = maxhp
self.health = hp
self.gold = g
self.weapon1 = weap
self.weapon2 = w2
self.weapon3 = w3
self.armor = arm
self.isBox = False
self.isCreature = False
self.directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
self.direction = 0
self.queue=[]
self.hasgoalchest=False
self.openedchests=0
def rotate(self, clockwise=True):
if clockwise:
self.direction = (self.direction + 1) % 4
else:
self.direction = (self.direction + 3) % 4
def moveFwd(self):
possible_steps = self.model.grid.get_neighborhood(
self.pos,
moore=False,
include_center=False)
new_position = (self.pos[0] + self.directions[self.direction][0],
self.pos[1] + self.directions[self.direction][1])
if new_position in possible_steps:
self.model.grid.move_agent(self, new_position)
print("moved to ", new_position)
# def move(self): # OLD
# possible_steps = self.model.grid.get_neighborhood(
# self.pos,
# moore=True,
# include_center=False)
# new_position = self.random.choice(possible_steps)
# self.model.grid.move_agent(self, new_position)
def meleeAttack(self, opponent):
attackValue = self.strength + dice(6)
defenseValue = opponent.strength + opponent.armor.defence
damage = attackValue - defenseValue
if damage > 0:
opponent.health = opponent.health - (damage + self.weapon1.damage)
def rangeAttack(self, opponent):
attackValue = self.agility + dice(6)
defenseValue = opponent.agility
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.weapon2.damage - opponent.armor.defence > 0):
opponent.health = opponent.health - (damage + self.weapon2.damage - opponent.armor.defence)
def magicAttack(self, opponent):
attackValue = self.wisdom + dice(6)
defenseValue = opponent.wisdom
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.weapon3.damage - opponent.armor.mag_protection > 0):
opponent.health = opponent.health - (damage + self.weapon3.damage - opponent.armor.mag_protection)
def fightOrFlight(self, opponent):
combat = True
while combat:
choice = dice(4)
print("dice rolled:", choice)
if choice == 1:
running_speed = self.agility + dice(6)
opponent_speed = opponent.agility + dice(6)
if running_speed > opponent_speed:
combat = False
print("Player ran away")
self.step()
else:
opponent.defaultAttack(self)
if self.health <= 0:
combat = False
print("Player died :/")
elif choice == 2:
self.meleeAttack(opponent)
if opponent.health > 0:
opponent.defaultAttack(self)
if self.health <= 0:
combat = False
print("Player died :/")
else:
combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
elif choice == 3:
self.rangeAttack(opponent)
if opponent.health > 0:
opponent.defaultAttack(self)
if self.health <= 0:
combat = False
print("Player died :/")
else:
combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
else:
self.magicAttack(opponent)
if opponent.health > 0:
opponent.defaultAttack(self)
if self.health <= 0:
combat = False
print("Player died :/")
else:
combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
def openChest(self, chest):
self.gold = self.gold + chest.gold
print("Chest opened. Gold inside:", chest.gold)
chest.gold = 0
self.openedchests+=1
self.hasgoalchest=False
chest.model.grid.remove_agent(chest)
self.direction=0 #po osiągnięciu jednego celu 'restartuje sie' na szukanie ścieżki do kolejnego
# if isinstance(chest.loot,Armor):
# buffer = self.armor
# self.armor = chest.loot
# chest.loot = buffer
# if isinstance(chest.loot,Weapon):
# if chest.loot.type == "Melee":
# buffer = self.weapon1
# self.weapon1 = chest.loot
# chest.loot = buffer
# elif chest.loot.type == "Range":
# buffer = self.weapon2
# self.weapon2 = chest.loot
# chest.loot = buffer
# elif chest.loot.type == "Magic":
# buffer = self.weapon3
# self.weapon3 = chest.loot
# chest.loot = buffer
def findShortestPathToTarget(self):
visited = []
precedessors = {}
queue = [self.pos]
found_target = False
while queue:
cur_pos = queue.pop(0)
#check for target
cell_contents = self.model.grid.get_cell_list_contents([cur_pos])
if cell_contents and any([isinstance(thing, Box) for thing in cell_contents]):
found_target = cur_pos
self.hasgoalchest=True
break
#enqueue safe unvisited neighbours
neighbours = self.model.grid.get_neighborhood(
cur_pos,
moore=False,
include_center=False)
for cell in neighbours:
#if cell hasn't been visited and the contents don't include creatures
if cell not in visited and not any([isinstance(thing, Creature) for thing in self.model.grid.get_cell_list_contents([cell])]):
queue.append(cell)
precedessors[cell] = cur_pos
visited.append(cur_pos)
if found_target:
path = [found_target]
while True:
if path[0] == self.pos:
break
precedessor = precedessors[path[0]]
path.insert(0, precedessor)
return path
return "no chests left"
# Funkcja konwertujaca wspolrzedne nastepnego pola do odwiedzenia
# na kolejke akcji do wykonania
# tl - turn left, tr - turn right, fwd - forward, op - open
# queue - kolejka akcji do zrobienia, pole klasy Player
# path - kolejka pol do odwiedzenia, pole klasy Player
# pole to element wziety z kolejki path
def actionPlanner(self, cell_from, cell_to):
x0 = cell_from[0]
y0 = cell_from[1]
x = cell_to[0]
y = cell_to[1]
if (x > x0):
if (self.direction == 1):
self.queue.append("fwd")
elif (self.direction == 0):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (self.direction == 2):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.insert("fwd")
elif (x < x0):
if (self.direction == 3):
self.queue.append("fwd")
elif (self.direction == 0):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 2):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (y > y0):
if (self.direction == 0):
self.queue.append("fwd")
elif (self.direction == 1):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 3):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (y < y0):
if (self.direction == 2):
self.queue.append("fwd")
elif (self.direction == 3):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 1):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (len(self.path)==0):
self.queue.append("op")
def step(self):
if self.health > 0:
print("position: ", self.pos)
#print("direction: ", self.direction)
if not self.hasgoalchest: #jeśli nie ma wyznaczonej skrzynki do której idzie to robi bfs żeby ją wyznaczyć
self.path=self.findShortestPathToTarget()
if self.path=="no chests left":
print("no chests left, life has lost meaning")
else:
print("the player should follow this path:", self.path)
for i in range(len(self.path)-1): #iteruje po kolejnych krotkach ze współrzędnymi pól
#actionPlanner ma się wykonać i-1 razy, bo dla ostatniego pola już nie
self.actionPlanner(self.path[i], self.path[i+1]) #dla każdego pola dodaje do kolejki kilka akcji potrzebnych żeby do niego dojść
print(self.queue)
self.direction=0 # bo po obrotach w wyznaczaniu ścieżki trzeba wrócić do orientacji takiej, jaka była na starcie wyznaczania
#to znaczy, że po otwarciu skrzynki też się zeruje żeby zacząć wyznaczanie i chodzenie od takiej samej
while len(self.queue)!=0:
self.action=self.queue.pop(0)
if self.action=="tr":
self.rotate(True)
print("tr'd, direction: ", self.direction)
break
elif self.action=="tl":
self.rotate(False)
print("tl'd, direction: ", self.direction)
break
elif self.action=="fwd":
self.moveFwd()
break
cellmates = self.model.grid.get_cell_list_contents([self.pos])
if len(cellmates) > 1:
if isinstance(cellmates[0], Box):
self.openChest(cellmates[0])
else:
opponent = cellmates[0]
print("Fighting")
self.fightOrFlight(opponent)
# print("HP: " + str(self.health) + " / " + str(self.maxHealth))
print("Gold: " + str(self.gold))
else:
print("HP: 0 / " + str(self.maxHealth))

View File

@ -1,59 +0,0 @@
from mesa import Model
from hero import Player
from othercharacters import Creature, Box, Wall, dice
from armory import WM1, A1, WR1, S1, WM2, A2
from mesa.time import RandomActivation
from mesa.space import MultiGrid
# from mesa.datacollection import DataCollector
import random
x = 10
y = 10
step_counter = 0
boxes_number = 4
creatures_number = 5
class GameMap(Model):
def __init__(self, x, y):
self.grid = MultiGrid(x, y, False)
self.schedule = RandomActivation(self) # agenci losowo po kolei wykonują swoje akcje
# to jest potrzebne przy założeniu, że potwory chodzą?
self.boxes_number = boxes_number
self.creatures_number = creatures_number
self.running = True
# player = Player(1000, self)
player = Player(1000, self, "Janusz", 3, 3, 3, 20, 20, WM1, A1, 0, WR1, S1)
self.schedule.add(player)
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
self.grid.place_agent(player, (x, y))
for i in range(self.boxes_number):
box = Box(i, self)
# self.schedule.add(box)
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(box, (x, y))
self.schedule.add(box)
else:
pass
for i in range(self.boxes_number,
self.boxes_number + self.creatures_number): # taki range, żeby każdy agent miał poprawne unique_id
# creature = Creature(i, self)
creature = Creature(i, self, "Goblin", 1, 1, 1, 1, 1, WM2, A2, dice(6))
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(creature, (x, y))
self.schedule.add(creature)
else:
pass
# self.datacollector=DataCollector #informacje o stanie planszy, pozycja agenta
def step(self):
self.schedule.step()
# self.datacollector.collect(self) #na razie niepotrzebne

BIN
nn_model.h5 Normal file

Binary file not shown.

View File

@ -1,86 +0,0 @@
from mesa import Agent
import random
def dice(number):
return random.randint(1, number)
class Wall(Agent):
def __init__(self, unique_id, model):
super().__init__(unique_id, model)
def step(self):
pass
class Box(Agent):
def __init__(self, unique_id, model):
super().__init__(unique_id, model)
self.gold = 3 * dice(6)
self.isBox = True
self.isCreature = False
def step(self):
pass
class Weapon():
def __init__(self, name, type, damage):
self.name = name
self.type = type
self.damage = damage
class Armor():
def __init__(self, name, defence, mp):
self.name = name
self.defence = defence
self.mag_protection = mp
class Creature(Agent):
def __init__(self, unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g):
super().__init__(unique_id, model)
self.name = n
self.strength = s
self.agility = a
self.wisdom = w
self.maxHealth = maxhp
self.health = hp
self.gold = g
self.weapon1 = weap
self.armor = arm
self.isBox = False
self.isCreature = True
def meleeAttack(self, opponent):
attackValue = self.strength + dice(6)
defenseValue = opponent.strength + opponent.armor.defence
damage = attackValue - defenseValue
if damage > 0:
opponent.health = opponent.health - (damage + self.weapon1.damage)
def rangeAttack(self, opponent):
attackValue = self.agility + dice(6)
defenseValue = opponent.agility
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.weapon1.damage - opponent.armor.defence > 0):
opponent.health = opponent.health - (damage + self.weapon1.damage - opponent.armor.defence)
def magicAttack(self, opponent):
attackValue = self.wisdom + dice(6)
defenseValue = opponent.wisdom
damage = attackValue - defenseValue
if (damage > 0) and (damage + self.weapon1.damage - opponent.armor.mag_protection > 0):
opponent.health = opponent.health - (damage + self.weapon1.damage - opponent.armor.mag_protection)
def defaultAttack(self, opponent):
if self.weapon1.type == "Meele":
self.meleeAttack(opponent)
elif self.weapon1.type == "Range":
self.rangeAttack(opponent)
else:
self.magicAttack(opponent)

View File

Before

Width:  |  Height:  |  Size: 208 B

After

Width:  |  Height:  |  Size: 208 B

BIN
sprites/heroN.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
sprites/heroS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

BIN
sprites/heroW.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

0
src/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

4
src/agent/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from .hero import Player
from .map.gameMap import GameMap
from .model import *
from .state import AgentState

Binary file not shown.

Binary file not shown.

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, 3, 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

350
src/agent/hero.py Normal file
View File

@ -0,0 +1,350 @@
import random
import pandas as pd
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.agent.model import *
from src.agent.state import AgentState
from src.direction import Direction
from src.items.armory import WM9
from src.treesearch.actionsInterpreter import ActionInterpreter
from src.agent.model.dice.dice import roll_the_dice
from src.treesearch.bfs import BFS
from src.nominalize import nominalize
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
import pathlib
class Player(Creature):
def __init__(self, unique_id, model, n, s, a, w, max_hp, hp, weapon, arm, g, w2, w3, list_of_chests):
super().__init__(unique_id, model, n, s, a, w, max_hp, hp, weapon, arm, g)
self.name = n
self.strength = s
self.agility = a
self.wisdom = w
self.maxHealth = max_hp
self.health = hp
self.gold = g
self.weapon1 = weapon
self.weapon2 = w2
self.weapon3 = w3
self.armor = arm
self.isBox = False
self.isCreature = False
self.isPlayer=True
self.direction = Direction.N
self.queue = []
self.has_goal_chest = False
self.opened_chests = 0
self.__listOfChests = list_of_chests
self.__actionsCollection = []
self.combat=False
self.opponent=None
self.strategy="PASS"
def identify_content(self, chest):
dataset_url = "https://drive.google.com/uc?export=download&id=1b6w1FbupRmgVC-q9Lpdlg5OBK_gRKEUy"
data_dir = tf.keras.utils.get_file(fname='loot', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)
#image_count = len(list(data_dir.glob('*/*.jpg')))
#print(image_count)
batch_size = 32
img_height = 180
img_width = 180
train_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="training",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
data_dir,
validation_split=0.2,
subset="validation",
seed=123,
image_size=(img_height, img_width),
batch_size=batch_size)
class_names = train_ds.class_names
#print(class_names)
normalization_layer = layers.experimental.preprocessing.Rescaling(1. / 255)
normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixels values are now in `[0,1]`.
#print(np.min(first_image), np.max(first_image))
#num_classes = 3
# Recreate the exact same model, including its weights and the optimizer
new_model = tf.keras.models.load_model('nn_model.h5')
# Show the model architecture
#new_model.summary()
# loss, acc = new_model.evaluate(test_images, test_labels, verbose=2)
# print('Restored model, accuracy: {:5.2f}%'.format(100 * acc))
object_url = chest.type
object_path = tf.keras.utils.get_file(chest.file_name, origin=object_url)
img = keras.preprocessing.image.load_img(
object_path, target_size=(img_height, img_width)
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
predictions = new_model.predict(img_array)
score = tf.nn.softmax(predictions[0])
print(
"This image most likely belongs to {} with a {:.2f} percent confidence."
.format(class_names[np.argmax(score)], 100 * np.max(score))
)
return class_names[np.argmax(score)]
def predict_strategy(self, opponent):
testcase = pd.DataFrame({'p_strength': nominalize(self.get_strength(),10),
'p_agility':nominalize(self.get_agility(), 10),
'p_wisdom':nominalize(self.get_wisdom(),10),
'p_health':nominalize(self.get_health(),50),
'p_melee_damage':nominalize(self.get_melee_damage(), 10),
'p_ranged_damage':nominalize(self.get_ranged_damage(),10),
'p_magic_damage':nominalize(self.get_magic_damage(),10),
'p_armor_defence':nominalize(self.get_armor_defence(),5),
'p_armor_magic_protection':nominalize(self.get_armor_magic_protection(),5),
'e_strength':nominalize(opponent.get_strength(), 10),
'e_agility':nominalize(opponent.get_agility(), 10),
'e_wisdom':nominalize(opponent.get_wisdom(),10),
'e_health':nominalize(opponent.get_health(), 50),
'e_damage':nominalize(opponent.get_damage(),10),
'e_armor_defence':nominalize(opponent.get_armor_defence(), 5),
'e_armor_magic_protection':nominalize(opponent.get_armor_magic_protection(), 5),
'e_attack_type':opponent.get_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
print(r_dataframe)
result=robjects.r('predict(fights.id3, r_dataframe)')
print(result)
return result[0]
def describe_situation(self, opponent):
situation = {# 'p_strength': self.get_strength(),
# 'p_agility': self.get_agility(),
# 'p_wisdom': self.get_wisdom(),
# 'p_health': self.get_health(),
# 'p_melee_damage': self.get_melee_damage(),
# 'p_ranged_damage': self.get_ranged_damage(),
# 'p_magic_damage': self.get_magic_damage(),
# 'p_armor_defence': self.get_armor_defence(),
# 'p_armor_magic_protection': self.get_armor_magic_protection(),
'e_strength': opponent.get_strength(),
'e_agility': opponent.get_agility(),
'e_wisdom': opponent.get_wisdom(),
'e_health': opponent.get_health(),
'e_damage': opponent.get_damage(),
'e_armor_defence': opponent.get_armor_defence(),
'e_armor_magic_protection': opponent.get_armor_magic_protection(),
'e_attack_type': opponent.get_attack_type().upper()}
return situation
def melee_attack(self, opponent):
attack_value = self.strength + roll_the_dice(6)
defense_value = opponent.strength + opponent.armor.get_defence()
damage = attack_value - defense_value
if damage > 0:
opponent.health = opponent.health - (damage + self.weapon1.get_damage())
print("damage done by the player: ", damage)
def range_attack(self, opponent):
attack_value = self.agility + roll_the_dice(6)
defense_value = opponent.agility
damage = attack_value - defense_value
if (damage > 0) and (damage + self.weapon2.get_damage() - opponent.armor.get_defence() > 0):
opponent.health = opponent.health - (damage + self.weapon2.get_damage() - opponent.armor.get_defence())
print("damage done by the player: ", damage)
def magic_attack(self, opponent):
attack_value = self.wisdom + roll_the_dice(6)
defense_value = opponent.wisdom
damage = attack_value - defense_value
if (damage > 0) and (damage + self.weapon3.get_damage() - opponent.armor.get_mag_protection() > 0):
opponent.health = opponent.health - (damage + self.weapon3.get_damage() - opponent.armor.get_mag_protection())
print("damage done by the player: ", damage)
def fight_or_flight(self, opponent, strategy):
self.combat = True
while self.combat:
if strategy=="MELEE":
self.melee_attack(opponent)
if opponent.health > 0:
opponent.default_attack(self)
if self.health <= 0:
self.combat = False
print("Player died :/")
else:
self.combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
elif strategy=="RANGED":
self.range_attack(opponent)
if opponent.health > 0:
opponent.default_attack(self)
if self.health <= 0:
self.combat = False
print("Player died :/")
else:
self.combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
elif strategy=='MAGIC':
self.magic_attack(opponent)
if opponent.health > 0:
opponent.default_attack(self)
if self.health <= 0:
self.combat = False
print("Player died :/")
else:
self.combat = False
self.gold = self.gold + opponent.gold
opponent.gold = 0
opponent.model.grid.remove_agent(opponent)
print("Fight won")
else:
running_speed = self.agility + roll_the_dice(6)
opponent_speed = opponent.agility + roll_the_dice(6)
if running_speed > opponent_speed:
self.combat = False
print("Player ran away")
self.step()
else:
print("Player was too slow to run away")
opponent.default_attack(self)
if self.health <= 0:
self.combat = False
print("Player died :/")
def open_chest(self, chest):
if chest.type == 1:
ch_gold = 3 * roll_the_dice(6)
self.gold = self.gold + ch_gold
print("------Chest opened. Gold inside:", ch_gold, "-----")
elif chest.type == 2:
self.weapon1 = WM9
else:
self.health = 0
# self.direction = 0 # po osiągnięciu jednego celu 'restartuje sie' na szukanie ścieżki do kolejnego -- NIE ZEROWAĆ OBROTU - to psuje goldState w bfs!!!
# if isinstance(chest.loot,Armor):
# buffer = self.armor
# self.armor = chest.loot
# chest.loot = buffer
# if isinstance(chest.loot,Weapon):
# if chest.loot.weapon_type == "Melee":
# buffer = self.weapon1
# self.weapon1 = chest.loot
# chest.loot = buffer
# elif chest.loot.weapon_type == "Range":
# buffer = self.weapon2
# self.weapon2 = chest.loot
# chest.loot = buffer
# elif chest.loot.weapon_type == "Magic":
# buffer = self.weapon3
# self.weapon3 = chest.loot
# chest.loot = buffer
def step(self):
if self.health > 0:
print("position: ", self.pos)
# print("direction: ", self.direction)
if not self.has_goal_chest: # jeśli nie ma wyznaczonej skrzynki do której idzie to robi bfs żeby ją wyznaczyć
# self.path=self.findShortestPathToTarget()
if len(self.__listOfChests) != 0:
# select and remove element from list
random_chest = random.choice(self.__listOfChests)
self.__listOfChests.remove(random_chest)
self.has_goal_chest = True
current_state = AgentState(self.pos[0], self.pos[1], self.direction)
goal_state = AgentState(random_chest[1][0], random_chest[1][1], self.direction)
# find way to goal state
treesearch_module = BFS(self)
self.__actionsCollection = treesearch_module.graphsearch([],
[],
current_state,
BFS.successor,
goal_state)
if self.__actionsCollection is None:
raise Exception("CRITICAL ERROR - Algorithm error - Path doesn't exist!!! ://")
else:
self.__actionsCollection = [action for action in self.__actionsCollection if
action is not None] # remove first None action
else:
raise Exception("WIN!!! :D")
elif len(
self.__actionsCollection) == 0: # jeśli jest wyznaczona skrzynka - cel & nie ma akcji do wykonania - cel osiągnięty
self.has_goal_chest = False
elif len(
self.__actionsCollection) != 0: # jeśli jest wyznaczona skrzynka - cel & są akcje do wykoannia to je realizuje
action_index = self.__actionsCollection[0] # ignore -1 because it's None
self.__actionsCollection.remove(action_index)
new_state = ActionInterpreter.interpret(action_index,
AgentState(self.pos[0], self.pos[1], self.direction))
self.model.grid.move_agent(self, (new_state.get_x(), new_state.get_y()))
self.direction = new_state.get_direction()
#print("moved to - ", [new_state.get_x(), new_state.get_y()])
cellmates = self.model.grid.get_cell_list_contents([self.pos])
if len(cellmates) > 1:
if isinstance(cellmates[0], Box):
decision = self.identify_content(cellmates[0])
print("Content of chest: "+cellmates[0].address)
if (decision == 'coins') or (decision == 'weapons'):
print("I will open this chest!")
self.open_chest(cellmates[0])
print("Type of opened chest: ", cellmates[0].type)
else:
print("Probably a trap - chest skipped!")
print("Type of skipped chest: ", cellmates[0].type)
self.opened_chests += 1
self.has_goal_chest = False
cellmates[0].model.grid.remove_agent(cellmates[0])
else:
self.opponent = cellmates[0]
self.strategy=self.predict_strategy(self.opponent)
print("Current enemy stats:\n", self.describe_situation(self.opponent))
print("Strategy returned from the tree: ", self.strategy)
self.fight_or_flight(self.opponent, self.strategy)
else:
print("HP: 0 / " + str(self.maxHealth))

Binary file not shown.

97
src/agent/map/gameMap.py Normal file
View File

@ -0,0 +1,97 @@
from mesa import Model
from mesa.datacollection import DataCollector
import src.agent.ga_chromosome as ga
from src.agent.hero import Player
from src.agent.model.dice.dice import roll_the_dice
from src.agent.model.creature import Creature
from src.agent.model.box import Box
from src.items.armory import *#WM1, A1, WR1, S1, WM2, A2
from mesa.time import RandomActivation
from mesa.space import MultiGrid
import random
# from mesa.datacollection import DataCollector
x = 10
y = 10
step_counter = 0
boxes_number = 6
creatures_number = 35
class GameMap(Model):
def __init__(self, x, y):
self.listOfChests = []
self.grid = MultiGrid(x, y, False)
self.schedule = RandomActivation(self) # agenci losowo po kolei wykonują swoje akcje
self.boxes_number = boxes_number
self.creatures_number = creatures_number
self.running = True
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)
print("player optimised stats:", s, a, w)
self.player = Player(1000, self, "Janusz", s, a, w, 50, 50, WM1, A1, 0, WR1, S1, self.listOfChests)
print('Player stats:',self.player.strength, self.player.agility, self.player.wisdom)
self.schedule.add(self.player)
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
self.grid.place_agent(self.player, (x, y))
for i in range(self.boxes_number):
r_type = random.randrange(1, 4)
box = Box(i, self, r_type)
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(box, (x, y))
self.schedule.add(box)
self.listOfChests.append([i, [x, y]]) # fetching chest position - [index, [OX, OY]]
else:
pass
for i in range(self.boxes_number,
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, "Goblin",
roll_the_dice(3), roll_the_dice(3), roll_the_dice(3), 15, roll_the_dice(3),
WM2, A2, roll_the_dice(5))
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(creature, (x, y))
self.schedule.add(creature)
else:
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
creature = Creature(i, self, "Skeleton",
roll_the_dice(7), roll_the_dice(7), roll_the_dice(7), 15, roll_the_dice(7),
WR4, A8, roll_the_dice(10))
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(creature, (x, y))
self.schedule.add(creature)
else:
pass
#self.datacollector=DataCollector(model_reporters={"HP":self.player.health, "Gold":self.player.gold, "Position (x, y)":self.player.pos}) #informacje o stanie planszy, pozycja agenta
#other data: position, strength & other parameters
def get_list_of_chests(self):
return self.listOfChests
def get_hp(self):
return self.player.health
def get_gold(self):
return self.player.gold
def get_position(self):
return str(self.player.pos)+str(self.player.direction.name)
def step(self):
self.schedule.step()
#self.datacollector.collect(self)
#print(str(self.datacollector.model_reporters))

View File

@ -0,0 +1,6 @@
from .dice import *
from .armor import Armor
from .box import Box
from .creature import Creature
from .wall import Wall
from .weapon import Weapon

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

21
src/agent/model/armor.py Normal file
View File

@ -0,0 +1,21 @@
class Armor:
def __init__(self, name, defence, mp):
self.__name = name
self.__defence = defence
self.__mag_protection = mp
def get_name(self):
return self.__name
def get_defence(self):
return self.__defence
def set_defence(self, new_defence):
self.__defence = new_defence
def get_mag_protection(self):
return self.__mag_protection
def set_mag_protection(self, new_mag_protection):
self.__mag_protection = new_mag_protection

42
src/agent/model/box.py Normal file
View File

@ -0,0 +1,42 @@
from mesa import Agent
import random
#from .dice.dice import roll_the_dice
golds = [("https://drive.google.com/uc?export=download&id=1fWeew0jXZ1lZBmv6CG5viLGloJAex6ao",'moneta'),
("https://drive.google.com/uc?export=download&id=1UrXbbfJhfCuDZSnxund7sVk40QMS3R2Q", 'moneta2'),
("https://drive.google.com/uc?export=download&id=1qH0OP4X1NQqpHtUkwD8SryJtKCKcZzVe", 'moneta3'),
("https://drive.google.com/uc?export=download&id=1b9tZf639mEWgiWq_EYyqjeKYPEMi7dX9", 'moneta4'),
("https://drive.google.com/uc?export=download&id=1z9jt-j3aS1fRUgVA_t1zR7TS5QzuXW5b", 'moneta5')]
weapons = [("https://drive.google.com/uc?export=download&id=1TA-ObC33FaiHmgQ6i71Kcb32VrHsKUd1", 'miecz'),
("https://drive.google.com/uc?export=download&id=1oyv15FSPJ84xx1tQLJW8Wlbb1JUx2xCy", 'miecz2'),
("https://drive.google.com/uc?export=download&id=1Ha0eeLRLcidrMAN1P59V9zB8uSQq3GM5", 'miecz3'),
("https://drive.google.com/uc?export=download&id=1GetUWnglUtqWqcK4sd5HsdVuaUpU5Ec_", 'miecz4'),
("https://drive.google.com/uc?export=download&id=1RImo84OykYICvwfLycDEb5tr4tPbGVy1", 'miecz5')]
traps = [("https://drive.google.com/uc?export=download&id=1G-AxY712V-eT2ylW0VXn4o2V_4pvy7lz", 'kwiat'),
("https://drive.google.com/uc?export=download&id=1i7MwzJRPBZ-KrCDqhT5RCXLstLlWCsx9", 'kwiat2'),
("https://drive.google.com/uc?export=download&id=1zF7wQuG1gtQ796m6TM08FOUOVK8s_qhT", 'kwiat3'),
("https://drive.google.com/uc?export=download&id=1qwrIThsoKg44b57JXvbXe--TIplacd-i", 'kwiat4'),
("https://drive.google.com/uc?export=download&id=1YsqdQaLyD8Es4w09p4Zdw2CufNkl_avN", 'kwiat5')]
class Box(Agent):
def __init__(self, unique_id, model, type):
super().__init__(unique_id, model)
#self.gold = 3 * roll_the_dice(6)
self.isBox = True
self.isCreature = False
self.isPlayer = False
self.type = type
r_img = random.randrange(0,4)
if type == 1:
self.address = golds[r_img][0]
self.file_name = golds[r_img][1]
elif type == 2:
self.address = weapons[r_img][0]
self.file_name = weapons[r_img][1]
else:
self.address = traps[r_img][0]
self.file_name = traps[r_img][1]
def step(self):
pass

View File

@ -0,0 +1,80 @@
from mesa import Agent
from .dice.dice import roll_the_dice
class Creature(Agent):
def __init__(self, unique_id, model, name, strength, agility, wisdom, max_hp, hp, weapon, armor, gold):
super().__init__(unique_id, model)
self.name = name
self.strength = strength
self.agility = agility
self.wisdom = wisdom
self.maxHealth = max_hp
self.health = hp
self.gold = gold
self.weapon1 = weapon
self.armor = armor
self.isBox = False
self.isCreature = True
self.isPlayer = False
def get_strength(self):
return self.strength
def get_agility(self):
return self.agility
def get_wisdom(self):
return self.wisdom
def get_health(self):
return self.health
def get_damage(self):
return self.weapon1.get_damage()
def get_melee_damage(self):
return self.weapon1.get_damage()
def get_ranged_damage(self):
return self.weapon2.get_damage()
def get_magic_damage(self):
return self.weapon3.get_damage()
def get_armor_defence(self):
return self.armor.get_defence()
def get_armor_magic_protection(self):
return self.armor.get_mag_protection()
def get_attack_type(self):
return self.weapon1.get_type()
def melee_attack(self, opponent):
attack_value = self.strength + roll_the_dice(6)
defense_value = opponent.strength + opponent.armor.get_defence()
damage = attack_value - defense_value
if damage > 0:
opponent.health = opponent.health - (damage + self.weapon1.get_damage())
print("damage done by the monster: ", damage)
def range_attack(self, opponent):
attack_value = self.agility + roll_the_dice(6)
defense_value = opponent.agility
damage = attack_value - defense_value
if (damage > 0) and (damage + self.weapon1.get_damage() - opponent.armor.get_defence() > 0):
opponent.health = opponent.health - (damage + self.weapon1.get_damage() - opponent.armor.get_defence())
print("damage done by the monster: ", damage)
def magic_attack(self, opponent):
attack_value = self.wisdom + roll_the_dice(6)
defense_value = opponent.wisdom
damage = attack_value - defense_value
if (damage > 0) and (damage + self.weapon1.get_damage() - opponent.armor.get_mag_protection() > 0):
opponent.health = opponent.health - (damage + self.weapon1.get_damage() - opponent.armor.get_mag_protection())
print("damage done by the monster: ", damage)
def default_attack(self, opponent):
if self.weapon1.get_type() == "Meele":
self.melee_attack(opponent)
elif self.weapon1.get_type() == "Ranged":
self.range_attack(opponent)
else:
self.magic_attack(opponent)

View File

Binary file not shown.

View File

@ -0,0 +1,4 @@
import random
def roll_the_dice(number):
return random.randint(1, number)

9
src/agent/model/wall.py Normal file
View File

@ -0,0 +1,9 @@
from mesa import Agent
class Wall(Agent):
def __init__(self, unique_id, model):
super().__init__(unique_id, model)
def step(self):
pass

14
src/agent/model/weapon.py Normal file
View File

@ -0,0 +1,14 @@
class Weapon:
def __init__(self, name, weapon_type, weapon_damage):
self.__name = name
self.__type = weapon_type
self.__damage = weapon_damage
def get_name(self):
return self.__name
def get_type(self):
return self.__type
def get_damage(self):
return self.__damage

29
src/agent/state.py Normal file
View File

@ -0,0 +1,29 @@
class AgentState:
def __init__(self, x, y, direction):
self.__x = x
self.__y = y
self.__direction = direction
def get_x(self):
return self.__x
def increment_x(self, value):
self.__x += value
def set_x(self, x):
self.__x = x
def get_y(self):
return self.__y
def increment_y(self, value):
self.__y += value
def set_y(self, y):
self.__y = y
def get_direction(self):
return self.__direction
def set_direction(self, direction):
self.__direction = direction

20
src/decisiontree.py Normal file
View File

@ -0,0 +1,20 @@
import rpy2.robjects as robjects
from rpy2.robjects.packages import importr
import pickle
def create_model():
RWeka = importr('RWeka')
robjects.r('WPM("refresh-cache")')
robjects.r('WPM("install-package", "simpleEducationalLearningSchemes")')
robjects.r('WPM("load-package", "simpleEducationalLearningSchemes")')
robjects.r('ID3<-make_Weka_classifier("weka/classifiers/trees/Id3")')
robjects.r('fights<-read.arff("C:/Users/X260/Downloads/currentdata.arff")')
robjects.r('fights.id3 <- ID3(strategy ~ p_strength + p_agility + p_wisdom+ p_health + '
'p_melee_damage + p_ranged_damage + p_magic_damage + p_armor_defence + p_armor_magic_protection + '
'e_strength+ e_agility + e_wisdom + e_health + e_damage + e_armor_defence + e_armor_magic_protection + '
'e_attack_type, data = fights)')
# robjects.r('.jcache(fights.id3)')
#robjects.r('save(fights.id3, file="tree.rda)')
# with open('tree.rda','wb') as f:
# pickle.dump(robjects.r('fights.id3'), f)
#todo: zapisać w rpythonie do pliku, raz zrobić i nie odpalać za każdym razem w serverze

Binary file not shown.

View File

@ -0,0 +1,5 @@
actions = {
"rotate_left": -1,
"move_forward": 0,
"rotate_right": 1
}

View File

@ -0,0 +1,8 @@
from src.direction import Direction
directions = {
Direction.N: [0, 1],
Direction.E: [1, 0],
Direction.S: [0, -1],
Direction.W: [-1, 0]
}

16
src/direction.py Normal file
View File

@ -0,0 +1,16 @@
from enum import Enum
class Direction(Enum):
N = 0
E = 1
S = 2
W = 3
def clockwise(self):
v = (self.value + 1) % 4
return Direction(v)
def counter_clockwise(self):
v = (self.value - 1) % 4
return Direction(v)

Binary file not shown.

View File

@ -1,6 +1,5 @@
from mesa import Agent, Model
import random
from hero import Weapon, Armor
from src.agent.model.weapon import Weapon
from src.agent.model.armor import Armor
WM1 = Weapon("Log", "Melee", 1)
WM2 = Weapon("Log", "Melee", 1)
@ -15,16 +14,16 @@ WM10 = Weapon("Axe", "Melee", 3)
WM11 = Weapon("Axe", "Melee", 3)
WM12 = Weapon("Battle axe", "Melee", 4)
WR1 = Weapon("Sling", "Range", 1)
WR2 = Weapon("Sling", "Range", 1)
WR3 = Weapon("Sling", "Range", 1)
WR4 = Weapon("Bow", "Range", 2)
WR5 = Weapon("Bow", "Range", 2)
WR6 = Weapon("Bow", "Range", 2)
WR7 = Weapon("Bow", "Range", 2)
WR8 = Weapon("Longbow", "Range", 3)
WR9 = Weapon("Longbow", "Range", 3)
WR10 = Weapon("Crossbow", "Range", 4)
WR1 = Weapon("Sling", "Ranged", 1)
WR2 = Weapon("Sling", "Ranged", 1)
WR3 = Weapon("Sling", "Ranged", 1)
WR4 = Weapon("Bow", "Ranged", 2)
WR5 = Weapon("Bow", "Ranged", 2)
WR6 = Weapon("Bow", "Ranged", 2)
WR7 = Weapon("Bow", "Ranged", 2)
WR8 = Weapon("Longbow", "Ranged", 3)
WR9 = Weapon("Longbow", "Ranged", 3)
WR10 = Weapon("Crossbow", "Ranged", 4)
S1 = Weapon("Push", "Magic", 2)
S2 = Weapon("Push", "Magic", 2)
@ -62,9 +61,9 @@ A16 = Armor("Magical Plate Armor", 3, 2)
# C10 = Box(A8)
# C11 = Box(A12)
# C12 = Box(A14)
#
# Gracz = Player(1000, self, "Janusz",3,3,3,20,20,WM1,A1,0,WR1,S1)
# def __init__(self, unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g):
# def __init__(self, unique_id, model, n, s, a, w, max_hp, hp, weapon, arm, g):
# M1 = Creature("Goblin",2,2,1,10,10,WM2,A2,dice(6))
# M2 = Creature("Goblin",2,2,1,10,10,WM3,A3,dice(6))
# M3 = Creature("Goblin",2,2,1,10,10,WR2,A4,dice(6))

9
src/nominalize.py Normal file
View File

@ -0,0 +1,9 @@
def nominalize(val, max_val):
return_value = "NONE"
if val > 0.66 * max_val:
return_value = "HIGH"
elif val > 0.33 * max_val:
return_value = "MEDIUM"
elif val > 0:
return_value = "LOW"
return return_value

Binary file not shown.

24
src/tree/node.py Normal file
View File

@ -0,0 +1,24 @@
class Node:
def __init__(self, parent, state_tuple, cost):
self._cost = cost
self._action = state_tuple[0]
self._state = state_tuple[1]
self._parent = parent
def get_cost(self):
return self._cost
def get_action(self):
return self._action
def get_state(self):
return self._state
def get_predecessor(self):
return self._parent
def set_predecessor(self, predecessor):
self._parent = predecessor
def __lt__(self, other):
return self._cost < other.get_cost()

View File

@ -0,0 +1,3 @@
from .bfs import BFS
from .actionsInterpreter import ActionInterpreter
from .heuristic import *

Binary file not shown.

View File

@ -0,0 +1,40 @@
from src.agent.state import AgentState
from src.direction import Direction
class ActionInterpreter:
@staticmethod
def interpret(action_index, default_state):
if action_index == -1:
return AgentState(
default_state.get_x(),
default_state.get_y(),
default_state.get_direction().counter_clockwise()
)
elif action_index == 0:
move_x = 0
move_y = 0
if default_state.get_direction() == Direction.N:
move_y = 1
elif default_state.get_direction() == Direction.E:
move_x = 1
elif default_state.get_direction() == Direction.S:
move_y = -1
elif default_state.get_direction() == Direction.W:
move_x = -1
return AgentState(
default_state.get_x() + move_x,
default_state.get_y() + move_y,
default_state.get_direction()
)
elif action_index == 1:
return AgentState(
default_state.get_x(),
default_state.get_y(),
default_state.get_direction().clockwise()
)
else:
return default_state

140
src/treesearch/bfs.py Normal file
View File

@ -0,0 +1,140 @@
import heapq
from src.dictionary.actions import actions
from src.agent.state import AgentState
from src.direction import Direction
from src.tree.node import Node
from src.treesearch.heuristic.manhattan import manhattan
class BFS:
def __init__(self, agent):
self.__agent = agent
@staticmethod
def successor(append):
rotate_left = AgentState(
append.get_x(),
append.get_y(),
append.get_direction().counter_clockwise()
)
rotate_right = AgentState(
append.get_x(),
append.get_y(),
append.get_direction().clockwise()
)
move_x = 0
move_y = 0
if append.get_direction() == Direction.N:
move_y = 1
elif append.get_direction() == Direction.E:
move_x = 1
elif append.get_direction() == Direction.S:
move_y = -1
elif append.get_direction() == Direction.W:
move_x = -1
if append.get_x() + move_x >= 0 and append.get_x() + move_x < 10 and append.get_y() + move_y >= 0 and append.get_y() + move_y < 10:
move_forward = AgentState(
append.get_x() + move_x,
append.get_y() + move_y,
append.get_direction()
)
else:
move_forward = None
return [
[actions["rotate_left"], rotate_left],
[actions["move_forward"], move_forward],
[actions["rotate_right"], rotate_right]
]
def graphsearch(self, fringe, explored, istate, succesor_function, goal_state):
final_action_list = []
init_state = [None, istate]
root = Node(None, init_state, 0)
heapq.heappush(fringe, (0, root)) # at beginning do nothing
while len(fringe) != 0:
_flag = True
if len(fringe) == 0:
return False
tmp_node = (heapq.heappop(fringe))[1] # node
# build dictionary
# parent = tmp_node.get_predecessor() # fetch parent state
# tmp_node.set_predecessor(None) # clear predecessor - don't build a tree chain
# if parent is None:
# final_action_list.append([parent, tmp_node])
# else:
# final_action_list.append(
# [parent[1], tmp_node]) # pair(key, value) - key: parent state, value: current state + action
if tmp_node.get_state().get_x() == goal_state.get_x() and tmp_node.get_state().get_y() == goal_state.get_y():
while tmp_node.get_predecessor() is not None:
final_action_list.append(tmp_node.get_action())
tmp_node = tmp_node.get_predecessor()
final_action_list = list(reversed(final_action_list))
return final_action_list # TODO change step!
explored.append(tmp_node)
tmp_list = succesor_function(tmp_node.get_state())
for new_state in tmp_list:
_flag = True
_flagFringe = True
_flagExplored = True
if new_state[1] is None:
continue
# calculating priority
monster = 0
if any([thing.isCreature for thing in
self.__agent.model.grid.get_cell_list_contents(
[(new_state[1].get_x(), new_state[1].get_y())])]):
if new_state[0] == 0:
monster = 0
p = manhattan(new_state[1], goal_state) + tmp_node.get_cost() + monster + 1
r = 0
counter = 0
pos = 0
for fringeNode in fringe:
if fringeNode[1].get_state().get_x() == new_state[1].get_x() and fringeNode[
1].get_state().get_y() == new_state[1].get_y() and fringeNode[1].get_state().get_direction() == \
new_state[1].get_direction():
_flagFringe = False
_flag = False
r = fringeNode[0]
pos = counter
counter = counter + 1
for exploredNode in explored:
if exploredNode.get_state().get_x() == new_state[1].get_x() and exploredNode.get_state().get_y() == \
new_state[1].get_y() and exploredNode.get_state().get_direction() == new_state[
1].get_direction():
_flagExplored = False
_flag = False
# if _flag:
# new_state[1].set_predecessor(tmp_node)
if _flagFringe and _flagExplored:
new_node = Node(tmp_node, new_state, tmp_node.get_cost() + 1 + monster)
heapq.heappush(fringe, (p, new_node))
elif not _flagFringe and (p < r):
new_node = Node(tmp_node, new_state, tmp_node.get_cost() + 1 + monster)
fringe[pos][0] = p
fringe[pos][1] = new_node
return None

View File

@ -0,0 +1 @@
from .manhattan import manhattan

View File

@ -0,0 +1,4 @@
# cost is initially step distance in manhattan metric
def manhattan(state, target_state):
return abs(state.get_x() - target_state.get_x()) + abs(state.get_y() - target_state.get_y())