Compare commits

..

12 Commits

56 changed files with 7504 additions and 552 deletions

View File

@ -1,47 +0,0 @@
# Funkcja konwertujaca wspolrzedne nastepnego pola do odwiedzenia
# pole to element wziety z kolejki path
from state import AgentState
from direction import Direction
def actionsInterpreter(actionIndex, defaultState, directions):
if actionIndex == -1:
return AgentState(
defaultState.get_x(),
defaultState.get_y(),
defaultState.get_direction().counterClockwise()
)
elif actionIndex == 0:
move_x = 0
move_y = 0
if defaultState.get_direction() == Direction.N:
move_y = 1
elif defaultState.get_direction() == Direction.E:
move_x = 1
elif defaultState.get_direction() == Direction.S:
move_y = -1
elif defaultState.get_direction() == Direction.W:
move_x = -1
return AgentState(
defaultState.get_x() + move_x, # directions[defaultState.get_direction()[0]], - is not subscriptable ???
defaultState.get_y() + move_y, # directions[defaultState.get_direction()][1], - is not subscriptable ???
defaultState.get_direction()
)
elif actionIndex == 1:
return AgentState(
defaultState.get_x(),
defaultState.get_y(),
defaultState.get_direction().clockwise()
)
else:
return defaultState
actions = {
"rotateLeft": -1,
"moveForward": 0,
"rotateRight": 1
}

1000
data_dd2.csv Normal file

File diff suppressed because it is too large Load Diff

5000
data_dd3.csv Normal file

File diff suppressed because it is too large Load Diff

160
dt.py Normal file
View File

@ -0,0 +1,160 @@
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
class GadId3Classifier:
def fit(self, input, output):
data = input.copy()
data[output.name] = output
self.tree = self.decision_tree(data, data, input.columns, output.name)
def predict(self, input):
# convert input data into a dictionary of samples
samples = input.to_dict(orient='records')
predictions = []
# make a prediction for every sample
for sample in samples:
predictions.append(self.make_prediction(sample, self.tree, 1.0))
return predictions
def entropy(self, attribute_column):
# find unique values and their frequency counts for the given attribute
values, counts = np.unique(attribute_column, return_counts=True)
# calculate entropy for each unique value
entropy_list = []
for i in range(len(values)):
probability = counts[i]/np.sum(counts)
entropy_list.append(-probability*np.log2(probability))
# calculate sum of individual entropy values
total_entropy = np.sum(entropy_list)
return total_entropy
def information_gain(self, data, feature_attribute_name, target_attribute_name):
# find total entropy of given subset
total_entropy = self.entropy(data[target_attribute_name])
# find unique values and their frequency counts for the attribute to be split
values, counts = np.unique(data[feature_attribute_name], return_counts=True)
# calculate weighted entropy of subset
weighted_entropy_list = []
for i in range(len(values)):
subset_probability = counts[i]/np.sum(counts)
subset_entropy = self.entropy(data.where(data[feature_attribute_name]==values[i]).dropna()[target_attribute_name])
weighted_entropy_list.append(subset_probability*subset_entropy)
total_weighted_entropy = np.sum(weighted_entropy_list)
# calculate information gain
information_gain = total_entropy - total_weighted_entropy
return information_gain
def decision_tree(self, data, orginal_data, feature_attribute_names, target_attribute_name, parent_node_class=None):
# base cases:
# if data is pure, return the majority class of subset
unique_classes = np.unique(data[target_attribute_name])
if len(unique_classes) <= 1:
return unique_classes[0]
# if subset is empty, ie. no samples, return majority class of original data
elif len(data) == 0:
majority_class_index = np.argmax(np.unique(original_data[target_attribute_name], return_counts=True)[1])
return np.unique(original_data[target_attribute_name])[majority_class_index]
# if data set contains no features to train with, return parent node class
elif len(feature_attribute_names) == 0:
return parent_node_class
# if none of the above are true, construct a branch:
else:
# determine parent node class of current branch
majority_class_index = np.argmax(np.unique(data[target_attribute_name], return_counts=True)[1])
parent_node_class = unique_classes[majority_class_index]
# determine information gain values for each feature
# choose feature which best splits the data, ie. highest value
ig_values = [self.information_gain(data, feature, target_attribute_name) for feature in feature_attribute_names]
best_feature_index = np.argmax(ig_values)
best_feature = feature_attribute_names[best_feature_index]
# create tree structure, empty at first
tree = {best_feature: {}}
# remove best feature from available features, it will become the parent node
feature_attribute_names = [i for i in feature_attribute_names if i != best_feature]
# create nodes under parent node
parent_attribute_values = np.unique(data[best_feature])
for value in parent_attribute_values:
sub_data = data.where(data[best_feature] == value).dropna()
# call the algorithm recursively
subtree = self.decision_tree(sub_data, orginal_data, feature_attribute_names, target_attribute_name, parent_node_class)
# add subtree to original tree
tree[best_feature][value] = subtree
return tree
def make_prediction(self, sample, tree, default=1):
# map sample data to tree
for attribute in list(sample.keys()):
# check if feature exists in tree
if attribute in list(tree.keys()):
try:
result = tree[attribute][sample[attribute]]
except:
return default
result = tree[attribute][sample[attribute]]
# if more attributes exist within result, recursively find best result
if isinstance(result, dict):
return self.make_prediction(sample, result)
else:
return result
#data_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/heart-disease/processed.cleveland.data"
#df = pd.read_csv(data_url, header=None)
df = pd.read_csv("data_dd3.csv", header=None)
# rename known columns
columns = ['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_melee_damage',
'e_ranged_damage','e_magic_damage','e_armor_defence','e_armor_magic_protection','e_attack_type','strategy']
#columns = ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg',
#'thalach', 'exang', 'oldpeak', 'slope', 'ca', 'thal', 'disease_present']
df.columns = columns
# convert disease_present feature to binary
# df['disease_present'] = df.disease_present.replace([1,2,3,4], 1)
# drop rows with missing values, missing = ?
df = df.replace("?", np.nan)
df = df.dropna()
# organize data into input and output
#X = df.drop(columns="disease_present")
#y = df["disease_present"]
X = df.drop(columns="strategy")
y = df["strategy"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
# initialize and fit model
model = GadId3Classifier()
model.fit(X_train, y_train)
# return accuracy score
y_pred = model.predict(X_test)
a = accuracy_score(y_test, y_pred)
print(a)
#print(y_pred)
#print(y_test)

325
hero.py
View File

@ -1,325 +0,0 @@
import random
import heapq
from mesa import Agent
from othercharacters import dice, Box, Creature, Armor, Weapon
from actions import actions, actionsInterpreter
from state import AgentState
from direction import Direction
from node import Node
class Player(Creature):
def __init__(self, unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g, w2, w3, listOfChests):
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 = {
Direction.N : [0, 1],
Direction.E : [1, 0],
Direction.S : [0, -1],
Direction.W : [-1, 0]
}
self.direction = Direction.N
self.queue = []
self.hasgoalchest = False
self.openedchests = 0
self.__listOfChests = listOfChests
self.__actionsCollection = []
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 -- 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.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
#- - - - bfs & successor - - - -#
def successor(self, append):
rotateLeft = AgentState(
append.get_x(),
append.get_y(),
append.get_direction().counterClockwise()
)
rotateRight = 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:
moveForward = AgentState(
append.get_x() + move_x,
append.get_y() + move_y,
append.get_direction()
)
else:
moveForward = None
return [
[actions["rotateLeft"], rotateLeft],
[actions["moveForward"], moveForward],
[actions["rotateRight"], rotateRight]
]
def heuristics(self, state, target_state):
# cost is initially step distance in manhattan metric
return abs(state.get_x() - target_state.get_x()) + abs(state.get_y() - target_state.get_y())
def graphsearch(self, fringe, explored, istate, succesorFunction, goalState):
finalActionList = []
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
tmpNode = (heapq.heappop(fringe))[1] # node
# build dictionary
# parent = tmpNode.get_predecessor() # fetch parent state
# tmpNode.set_predecessor(None) # clear predecessor - don't build a tree chain
# if parent is None:
# finalActionList.append([parent, tmpNode])
# else:
# finalActionList.append(
# [parent[1], tmpNode]) # pair(key, value) - key: parent state, value: current state + action
if tmpNode._state.get_x() == goalState.get_x() and tmpNode._state.get_y() == goalState.get_y():
while tmpNode._parent is not None:
finalActionList.append(tmpNode._action)
tmpNode = tmpNode._parent
finalActionList = list(reversed(finalActionList))
return finalActionList # TODO change step!
explored.append(tmpNode)
tmpList = succesorFunction(tmpNode._state)
for newState in tmpList:
_flag = True
_flagFringe = True
_flagExplored = True
if newState[1] is None:
continue
# calculating priority
monster = 0
if any([thing.isCreature for thing in self.model.grid.get_cell_list_contents([(newState[1].get_x(), newState[1].get_y())])]):
if newState[0] == 0:
monster = 10
p = self.heuristics(newState[1], goalState) + tmpNode._cost + monster + 1
r = 0
counter = 0
pos = 0
for fringeNode in fringe:
if fringeNode[1]._state.get_x() == newState[1].get_x() and fringeNode[1]._state.get_y() == newState[1].get_y() and fringeNode[1]._state.get_direction() == newState[1].get_direction():
_flagFringe = False
_flag = False
r = fringeNode[0]
pos = counter
counter = counter + 1
for exploredNode in explored:
if exploredNode._state.get_x() == newState[1].get_x() and exploredNode._state.get_y() == newState[1].get_y() and exploredNode._state.get_direction() == newState[1].get_direction():
_flagExplored = False
_flag = False
# if _flag:
# newState[1].set_predecessor(tmpNode)
if _flagFringe and _flagExplored:
newNode = Node(tmpNode, newState, tmpNode._cost + 1 + monster)
heapq.heappush(fringe, (p, newNode))
elif not _flagFringe and (p < r):
newNode = Node(tmpNode, newState, tmpNode._cost + 1 + monster)
fringe[pos][0] = p
fringe[pos][1] = newNode
return None
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 len(self.__listOfChests) != 0:
# select and remove element from list
randomChest = random.choice(self.__listOfChests)
self.__listOfChests.remove(randomChest)
self.hasgoalchest = True
currentState = AgentState(self.pos[0], self.pos[1], self.direction)
goalState = AgentState(randomChest[1][0], randomChest[1][1], self.direction)
# find way to goal state
self.__actionsCollection = self.graphsearch([],
[],
currentState,
self.successor,
goalState)
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.hasgoalchest = False
elif len(self.__actionsCollection) != 0: # jeśli jest wyznaczona skrzynka - cel & są akcje do wykoannia to je realizuje
actionIndex = self.__actionsCollection[0] # ignore -1 because it's None
self.__actionsCollection.remove(actionIndex)
newState = actionsInterpreter(actionIndex, AgentState(self.pos[0], self.pos[1], self.direction), self.directions)
self.model.grid.move_agent(self, (newState.get_x(), newState.get_y()))
self.direction = newState.get_direction()
print("moved to - ", [newState.get_x(), newState.get_y()])
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,65 +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.listOfChests = []
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.listOfChests)
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)
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): # 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 get_listOfChests(self):
return self.listOfChests
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

@ -1,22 +1,64 @@
from model import GameMap
from src.agent.map.gameMap import GameMap
from mesa.visualization.modules import CanvasGrid
from mesa.visualization.modules.TextVisualization import TextElement
from mesa.visualization.ModularVisualization import ModularServer
#from src.decisiontree import create_model
from src.direction import Direction
from collections import defaultdict
import src.agent.ga_chromosome as ga
def player_representation(agent):
portrayal = {"Shape": "sprites/hero.png",
portrayal = {"Shape": "sprites/heroE.png",
"Layer": 1}
if agent.isBox:
if agent.isPlayer and agent.direction==Direction.N:
portrayal["Shape"] = "sprites/heroN.png"
elif agent.isPlayer and agent.direction == Direction.W:
portrayal["Shape"] = "sprites/heroW.png"
elif agent.isPlayer and agent.direction == Direction.S:
portrayal["Shape"] = "sprites/heroS.png"
elif agent.isBox:
portrayal["Shape"] = "sprites/box.png"
portrayal["Layer"] = 0
elif agent.isCreature:
portrayal["Shape"]='sprites/goblin.png'
if agent.name=='Goblin':
portrayal["Shape"] = 'sprites/goblin.png'
elif agent.name=='Skeleton':
portrayal["Shape"] = 'sprites/skeletonArcher.png'
return portrayal
grid = CanvasGrid(player_representation, 10, 10, 500, 500)
def chest_content(agent):
if agent.isBox:
portrayal = {"Shape": "sprites/coin.jpg",
"Layer": 1}
return portrayal
grid = CanvasGrid(player_representation, 10, 10, 700, 700)
image=CanvasGrid(chest_content, 1, 1, 200, 200)
class Stats(TextElement):
def render(self, model):
hp = str(model.get_hp())
position = str(model.get_position())
gold = str(model.get_gold())
return "Player hp: {}<br>Current position: {}<br>Player's gold: {}".format(
hp, position, gold)
# class ChestContent(CanvasGrid):
# def render(self,model):
# grid_state = defaultdict(list)
# portrayal = self.chest_content(agent)
# portrayal["x"] = 0
# portrayal["y"] = 0
# grid_state[portrayal["Layer"]].append(portrayal)
# return
# class FightStats(TextElement):
# def render(self, model):
# if model.player.combat:
# return model.player.describe_situation(model.player.opponent, model.player.strategy)
# else:
# return "Not fighting"
ga.create_model()
server = ModularServer(GameMap,
[grid],
[grid,Stats()],
"Map",
{"x":10, "y":10})
{"x": 10, "y": 10})
server.port = 8081
server.launch()
server.launch()

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

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]
}

View File

@ -1,5 +1,6 @@
from enum import Enum
class Direction(Enum):
N = 0
E = 1
@ -7,9 +8,9 @@ class Direction(Enum):
W = 3
def clockwise(self):
v = (self.value+1)%4
v = (self.value + 1) % 4
return Direction(v)
def counterClockwise(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.

View File

@ -5,6 +5,15 @@ class Node:
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
@ -12,4 +21,4 @@ class Node:
self._parent = predecessor
def __lt__(self, other):
return self._cost < other._cost
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())

192
tree_data_gen.py Normal file
View File

@ -0,0 +1,192 @@
import random
from os import urandom
import statistics
import csv
def nominalizeOld(val, max_val):
return_value = "NONE"
if val > 0.8 * max_val:
return_value = "VERY_HIGH"
elif val > 0.6 * max_val:
return_value = "HIGH"
elif val > 0.4 * max_val:
return_value = "MEDIUM"
elif val > 0.2 * max_val:
return_value = "LOW"
elif val > 0:
return_value = "VERY_LOW"
return return_value
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
class Stats:
def __init__(self):
self.strength = random.randint(1, 10)
self.agility = random.randint(1, 10)
self.wisdom = random.randint(1, 10)
self.health = random.randint(1, 50)
self.melee_wep_damage = random.randint(1, 10)
self.ranged_wep_damage = random.randint(1, 10)
self.magic_wep_damage = random.randint(1, 10)
self.armor_defence = random.randint(0, 5)
self.armor_magic_protection = random.randint(0, 5)
self.damage = 0
def meleeAttack(self, opponent):
attackValue = self.strength + random.randint(1, 6)
defenseValue = opponent.strength + opponent.armor_defence
damage = attackValue - defenseValue
if damage > 0:
opponent.damage += (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.damage += (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.damage += (damage + self.magic_wep_damage - opponent.armor_magic_protection)
def reset(self):
self.damage = 0
FIELDNAMES = ["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",
"strategy"]
RESULT_FILE = open('data.csv', 'w', newline='')
FILE_WRITER = csv.writer(RESULT_FILE, dialect='excel', delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
FILE_WRITER.writerow(FIELDNAMES)
SETUP_RESULTS = [[], [], []]
MAX_COMBAT_TIME = 20
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.damage >= e.health:
SETUP_RESULTS[player_att_type].append(p.health - p.damage)
break
if enemy_att_type == 0:
e.meleeAttack(p)
elif enemy_att_type == 1:
e.rangeAttack(p)
else:
e.magicAttack(p)
if p.damage >= p.health:
SETUP_RESULTS[player_att_type].append(0)
break
current_iteration += 1
if current_iteration >= MAX_COMBAT_TIME:
SETUP_RESULTS[player_att_type].append(0)
break
p.reset()
e.reset()
for trial in range(10000):
stat_seed = urandom(16)
random.seed(stat_seed)
player = Stats()
enemy = Stats()
enemy_attack_type = random.randint(0, 2) # Enemy weapon choice
for i in range(30):
combat_seed = urandom(16)
try_combat(combat_seed, player, enemy, 0, enemy_attack_type)
try_combat(combat_seed, player, enemy, 1, enemy_attack_type)
try_combat(combat_seed, player, enemy, 2, enemy_attack_type)
for i, series in enumerate(SETUP_RESULTS):
SETUP_RESULTS[i] = statistics.mean(series)
strategy = "PASS"
if any(SETUP_RESULTS):
max_index = SETUP_RESULTS.index(max(SETUP_RESULTS))
if max_index == 0:
strategy = "MELEE"
elif max_index == 1:
strategy = "RANGED"
elif max_index == 2:
strategy = "MAGIC"
enemy_damage = 0
if enemy_attack_type == 0:
enemy_attack_type = "MELEE"
enemy_damage = enemy.melee_wep_damage
elif enemy_attack_type == 1:
enemy_attack_type = "RANGED"
enemy_damage = enemy.ranged_wep_damage
elif enemy_attack_type == 2:
enemy_attack_type = "MAGIC"
enemy_damage = enemy.magic_wep_damage
FILE_WRITER.writerow([nominalize(player.strength, 10),
nominalize(player.agility, 10),
nominalize(player.wisdom, 10),
nominalize(player.health, 50),
nominalize(player.melee_wep_damage, 10),
nominalize(player.ranged_wep_damage, 10),
nominalize(player.magic_wep_damage, 10),
nominalize(player.armor_defence, 5),
nominalize(player.armor_magic_protection, 5),
nominalize(enemy.strength, 10),
nominalize(enemy.agility, 10),
nominalize(enemy.wisdom, 10),
nominalize(enemy.health, 50),
nominalize(enemy_damage, 10),
nominalize(enemy.armor_defence, 5),
nominalize(enemy.armor_magic_protection, 5),
enemy_attack_type,
strategy])
SETUP_RESULTS = [[], [], []]
if trial%100 == 0:
print("Trials done: " + str(trial))