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

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)

338
hero.py
View File

@ -1,8 +1,15 @@
import random
from mesa import Agent from mesa import Agent
from othercharacters import dice, Box, Creature, Armor, Weapon from othercharacters import dice, Box, Creature, Armor, Weapon
from actions import actions, actionsInterpreter
from state import AgentState
from direction import Direction
class Player(Creature): 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) super().__init__(unique_id, model, n, s, a, w, maxhp, hp, weap, arm, g)
self.name = n self.name = n
self.strength = s self.strength = s
@ -17,35 +24,18 @@ class Player(Creature):
self.armor = arm self.armor = arm
self.isBox = False self.isBox = False
self.isCreature = False self.isCreature = False
self.directions = [[0, 1], [1, 0], [0, -1], [-1, 0]] self.directions = {
self.direction = 0 Direction.N : [0, 1],
Direction.E : [1, 0],
Direction.S : [0, -1],
Direction.W : [-1, 0]
}
self.direction = Direction.N
self.queue = [] self.queue = []
self.hasgoalchest = False self.hasgoalchest = False
self.openedchests = 0 self.openedchests = 0
self.__listOfChests = listOfChests
def rotate(self, clockwise=True): self.__actionsCollection = []
if clockwise:
self.direction = (self.direction + 1) % 4
else:
self.direction = (self.direction + 3) % 4
def moveFwd(self):
possible_steps = self.model.grid.get_neighborhood(
self.pos,
moore=False,
include_center=False)
new_position = (self.pos[0] + self.directions[self.direction][0],
self.pos[1] + self.directions[self.direction][1])
if new_position in possible_steps:
self.model.grid.move_agent(self, new_position)
print("moved to ", new_position)
# def move(self): # OLD
# possible_steps = self.model.grid.get_neighborhood(
# self.pos,
# moore=True,
# include_center=False)
# new_position = self.random.choice(possible_steps)
# self.model.grid.move_agent(self, new_position)
def meleeAttack(self, opponent): def meleeAttack(self, opponent):
attackValue = self.strength + dice(6) attackValue = self.strength + dice(6)
@ -132,7 +122,7 @@ class Player(Creature):
self.openedchests += 1 self.openedchests += 1
self.hasgoalchest = False self.hasgoalchest = False
chest.model.grid.remove_agent(chest) 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): # if isinstance(chest.loot,Armor):
# buffer = self.armor # buffer = self.armor
# self.armor = chest.loot # self.armor = chest.loot
@ -151,160 +141,172 @@ class Player(Creature):
# self.weapon3 = chest.loot # self.weapon3 = chest.loot
# chest.loot = buffer # chest.loot = buffer
def findShortestPathToTarget(self): #- - - - bfs & successor - - - -#
visited = [] def successor(self, append):
precedessors = {}
queue = [self.pos]
found_target = False
while queue: rotateLeft = AgentState(
cur_pos = queue.pop(0) append.get_x(),
append.get_y(),
append.get_direction().counterClockwise()
)
#check for target rotateRight = AgentState(
cell_contents = self.model.grid.get_cell_list_contents([cur_pos]) append.get_x(),
if cell_contents and any([isinstance(thing, Box) for thing in cell_contents]): append.get_y(),
found_target = cur_pos append.get_direction().clockwise()
self.hasgoalchest=True )
break
#enqueue safe unvisited neighbours move_x = 0
neighbours = self.model.grid.get_neighborhood( move_y = 0
cur_pos,
moore=False,
include_center=False)
for cell in neighbours:
#if cell hasn't been visited and the contents don't include creatures
if cell not in visited and not any([isinstance(thing, Creature) for thing in self.model.grid.get_cell_list_contents([cell])]):
queue.append(cell)
precedessors[cell] = cur_pos
visited.append(cur_pos) if 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: 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:
path = [found_target] moveForward = AgentState(
while True: append.get_x() + move_x,
if path[0] == self.pos: append.get_y() + move_y,
break append.get_direction()
precedessor = precedessors[path[0]] )
path.insert(0, precedessor)
return path
return "no chests left"
# Funkcja konwertujaca wspolrzedne nastepnego pola do odwiedzenia
# na kolejke akcji do wykonania
# tl - turn left, tr - turn right, fwd - forward, op - open
# queue - kolejka akcji do zrobienia, pole klasy Player
# path - kolejka pol do odwiedzenia, pole klasy Player
# pole to element wziety z kolejki path
def actionPlanner(self, cell_from, cell_to):
x0 = cell_from[0]
y0 = cell_from[1]
x = cell_to[0]
y = cell_to[1]
if (x > x0):
if (self.direction == 1):
self.queue.append("fwd")
elif (self.direction == 0):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (self.direction == 2):
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd")
else: else:
self.queue.append("tr") moveForward = None
self.rotate(True)
self.queue.append("tr") return [
self.rotate(True) [actions["rotateLeft"], rotateLeft],
self.queue.insert("fwd") [actions["moveForward"], moveForward],
elif (x < x0): [actions["rotateRight"], rotateRight]
if (self.direction == 3): ]
self.queue.append("fwd")
elif (self.direction == 0): def graphsearch(self, fringe, explored, istate, succesorFunction, goalState):
self.queue.append("tl") finalActionList = []
self.rotate(False) fringe.append([None, istate]) # at beginning do nothing
self.queue.append("fwd")
elif (self.direction == 2): while len(fringe) != 0:
self.queue.append("tr") _flag = True
self.rotate(True)
self.queue.append("fwd") if len(fringe) == 0:
return False
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: else:
self.queue.append("tr") finalActionList.append([parent[1], tmpState]) # pair(key, value) - key: parent state, value: current state + action
self.rotate(True)
self.queue.append("tr")
self.rotate(True) if tmpState[1].get_x() == goalState.get_x() and tmpState[1].get_y() == goalState.get_y():
self.queue.append("fwd") return finalActionList
elif (y > y0):
if (self.direction == 0): explored.append(tmpState)
self.queue.append("fwd")
elif (self.direction == 1): tmpList = succesorFunction(tmpState[1])
self.queue.append("tl") for newState in tmpList:
self.rotate(False) _flag = True
self.queue.append("fwd")
elif (self.direction == 3): if newState[1] is None:
self.queue.append("tr") continue
self.rotate(True)
self.queue.append("fwd") for fringeState in fringe:
else: 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():
self.queue.append("tr") _flag = False
self.rotate(True)
self.queue.append("tr") for exploredState in explored:
self.rotate(True) 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():
self.queue.append("fwd") _flag = False
elif (y < y0):
if (self.direction == 2): if _flag:
self.queue.append("fwd") newState[1].set_predecessor(tmpState)
elif (self.direction == 3): fringe.append(newState)
self.queue.append("tl")
self.rotate(False)
self.queue.append("fwd") return None
elif (self.direction == 1):
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
else:
self.queue.append("tr")
self.rotate(True)
self.queue.append("tr")
self.rotate(True)
self.queue.append("fwd")
elif (len(self.path)==0):
self.queue.append("op")
def step(self): def step(self):
if self.health > 0: if self.health > 0:
print("position: ", self.pos) print("position: ", self.pos)
# print("direction: ", self.direction) # print("direction: ", self.direction)
if not self.hasgoalchest: # jeśli nie ma wyznaczonej skrzynki do której idzie to robi bfs żeby ją wyznaczyć if not self.hasgoalchest: # jeśli nie ma wyznaczonej skrzynki do której idzie to robi bfs żeby ją wyznaczyć
self.path=self.findShortestPathToTarget() # self.path=self.findShortestPathToTarget()
if self.path=="no chests left": if len(self.__listOfChests) != 0:
print("no chests left, life has lost meaning") # 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: else:
print("the player should follow this path:", self.path) raise Exception("WIN!!! :D")
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 elif len(self.__actionsCollection) == 0: # jeśli jest wyznaczona skrzynka - cel & nie ma akcji do wykonania - cel osiągnięty
self.actionPlanner(self.path[i], self.path[i+1]) #dla każdego pola dodaje do kolejki kilka akcji potrzebnych żeby do niego dojść self.hasgoalchest = False
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 elif len(self.__actionsCollection) != 0: # jeśli jest wyznaczona skrzynka - cel & są akcje do wykoannia to je realizuje
#to znaczy, że po otwarciu skrzynki też się zeruje żeby zacząć wyznaczanie i chodzenie od takiej samej
while len(self.queue)!=0: actionIndex = self.__actionsCollection[0] # ignore -1 because it's None
self.action=self.queue.pop(0) self.__actionsCollection.remove(actionIndex)
if self.action=="tr":
self.rotate(True) newState = actionsInterpreter(actionIndex, AgentState(self.pos[0], self.pos[1], self.direction), self.directions)
print("tr'd, direction: ", self.direction)
break self.model.grid.move_agent(self, (newState.get_x(), newState.get_y()))
elif self.action=="tl": self.direction = newState.get_direction()
self.rotate(False)
print("tl'd, direction: ", self.direction) print("moved to - ", [newState.get_x(), newState.get_y()])
break
elif self.action=="fwd":
self.moveFwd()
break
cellmates = self.model.grid.get_cell_list_contents([self.pos]) cellmates = self.model.grid.get_cell_list_contents([self.pos])
if len(cellmates) > 1: if len(cellmates) > 1:
if isinstance(cellmates[0], Box): if isinstance(cellmates[0], Box):

View File

@ -16,6 +16,7 @@ creatures_number = 5
class GameMap(Model): class GameMap(Model):
def __init__(self, x, y): def __init__(self, x, y):
self.listOfChests = []
self.grid = MultiGrid(x, y, False) self.grid = MultiGrid(x, y, False)
self.schedule = RandomActivation(self) # agenci losowo po kolei wykonują swoje akcje self.schedule = RandomActivation(self) # agenci losowo po kolei wykonują swoje akcje
# to jest potrzebne przy założeniu, że potwory chodzą? # to jest potrzebne przy założeniu, że potwory chodzą?
@ -23,12 +24,13 @@ class GameMap(Model):
self.creatures_number = creatures_number self.creatures_number = creatures_number
self.running = True self.running = True
# player = Player(1000, self) # 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) self.schedule.add(player)
x = self.random.randrange(self.grid.width) x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height) y = self.random.randrange(self.grid.height)
self.grid.place_agent(player, (x, y)) self.grid.place_agent(player, (x, y))
for i in range(self.boxes_number): for i in range(self.boxes_number):
box = Box(i, self) box = Box(i, self)
# self.schedule.add(box) # self.schedule.add(box)
@ -37,6 +39,7 @@ class GameMap(Model):
if self.grid.is_cell_empty((x, y)): if self.grid.is_cell_empty((x, y)):
self.grid.place_agent(box, (x, y)) self.grid.place_agent(box, (x, y))
self.schedule.add(box) self.schedule.add(box)
self.listOfChests.append([i, [x, y]]) #fetching chest position - [index, [OX, OY]]
else: else:
pass pass
@ -54,6 +57,9 @@ class GameMap(Model):
# self.datacollector=DataCollector #informacje o stanie planszy, pozycja agenta # self.datacollector=DataCollector #informacje o stanie planszy, pozycja agenta
def get_listOfChests(self):
return self.listOfChests
def step(self): def step(self):
self.schedule.step() self.schedule.step()
# self.datacollector.collect(self) #na razie niepotrzebne # self.datacollector.collect(self) #na razie niepotrzebne

View File

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