merged jakfit-feature-treesearch and jak-dev

This commit is contained in:
kabix09 2021-04-25 22:48:55 +02:00
parent 3b69b78d11
commit da9fdc0bb9
6 changed files with 277 additions and 240 deletions

View File

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

15
direction.py Normal file
View File

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

346
hero.py
View File

@ -1,8 +1,15 @@
import random
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
class Player(Creature):
def __init__(self, unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g, w2, w3):
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
@ -17,35 +24,18 @@ class Player(Creature):
self.armor = arm
self.isBox = False
self.isCreature = False
self.directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
self.direction = 0
self.queue=[]
self.hasgoalchest=False
self.openedchests=0
def rotate(self, clockwise=True):
if clockwise:
self.direction = (self.direction + 1) % 4
else:
self.direction = (self.direction + 3) % 4
def moveFwd(self):
possible_steps = self.model.grid.get_neighborhood(
self.pos,
moore=False,
include_center=False)
new_position = (self.pos[0] + self.directions[self.direction][0],
self.pos[1] + self.directions[self.direction][1])
if new_position in possible_steps:
self.model.grid.move_agent(self, new_position)
print("moved to ", new_position)
# def move(self): # OLD
# possible_steps = self.model.grid.get_neighborhood(
# self.pos,
# moore=True,
# include_center=False)
# new_position = self.random.choice(possible_steps)
# self.model.grid.move_agent(self, new_position)
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)
@ -129,10 +119,10 @@ class Player(Creature):
self.gold = self.gold + chest.gold
print("Chest opened. Gold inside:", chest.gold)
chest.gold = 0
self.openedchests+=1
self.hasgoalchest=False
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
#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
@ -151,160 +141,172 @@ class Player(Creature):
# self.weapon3 = chest.loot
# chest.loot = buffer
def findShortestPathToTarget(self):
visited = []
precedessors = {}
queue = [self.pos]
found_target = False
#- - - - bfs & successor - - - -#
def successor(self, append):
while queue:
cur_pos = queue.pop(0)
rotateLeft = AgentState(
append.get_x(),
append.get_y(),
append.get_direction().counterClockwise()
)
#check for target
cell_contents = self.model.grid.get_cell_list_contents([cur_pos])
if cell_contents and any([isinstance(thing, Box) for thing in cell_contents]):
found_target = cur_pos
self.hasgoalchest=True
break
rotateRight = AgentState(
append.get_x(),
append.get_y(),
append.get_direction().clockwise()
)
#enqueue safe unvisited neighbours
neighbours = self.model.grid.get_neighborhood(
cur_pos,
moore=False,
include_center=False)
for cell in neighbours:
#if cell hasn't been visited and the contents don't include creatures
if cell not in visited and not any([isinstance(thing, Creature) for thing in self.model.grid.get_cell_list_contents([cell])]):
queue.append(cell)
precedessors[cell] = cur_pos
move_x = 0
move_y = 0
visited.append(cur_pos)
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 found_target:
path = [found_target]
while True:
if path[0] == self.pos:
break
precedessor = precedessors[path[0]]
path.insert(0, precedessor)
return path
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 "no chests left"
return [
[actions["rotateLeft"], rotateLeft],
[actions["moveForward"], moveForward],
[actions["rotateRight"], rotateRight]
]
# Funkcja konwertujaca wspolrzedne nastepnego pola do odwiedzenia
# na kolejke akcji do wykonania
def graphsearch(self, fringe, explored, istate, succesorFunction, goalState):
finalActionList = []
fringe.append([None, istate]) # at beginning do nothing
# tl - turn left, tr - turn right, fwd - forward, op - open
# queue - kolejka akcji do zrobienia, pole klasy Player
# path - kolejka pol do odwiedzenia, pole klasy Player
while len(fringe) != 0:
_flag = True
# pole to element wziety z kolejki path
if len(fringe) == 0:
return False
def actionPlanner(self, cell_from, cell_to):
x0 = cell_from[0]
y0 = cell_from[1]
x = cell_to[0]
y = cell_to[1]
if (x > x0):
if (self.direction == 1):
self.queue.append("fwd")
elif (self.direction == 0):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (self.direction == 2):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
tmpState = fringe.pop(0)
# build dictionary
parent = tmpState[1].get_predecessor() #fetch paren state
tmpState[1].set_predecessor(None) # clear predecessor - don't build a tree chain
if parent is None:
finalActionList.append([parent, tmpState])
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.insert("fwd")
elif (x < x0):
if (self.direction == 3):
self.queue.append("fwd")
elif (self.direction == 0):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 2):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (y > y0):
if (self.direction == 0):
self.queue.append("fwd")
elif (self.direction == 1):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 3):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (y < y0):
if (self.direction == 2):
self.queue.append("fwd")
elif (self.direction == 3):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
elif (self.direction == 1):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (len(self.path)==0):
self.queue.append("op")
finalActionList.append([parent[1], tmpState]) # pair(key, value) - key: parent state, value: current state + action
if tmpState[1].get_x() == goalState.get_x() and tmpState[1].get_y() == goalState.get_y():
return finalActionList
explored.append(tmpState)
tmpList = succesorFunction(tmpState[1])
for newState in tmpList:
_flag = True
if newState[1] is None:
continue
for fringeState in fringe:
if fringeState[1].get_x() == newState[1].get_x() and fringeState[1].get_y() == newState[1].get_y() and fringeState[1].get_direction() == newState[1].get_direction():
_flag = False
for exploredState in explored:
if exploredState[1].get_x() == newState[1].get_x() and exploredState[1].get_y() == newState[1].get_y() and exploredState[1].get_direction() == newState[1].get_direction():
_flag = False
if _flag:
newState[1].set_predecessor(tmpState)
fringe.append(newState)
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 self.path=="no chests left":
print("no chests left, life has lost meaning")
# 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: #build list from dictionary by last element
goalActionsList = []
#keysList = list(self.__actionsCollection.keys())
#valuesList = list(self.__actionsCollection.values())
stateWithChest = self.__actionsCollection[-1] # fetch last item
#stateWithChest:
# [
# [0] key - parent ActionState: object,
# [1] value - node successor:
# {
# [0] action: string - action to get state
# [1] AgentState: object - current state
# }
# ]
goalActionsList.append(stateWithChest[1][0]) # save action
tmpState = stateWithChest[0]
while tmpState is not None: # iterate while key (parent state) != None
index = 0
for valeState in self.__actionsCollection: # find new key(parent status) index in array data
if valeState[1][1].get_x() == tmpState.get_x() and valeState[1][1].get_y() == tmpState.get_y() and valeState[1][1].get_direction() == tmpState.get_direction():
break
index += 1
goalActionsList.append(self.__actionsCollection[index][1][0]) # get action
tmpState = self.__actionsCollection[index][0] # get state - and next we will find key equal it's value
self.__actionsCollection = list(reversed(goalActionsList))
self.__actionsCollection = [action for action in self.__actionsCollection if action is not None] # remove first None action
else:
print("the player should follow this path:", self.path)
for i in range(len(self.path)-1): #iteruje po kolejnych krotkach ze współrzędnymi pól
#actionPlanner ma się wykonać i-1 razy, bo dla ostatniego pola już nie
self.actionPlanner(self.path[i], self.path[i+1]) #dla każdego pola dodaje do kolejki kilka akcji potrzebnych żeby do niego dojść
print(self.queue)
self.direction=0 # bo po obrotach w wyznaczaniu ścieżki trzeba wrócić do orientacji takiej, jaka była na starcie wyznaczania
#to znaczy, że po otwarciu skrzynki też się zeruje żeby zacząć wyznaczanie i chodzenie od takiej samej
while len(self.queue)!=0:
self.action=self.queue.pop(0)
if self.action=="tr":
self.rotate(True)
print("tr'd, direction: ", self.direction)
break
elif self.action=="tl":
self.rotate(False)
print("tl'd, direction: ", self.direction)
break
elif self.action=="fwd":
self.moveFwd()
break
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):
@ -313,7 +315,7 @@ class Player(Creature):
opponent = cellmates[0]
print("Fighting")
self.fightOrFlight(opponent)
# print("HP: " + str(self.health) + " / " + str(self.maxHealth))
# print("HP: " + str(self.health) + " / " + str(self.maxHealth))
print("Gold: " + str(self.gold))
else:
print("HP: 0 / " + str(self.maxHealth))

View File

@ -16,6 +16,7 @@ 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ą?
@ -23,12 +24,13 @@ class GameMap(Model):
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)
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)
@ -37,6 +39,7 @@ class GameMap(Model):
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
@ -54,6 +57,9 @@ class GameMap(Model):
# 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

View File

@ -18,5 +18,5 @@ server = ModularServer(GameMap,
[grid],
"Map",
{"x":10, "y":10})
server.port = 8521
server.port = 8080
server.launch()

36
state.py Normal file
View File

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