diff --git a/actions.py b/actions.py deleted file mode 100644 index 389ab12..0000000 --- a/actions.py +++ /dev/null @@ -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 -} diff --git a/hero.py b/hero.py deleted file mode 100644 index 3d1b6b6..0000000 --- a/hero.py +++ /dev/null @@ -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)) diff --git a/othercharacters.py b/othercharacters.py deleted file mode 100644 index b558ec1..0000000 --- a/othercharacters.py +++ /dev/null @@ -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) - diff --git a/server.py b/server.py index 1d0b90d..ae17886 100644 --- a/server.py +++ b/server.py @@ -1,4 +1,4 @@ -from model import GameMap +from src.agent.map.gameMap import GameMap from mesa.visualization.modules import CanvasGrid from mesa.visualization.ModularVisualization import ModularServer @@ -10,13 +10,14 @@ def player_representation(agent): portrayal["Shape"] = "sprites/box.png" portrayal["Layer"] = 0 elif agent.isCreature: - portrayal["Shape"]='sprites/goblin.png' + portrayal["Shape"] = 'sprites/goblin.png' return portrayal + grid = CanvasGrid(player_representation, 10, 10, 500, 500) server = ModularServer(GameMap, [grid], "Map", - {"x":10, "y":10}) + {"x": 10, "y": 10}) server.port = 8081 -server.launch() \ No newline at end of file +server.launch() diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/__pycache__/__init__.cpython-39.pyc b/src/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..1ab9b42 Binary files /dev/null and b/src/__pycache__/__init__.cpython-39.pyc differ diff --git a/src/__pycache__/direction.cpython-39.pyc b/src/__pycache__/direction.cpython-39.pyc new file mode 100644 index 0000000..923230d Binary files /dev/null and b/src/__pycache__/direction.cpython-39.pyc differ diff --git a/src/agent/__init__.py b/src/agent/__init__.py new file mode 100644 index 0000000..dbf109d --- /dev/null +++ b/src/agent/__init__.py @@ -0,0 +1,4 @@ +from .hero import Player +from .map.gameMap import GameMap +from .model import * +from .state import AgentState diff --git a/src/agent/__pycache__/__init__.cpython-39.pyc b/src/agent/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..b489ef8 Binary files /dev/null and b/src/agent/__pycache__/__init__.cpython-39.pyc differ diff --git a/src/agent/__pycache__/hero.cpython-39.pyc b/src/agent/__pycache__/hero.cpython-39.pyc new file mode 100644 index 0000000..6c15015 Binary files /dev/null and b/src/agent/__pycache__/hero.cpython-39.pyc differ diff --git a/src/agent/hero.py b/src/agent/hero.py new file mode 100644 index 0000000..06f052d --- /dev/null +++ b/src/agent/hero.py @@ -0,0 +1,199 @@ +import random + +from src.agent.model import * +from src.agent.state import AgentState +from src.direction import Direction +from src.treesearch.actionsInterpreter import ActionInterpreter + +from src.treesearch.bfs import BFS + + +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.direction = Direction.N + self.queue = [] + self.has_goal_chest = False + self.opened_chests = 0 + self.__listOfChests = list_of_chests + self.__actionsCollection = [] + + def melee_attack(self, opponent): + attack_value = self.strength + roll_the_dice(6) + defense_value = opponent.strength + opponent.armor.defence + damage = attack_value - defense_value + if damage > 0: + opponent.health = opponent.health - (damage + self.weapon1.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.damage - opponent.armor.defence > 0): + opponent.health = opponent.health - (damage + self.weapon2.damage - opponent.armor.defence) + + 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.damage - opponent.armor.mag_protection > 0): + opponent.health = opponent.health - (damage + self.weapon3.damage - opponent.armor.mag_protection) + + def fight_or_flight(self, opponent): + combat = True + while combat: + choice = roll_the_dice(4) + print("roll_the_dice rolled:", choice) + if choice == 1: + running_speed = self.agility + roll_the_dice(6) + opponent_speed = opponent.agility + roll_the_dice(6) + if running_speed > opponent_speed: + combat = False + print("Player ran away") + self.step() + else: + opponent.default_attack(self) + if self.health <= 0: + combat = False + print("Player died :/") + elif choice == 2: + self.melee_attack(opponent) + if opponent.health > 0: + opponent.default_attack(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.range_attack(opponent) + if opponent.health > 0: + opponent.default_attack(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.magic_attack(opponent) + if opponent.health > 0: + opponent.default_attack(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 open_chest(self, chest): + self.gold = self.gold + chest.gold + print("------Chest opened. Gold inside:", chest.gold, "-----") + chest.gold = 0 + self.opened_chests += 1 + self.has_goal_chest = 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.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): + self.open_chest(cellmates[0]) + else: + opponent = cellmates[0] + print("Fighting") + self.fight_or_flight(opponent) + # print("HP: " + str(self.health) + " / " + str(self.maxHealth)) + print("Gold: " + str(self.gold)) + else: + print("HP: 0 / " + str(self.maxHealth)) diff --git a/src/agent/map/__pycache__/gameMap.cpython-39.pyc b/src/agent/map/__pycache__/gameMap.cpython-39.pyc new file mode 100644 index 0000000..b3c5160 Binary files /dev/null and b/src/agent/map/__pycache__/gameMap.cpython-39.pyc differ diff --git a/model.py b/src/agent/map/gameMap.py similarity index 84% rename from model.py rename to src/agent/map/gameMap.py index c67a5ea..7306d5d 100644 --- a/model.py +++ b/src/agent/map/gameMap.py @@ -1,65 +1,69 @@ -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 +from mesa import Model +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 + +# from mesa.datacollection import DataCollector + +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, roll_the_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_list_of_chests(self): + return self.listOfChests + + def step(self): + self.schedule.step() + # self.datacollector.collect(self) #na razie niepotrzebne diff --git a/src/agent/model/__init__.py b/src/agent/model/__init__.py new file mode 100644 index 0000000..6d42ab3 --- /dev/null +++ b/src/agent/model/__init__.py @@ -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 diff --git a/src/agent/model/__pycache__/armor.cpython-39.pyc b/src/agent/model/__pycache__/armor.cpython-39.pyc new file mode 100644 index 0000000..af9d358 Binary files /dev/null and b/src/agent/model/__pycache__/armor.cpython-39.pyc differ diff --git a/src/agent/model/__pycache__/box.cpython-39.pyc b/src/agent/model/__pycache__/box.cpython-39.pyc new file mode 100644 index 0000000..f6499ac Binary files /dev/null and b/src/agent/model/__pycache__/box.cpython-39.pyc differ diff --git a/src/agent/model/__pycache__/creature.cpython-39.pyc b/src/agent/model/__pycache__/creature.cpython-39.pyc new file mode 100644 index 0000000..f91d40c Binary files /dev/null and b/src/agent/model/__pycache__/creature.cpython-39.pyc differ diff --git a/src/agent/model/__pycache__/wall.cpython-39.pyc b/src/agent/model/__pycache__/wall.cpython-39.pyc new file mode 100644 index 0000000..0747808 Binary files /dev/null and b/src/agent/model/__pycache__/wall.cpython-39.pyc differ diff --git a/src/agent/model/__pycache__/weapon.cpython-39.pyc b/src/agent/model/__pycache__/weapon.cpython-39.pyc new file mode 100644 index 0000000..eb4e9e8 Binary files /dev/null and b/src/agent/model/__pycache__/weapon.cpython-39.pyc differ diff --git a/src/agent/model/armor.py b/src/agent/model/armor.py new file mode 100644 index 0000000..09d8995 --- /dev/null +++ b/src/agent/model/armor.py @@ -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 + diff --git a/src/agent/model/box.py b/src/agent/model/box.py new file mode 100644 index 0000000..d8709f9 --- /dev/null +++ b/src/agent/model/box.py @@ -0,0 +1,13 @@ +from mesa import Agent +from .dice.dice import roll_the_dice + + +class Box(Agent): + def __init__(self, unique_id, model): + super().__init__(unique_id, model) + self.gold = 3 * roll_the_dice(6) + self.isBox = True + self.isCreature = False + + def step(self): + pass diff --git a/src/agent/model/creature.py b/src/agent/model/creature.py new file mode 100644 index 0000000..0c1309b --- /dev/null +++ b/src/agent/model/creature.py @@ -0,0 +1,47 @@ +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 + + def melee_attack(self, opponent): + attack_value = self.strength + roll_the_dice(6) + defense_value = opponent.strength + opponent.armor.defence + damage = attack_value - defense_value + if damage > 0: + opponent.health = opponent.health - (damage + self.weapon1.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.damage - opponent.armor.defence > 0): + opponent.health = opponent.health - (damage + self.weapon1.damage - opponent.armor.defence) + + 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.damage - opponent.armor.mag_protection > 0): + opponent.health = opponent.health - (damage + self.weapon1.damage - opponent.armor.mag_protection) + + def default_attack(self, opponent): + if self.weapon1.type == "Meele": + self.melee_attack(opponent) + elif self.weapon1.type == "Range": + self.range_attack(opponent) + else: + self.magic_attack(opponent) diff --git a/src/agent/model/dice/__init__.py b/src/agent/model/dice/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/agent/model/dice/__pycache__/dice.cpython-39.pyc b/src/agent/model/dice/__pycache__/dice.cpython-39.pyc new file mode 100644 index 0000000..c27cfdd Binary files /dev/null and b/src/agent/model/dice/__pycache__/dice.cpython-39.pyc differ diff --git a/src/agent/model/dice/dice.py b/src/agent/model/dice/dice.py new file mode 100644 index 0000000..642e2fa --- /dev/null +++ b/src/agent/model/dice/dice.py @@ -0,0 +1,5 @@ +import random + + +def roll_the_dice(number): + return random.randint(1, number) \ No newline at end of file diff --git a/src/agent/model/wall.py b/src/agent/model/wall.py new file mode 100644 index 0000000..859e0dc --- /dev/null +++ b/src/agent/model/wall.py @@ -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 diff --git a/src/agent/model/weapon.py b/src/agent/model/weapon.py new file mode 100644 index 0000000..fd90233 --- /dev/null +++ b/src/agent/model/weapon.py @@ -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 diff --git a/state.py b/src/agent/state.py similarity index 100% rename from state.py rename to src/agent/state.py diff --git a/src/dictionary/__pycache__/actions.cpython-39.pyc b/src/dictionary/__pycache__/actions.cpython-39.pyc new file mode 100644 index 0000000..1551064 Binary files /dev/null and b/src/dictionary/__pycache__/actions.cpython-39.pyc differ diff --git a/src/dictionary/actions.py b/src/dictionary/actions.py new file mode 100644 index 0000000..5fc1ee4 --- /dev/null +++ b/src/dictionary/actions.py @@ -0,0 +1,5 @@ +actions = { + "rotate_left": -1, + "move_forward": 0, + "rotate_right": 1 + } diff --git a/src/dictionary/directions.py b/src/dictionary/directions.py new file mode 100644 index 0000000..1483cbd --- /dev/null +++ b/src/dictionary/directions.py @@ -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] + } diff --git a/direction.py b/src/direction.py similarity index 52% rename from direction.py rename to src/direction.py index 67d353e..69bf510 100644 --- a/direction.py +++ b/src/direction.py @@ -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) \ No newline at end of file + def counter_clockwise(self): + v = (self.value - 1) % 4 + return Direction(v) diff --git a/src/items/__pycache__/armory.cpython-39.pyc b/src/items/__pycache__/armory.cpython-39.pyc new file mode 100644 index 0000000..ed818b7 Binary files /dev/null and b/src/items/__pycache__/armory.cpython-39.pyc differ diff --git a/armory.py b/src/items/armory.py similarity index 93% rename from armory.py rename to src/items/armory.py index d8a872e..9aaf6d2 100644 --- a/armory.py +++ b/src/items/armory.py @@ -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) @@ -64,7 +63,7 @@ A16 = Armor("Magical Plate Armor", 3, 2) # 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)) diff --git a/src/tree/__pycache__/node.cpython-39.pyc b/src/tree/__pycache__/node.cpython-39.pyc new file mode 100644 index 0000000..14a4e69 Binary files /dev/null and b/src/tree/__pycache__/node.cpython-39.pyc differ diff --git a/node.py b/src/tree/node.py similarity index 64% rename from node.py rename to src/tree/node.py index 77f60ab..a4a4e49 100644 --- a/node.py +++ b/src/tree/node.py @@ -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() diff --git a/src/treesearch/__init__.py b/src/treesearch/__init__.py new file mode 100644 index 0000000..a58caa9 --- /dev/null +++ b/src/treesearch/__init__.py @@ -0,0 +1,3 @@ +from .bfs import BFS +from .actionsInterpreter import ActionInterpreter +from .heuristic import * diff --git a/src/treesearch/__pycache__/actionsInterpreter.cpython-39.pyc b/src/treesearch/__pycache__/actionsInterpreter.cpython-39.pyc new file mode 100644 index 0000000..e087dbd Binary files /dev/null and b/src/treesearch/__pycache__/actionsInterpreter.cpython-39.pyc differ diff --git a/src/treesearch/__pycache__/bfs.cpython-39.pyc b/src/treesearch/__pycache__/bfs.cpython-39.pyc new file mode 100644 index 0000000..b25d819 Binary files /dev/null and b/src/treesearch/__pycache__/bfs.cpython-39.pyc differ diff --git a/src/treesearch/actionsInterpreter.py b/src/treesearch/actionsInterpreter.py new file mode 100644 index 0000000..20b1af9 --- /dev/null +++ b/src/treesearch/actionsInterpreter.py @@ -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 diff --git a/src/treesearch/bfs.py b/src/treesearch/bfs.py new file mode 100644 index 0000000..fdf930b --- /dev/null +++ b/src/treesearch/bfs.py @@ -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 = 10 + 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 diff --git a/src/treesearch/heuristic/__init__.py b/src/treesearch/heuristic/__init__.py new file mode 100644 index 0000000..1e52a18 --- /dev/null +++ b/src/treesearch/heuristic/__init__.py @@ -0,0 +1 @@ +from .manhattan import manhattan \ No newline at end of file diff --git a/src/treesearch/heuristic/manhattan.py b/src/treesearch/heuristic/manhattan.py new file mode 100644 index 0000000..a3944ba --- /dev/null +++ b/src/treesearch/heuristic/manhattan.py @@ -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())