class Agent: """""" counter = -1 # Contador de passos no plano, usado na deliberação def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model self.prob = Problem() # @TODO T_AAFP - criar crencas sobre as paredes do labirinto self.prob.createMaze(9, 9) self.prob.mazeBelief.putVerticalWall(0,1,0) self.prob.mazeBelief.putVerticalWall(0,0,1) self.prob.mazeBelief.putVerticalWall(5,8,1) self.prob.mazeBelief.putVerticalWall(5,5,2) self.prob.mazeBelief.putVerticalWall(8,8,2) self.prob.mazeBelief.putHorizontalWall(4,7,0) self.prob.mazeBelief.putHorizontalWall(7,7,1) self.prob.mazeBelief.putHorizontalWall(3,5,2) self.prob.mazeBelief.putHorizontalWall(3,5,3) self.prob.mazeBelief.putHorizontalWall(7,7,3) self.prob.mazeBelief.putVerticalWall(6,7,4) self.prob.mazeBelief.putVerticalWall(5,6,5) self.prob.mazeBelief.putVerticalWall(5,7,7) # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col) self.cost = 0 self.nextState = self.prob.initialState # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # @TODO T_AAFP - defina estado objetivo # Define o estado objetivo # self.prob.defGoalState(?, ?) self.prob.defGoalState(0,8) # o metodo abaixo serve apenas para a view desenhar a pos objetivo # self.model.setGoalPos(2,8) self.model.setGoalPos(0,8) # Plano de busca - inicialmente vazio (equivale a solucao) self.plan = None def printPlan(self): """Apresenta o plano de busca.""" print("--- PLANO ---") # @TODO: Implementação do aluno for plannedAction in self.plan: print("{} > ".format(action[plannedAction]),end='') print("FIM\n\n") def deliberate(self): # Primeira chamada, realiza busca para elaborar um plano # @TODO T_AAFP: Implementação do aluno if self.counter == -1: # @TODO T_AAFP: dar um plano fixo ao agente (preh-programado) - ver cardinal.py # @TODO T_AAFP: plano = solucao: contem acoes que levam o agente ateh o estado objetivo self.plan = [0,0,0,1,2,2,2,2,1,1,2,0,0] if self.plan != None: self.printPlan() else: print("SOLUÇÃO NÃO ENCONTRADA") return -1 # Nas demais chamadas, executa o plano já calculado self.counter += 1 # @TODO T_AAFP - testar se atingiu o estado objetivo ou se chegou ao final do plano sem alcancar o objetivo if(self.prob.goalTest(self.positionSensor())): #colocar print final aqui print("*************** ultimo ciclo ***********************") print("estado atual:" + str(self.currentState)) print("ct = "+ str(self.counter) +" de "+str(len(self.plan))) print("custo ate o momento (com a acao escolhida):"+str(self.cost)) print("Objetivo conquistado!!!") print("****************************************************\n") return -1 elif(self.counter == len(self.plan)): #colocar um print aqui depois print("*************** ultimo ciclo ***********************") print("estado atual:" + str(self.currentState)) print("ct = "+ str(self.counter) +" de "+str(len(self.plan))) print("custo ate o momento (com a acao escolhida):"+str(self.cost)) print("Objetivo nao conquistado!!") print("****************************************************\n") return -1 possibleAction = self.prob.possibleActions(self.positionSensor()) currentAction = self.plan[self.counter] self.nextState = self.prob.suc(self.currentState,currentAction) # @TODO T_AAFP - fazer prints solicitados print("*************** inicio do ciclo ***********************") print("estado atual:" + str(self.currentState)) print("proximo estado:" + str(self.nextState)) print("açoes possiveis:{ ", end= '') for i in range(len(action)): if(possibleAction[i]==1): print("{} ".format(action[i]),end='') print("}") print("ct = "+ str(self.counter) +" de "+str(len(self.plan))+ ". Ação escolhida=" +action[currentAction]) print("custo ate o momento (com a acao escolhida):" + str(self.cost)) print("****************************************************\n") # @TODO T_AAFP - o agente deve executar a acao e atualizar seu estado atual self.executeGo(currentAction) self.cost += self.prob.getActionCost(currentAction) self.currentState = self.positionSensor() return 1 def executeGo(self, direction): """Atuador: solicita ao agente física para executar a ação. @param direction: Direção da ação do agente @return 1 caso movimentação tenha sido executada corretamente.""" self.model.go(direction) return 1 def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0],pos[1])
class Agent: def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model ## Pega o tipo de mesh, que está no model (influência na movimentação) self.mesh = self.model.mesh ## Cria a instância do problema para o agente self.prob = Problem() self.prob.createMaze(model.rows, model.columns, model.maze) # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col) # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # Define o estado objetivo self.prob.defGoalState(model.goalPos[0], model.goalPos[1]) """ DEFINE OS PLANOS DE EXECUÇÃO DO AGENTE """ ##Para usar o Planner online, exemplo abaixo: ##plann = Planner() ##print(plann.generate()) # Plano de busca - inicialmente vazio (equivale a solucao) self.plan = [] ##Custo da solução self.costAll = 0 ## Cria a instancia do algoritmo LRTA* self.planToGoal = Lrta(model.rows, model.columns, self.prob.goalState, initial, "goal", self.mesh) self.planToGoal.startManhattanHeuristic(self.prob.mazeBelief.walls) ## Coloca na biblioteca de planos todos os planos possíveis self.libPlan = [] ## Coloca dentro do plano as ações, nesse caso, ele deve executar o LRTA self.plan = [] ## Metodo que define a deliberacao do agente def deliberate(self): ## Verifica se há algum plano a ser executado if len(self.plan) == 0: return -1 print ("******************************Inicio do ciclo***************") print("Posição agente : {0},{1}".format(self.model.agentPos[0],self.model.agentPos[1])) ## Define a proxima acao a ser realizada como a primeira do plano currentAction = self.plan[0] ## Executa esse acao, atraves do metodo executeGo self.executeGo(currentAction) ## Redefine o estado atual do agente self.currentState = self.positionSensor() ## Atualiza a biblioteca de planos self.updateLibPlan() ## Soma o custo da acao com o total self.costAll += self.prob.getActionCost(currentAction) print ("Custo até o momento (com a ação escolhida):", self.costAll) print ("***************************************************************") return 1 ## Metodo que executa as acoes def executeGo(self, action): """Atuador: solicita ao agente físico para executar a acao. @param direction: Direcao da acao do agente @return 1 caso movimentacao tenha sido executada corretamente.""" ## Passa a acao para o modelo result = self.model.go(action) ## Se o resultado for True, significa que a acao foi completada com sucesso, e ja pode ser removida do plano if (result): del self.plan[0] self.actionGo([6,7], True) return 1 ## Metodo que pega a posicao real do agente no ambiente def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0],pos[1]) ## Metodo que atualiza a biblioteca de planos, de acordo com o estado atual do agente def updateLibPlan(self): for i in self.libPlan: i.updateCurrentState(self.currentState) def actionGo(self, posAction, action = True): self.model.do(posAction, action) def addPlan(self, plano): self.plan.append(plano)
class Agent: """""" counter = -1 # Contador de passos no plano, usado na deliberação def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model self.prob = Problem() self.prob.createMaze(6, 6) self.prob.mazeBelief.putVerticalWall(2, 4, 3) self.prob.mazeBelief.putHorizontalWall(0, 1, 2) self.prob.mazeBelief.putBox(4, 1) self.prob.mazeBelief.putBox(4, 2) self.prob.mazeBelief.putBox(3, 4) self.prob.mazeBelief.putBox(1, 3) # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col) # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # Plano de busca self.plan = None def printPlan(self): """Apresenta o plano de busca.""" print("--- PLANO ---") # @TODO: Implementação do aluno for plannedAction in self.plan: print("{} > ".format(action[plannedAction]), end='') print("FIM\n\n") def deliberate(self): # Primeira chamada, realiza busca para elaborar um plano # @TODO: Implementação do aluno if self.counter == -1: self.plan = self.cheapestFirstSearch( 1 ) # 0 = custo uniforme, 1 = A* com colunas, 2 = A* com dist Euclidiana if self.plan != None: self.printPlan() else: print("SOLUÇÃO NÃO ENCONTRADA") return -1 # Nas demais chamadas, executa o plano já calculado self.counter += 1 # Atingiu o estado objetivo if self.prob.goalFinalTest(): print("!!! ATINGIU O ESTADO OBJETIVO !!!") return -1 # Algo deu errado, chegou ao final do plano sem atingir o objetivo if self.counter >= len(self.plan): print( "### ERRO: plano chegou ao fim, mas objetivo não foi atingido." ) return -1 currentAction = self.plan[self.counter] print("--- Mente do Agente ---") print("{0:<20}{1}".format("Estado atual :", self.currentState)) print("{0:<20}{1} de {2}. Ação= {3}\n".format("Passo do plano :", self.counter + 1, len(self.plan), action[currentAction])) self.executeGo(currentAction) # Atualiza o estado atual baseando-se apenas nas suas crenças e na função sucessora # Não faz leitura do sensor de posição self.currentState = self.prob.suc(self.currentState, currentAction) return 1 def executeGo(self, direction): """Atuador: solicita ao agente física para executar a ação. @param direction: Direção da ação do agente @return 1 caso movimentação tenha sido executada corretamente.""" self.model.go(direction) return 1 def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0], pos[1]) def hn1(self, state, action): """Implementa uma heurísitca - número 1 - para a estratégia A*. No caso hn1 é a distância em linhas do estado passado com argumento até a linhas do estado objetivo. @param state: estado para o qual se quer calcular o valor de h(n).""" distance = 0 distRow = 0 distCol = 0 distColGoal = 0 for row in range(self.prob.mazeBelief.maxRows - 1): for col in range(self.prob.mazeBelief.maxColumns): if self.prob.mazeBelief.walls[row][col] == 2: pushesBox = 8 # IFs para compracao ao redor da caixa e ver algum cenario de deadlock # consequentemente vejo todas as posicoes ao redor da caixa e # se a caixa ossui algum obstaculo para movela # se possuir subo o numero de pushesBoes para um numero bem alto # se os movimentos forem livres seto o numero de pushes baseado numa matrix 3 por 3 # e na distancia de manhattan # Checo se tenho a matrix 3 por 3 em volta da box if (state.col == col - 1 or state.col == col or state.col == col + 1) and (state.row == row - 1 or state.row == row or state.row == row + 1): pushesBox = 4 # vejo se os limites estao dentro da matrix if row - 1 > 0 and col - 1 > 0 and row + 1 < self.prob.maxRows and col + 1 < self.prob.maxColumns: if state.col == col - 1 and state.row == row - 1: # posicao 0,0 na matriz emvolta da Box pushesBox = 2 if state.col == col and state.row == row - 1: # posicao 0,1 na matriz emvolta da Box pushesBox = 1 if state.col == col + 1 and state.row == row - 1: # posicao 0,2 na matriz emvolta da Box pushesBox = 2 if state.col == col - 1 and state.row == row: # posicao 1,0 na matriz emvolta da Box pushesBox = 1 if state.col == col and state.row == row: # posicao 1,1 na matriz emvolta da Box pushesBox = 0 if state.col == col + 1 and state.row == row: # posicao 1,2 na matriz emvolta da Box pushesBox = 1 if state.col == col - 1 and state.row == row + 1: # posicao 2,1 na matriz emvolta da Box pushesBox = 2 if state.col == col and state.row == row + 1: # posicao 2,2 na matriz emvolta da Box pushesBox = 1 if state.col == col + 1 and state.row == row + 1: # posicao 2,3 na matriz emvolta da Box pushesBox = 2 # se nao estiverem testo para deadlock # else: else: # pushesBox = 4 #pushesBox = # deixo menos pesado para i para cima do q para baixo pois nas colunas limites # a caixa so pode so deve se movimentar para baixo # else: pushesBox = 16 # colunas sendo o limite de 0 ou 5 posso testar o movimento para baixo distRow = abs( row - 5) # calculo individual da caixa para a linha obj if self.prob.mazeBelief.walls[5][col] == 2: # loop para ver qual objetivo esta mais perto e vazio for colGoal in range(self.prob.mazeBelief.maxColumns): distColGoal = 5 if self.prob.mazeBelief.walls[5][colGoal] != 2: distColGoal = abs(col - colGoal) if distColGoal < distCol: distCol = distCol + distColGoal else: distCol = 0 distance = distance + distRow + distCol + pushesBox return distance def hn2(self, state): """Implementa uma heurísitca - número 2 - para a estratégia A*. No caso hn1 é a distância distância euclidiana do estado passado com argumento até o estado objetivo. @param state: estado para o qual se quer calcular o valor de h(n).""" # @TODO: Implementação do aluno distCol = abs(state.col - self.prob.goalState.col) distRow = abs(state.row - self.prob.goalState.row) squared = distRow**2 + distCol**2 return squared**0.5 def cheapestFirstSearch(self, searchType): """Realiza busca com a estratégia de custo uniforme ou A* conforme escolha realizada na chamada. @param searchType: 0=custo uniforme, 1=A* com heurística hn1; 2=A* com hn2 @return plano encontrado""" # @TODO: Implementação do aluno # Atributos para análise de desempenho treeNodesCt = 0 # contador de nós gerados incluídos na árvore # nós inseridos na árvore, mas que não necessitariam porque o estado # já foi explorado ou por já estar na fronteira exploredDicardedNodesCt = 0 frontierDiscardedNodesCt = 0 # Algoritmo de busca solution = None solutionBox = [] root = TreeNode(parent=None) root.state = self.prob.initialState root.gn = 0 root.hn = 0 root.action = -1 treeNodesCt += 1 # cria FRONTEIRA com estado inicial frontier = [] frontier.append(root) # cria EXPLORADOS - inicialmente vazia explored = [] print("\n*****\n***** INICIALIZAÇÃO ÁRVORE DE BUSCA\n*****\n") print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) while len(frontier): # Fronteira não vazia print("\n*****\n***** Início iteração\n*****\n") printFrontier(frontier) selNode = frontier.pop(0) # retira nó da fronteira selState = selNode.state print("Selecionado para expansão: {}\n".format(selNode)) if self.prob.goalBoxTest(): solutionBox.append(selNode) if self.prob.goalFinalTest(): solution = selNode break explored.append(selNode) printExplored(explored) # Obtem ações possíveis para o estado selecionado para expansão actions = self.prob.possibleActionsWithoutCollaterals( selState) # actions é do tipo [-1, -1, -1, 1, 1, -1, -1, -1] for actionIndex, act in enumerate(actions): if (act < 0): # Ação não é possível continue # INSERE NÓ FILHO NA ÁRVORE DE BUSCA - SEMPRE INSERE, DEPOIS # VERIFICA SE O INCLUI NA FRONTEIRA OU NÃO # Instancia o filho ligando-o ao nó selecionado (nSel) child = selNode.addChild() # Obtem o estado sucessor pela execução da ação <act> sucState = self.prob.suc(selState, actionIndex) child.state = sucState # Custo g(n): custo acumulado da raiz até o nó filho gnChild = selNode.gn + self.prob.getActionCost(actionIndex) if searchType == UNIFORME_COST: child.setGnHn( gnChild, 0 ) # Deixa h(n) zerada porque é busca de custo uniforme elif searchType == A_START_1: child.setGnHn(gnChild, self.hn1(sucState, actionIndex)) elif searchType == A_START_2: child.setGnHn(gnChild, self.hn2(sucState)) child.action = actionIndex # INSERE NÓ FILHO NA FRONTEIRA (SE SATISFAZ CONDIÇÕES) # Testa se estado do nó filho foi explorado alreadyExplored = False # for node in explored: # if child.state == node.state: # alreadyExplored = True # break # Testa se estado do nó filho está na fronteira, caso esteja # guarda o nó existente em nFront nodeFront = None if not alreadyExplored: for node in frontier: if (child.state == node.state): nodeFront = node break # Se ainda não foi explorado if not alreadyExplored: # e não está na fronteira, adiciona à fronteira if nodeFront == None: frontier.append(child) frontier.sort(key=lambda x: x.getFn( )) # Ordena a fronteira pelo f(n), ascendente treeNodesCt += 1 else: # Se já está na fronteira temos que ver se é melhor if nodeFront.getFn() > child.getFn( ): # Nó da fronteira tem custo maior que o filho frontier.remove( nodeFront ) # Remove nó da fronteira (pior e deve ser substituído) nodeFront.remove() # Retira-se da árvore frontier.append( child) # Adiciona filho que é melhor frontier.sort(key=lambda x: x.getFn( )) # Ordena a fronteira pelo f(n), ascendente # treeNodesCt não é incrementado por inclui o melhor e retira o pior else: # Conta como descartado porque o filho é pior que o nó da fronteira e foi descartado frontierDiscardedNodesCt += 1 else: exploredDicardedNodesCt += 1 print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) if (solution != None): print("!!! Solução encontrada !!!") print("!!! Custo: {}".format(solution.gn)) print("!!! Profundidade: {}\n".format(solution.depth)) print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) return buildPlan(solution) else: print("### Solução NÃO encontrada ###") return None
class Agent: """""" counter = -1 # Contador de passos no plano, usado na deliberação def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model self.prob = Problem() self.prob.createMaze(6, 6) self.prob.mazeBelief.putVerticalWall(2, 4, 3) self.prob.mazeBelief.putHorizontalWall(0, 1, 2) # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col, initial.boxes) # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # Define o estado objetivo self.prob.defGoalState(0, 0, [(5, 1), (5, 4), (5, 5)]) self.model.addGoalPos(5, 5) self.model.addGoalPos(5, 4) #self.model.addGoalPos(5,3) #self.model.addGoalPos(5,2) self.model.addGoalPos(5, 1) #self.model.addGoalPos(5,0) # Plano de busca self.plan = None def deliberate(self): # Primeira chamada, realiza busca para elaborar um plano if self.counter == -1: self.plan = self.cheapestFirstSearch( H_OPT ) # 0 = custo uniforme, 1 = A* com colunas, 2 = A* com dist Euclidiana if self.plan != None: self.printPlan() else: print("SOLUÇÃO NÃO ENCONTRADA") return -1 # Nas demais chamadas, executa o plano já calculado self.counter += 1 # Atingiu o estado objetivo if self.prob.goalTest(self.currentState): print("!!! ATINGIU O ESTADO OBJETIVO !!!") return -1 # Algo deu errado, chegou ao final do plano sem atingir o objetivo if self.counter >= len(self.plan): print( "### ERRO: plano chegou ao fim, mas objetivo não foi atingido." ) return -1 currentAction = self.plan[self.counter] print("--- Mente do Agente ---") print("{0:<20}{1}".format("Estado atual :", self.currentState)) print("{0:<20}{1} de {2}. Ação= {3}\n".format("Passo do plano :", self.counter + 1, len(self.plan), action[currentAction])) self.executeGo(currentAction) # Atualiza o estado atual baseando-se apenas nas suas crenças e na função sucessora # Não faz leitura do sensor de posição self.currentState = self.prob.suc(self.currentState, currentAction) return 1 def executeGo(self, direction): """Atuador: solicita ao agente física para executar a ação. @param direction: Direção da ação do agente @return 1 caso movimentação tenha sido executada corretamente.""" self.model.go(direction) return 1 def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0], pos[1], self.model.boxPos, 0) def hn(self, state): goalBoxes = self.prob.goalState.boxes h = 0 distsToAgent = [] for i in range(len(goalBoxes)): box = goalBoxes[i] sBox = state.boxes[i] distsToAgent.append( (abs(sBox[0] - state.row), abs(sBox[1] - state.col))) h += abs(box[0] - sBox[0]) + abs(box[1] - sBox[1]) minDist = min(distsToAgent) h += minDist[0] + minDist[ 1] # menor distancia entre o agente e as caixas return h def hnmeans(self, state): goalBoxes = self.prob.goalState.boxes h = 0 for gbox in goalBoxes: m = 0 for sbox in state.boxes: m += abs(gbox[0] - sbox[0]) + abs(gbox[1] - sbox[1]) h += (m / len(state.boxes)) + (abs(sbox[0] - state.row) + abs(sbox[1] - state.col)) return h def hnwall(self, state): goalBoxes = self.prob.goalState.boxes h = 0 distsToAgent = [] for i in range(len(goalBoxes)): box = goalBoxes[i] sBox = state.boxes[i] distsToAgent.append( abs(sBox[0] - state.row) + abs(sBox[1] - state.col) + self.prob.checkWall(sBox, (state.row, state.col))) h += abs(box[0] - sBox[0]) + abs(box[1] - sBox[1]) + self.prob.checkWall( sBox, box) minDist = min(distsToAgent) h += minDist # menor distancia entre o agente e as caixas return h def hnOptm(self, state): distsg = [(state.row, state.col)] distsg += [box for box in self.prob.goalState.boxes] dists = [box for box in state.boxes] distsg.sort() dists.sort() h = 0 for i in range(len(dists)): h += abs(dists[i][0] - distsg[i][0]) + abs(dists[i][1] - distsg[i][1]) h += abs(dists[i][0] - distsg[i + 1][0]) + abs(dists[i][1] - distsg[i + 1][1]) return h def hnOptmWall(self, state): distsg = [(state.row, state.col)] distsg += [box for box in self.prob.goalState.boxes] dists = [box for box in state.boxes] distsg.sort() dists.sort() h = 0 for i in range(len(dists)): h += abs(dists[i][0] - distsg[i][0]) + abs(dists[i][1] - distsg[i][1]) h += abs(dists[i][0] - distsg[i + 1][0]) + abs(dists[i][1] - distsg[i + 1][1]) h += self.prob.checkWall(dists[i], distsg[i]) + self.prob.checkWall( dists[i], distsg[i + 1]) return h def hnOptmEucl(self, state): distsg = [(state.row, state.col)] distsg += [box for box in self.prob.goalState.boxes] dists = [box for box in state.boxes] distsg.sort() dists.sort() h = 0 for i in range(len(dists)): h += abs(dists[i][0] - distsg[i][0])**2 h += abs(dists[i][1] - distsg[i][1])**2 h += abs(dists[i][0] - distsg[i + 1][0])**2 h += abs(dists[i][1] - distsg[i + 1][1])**2 return h**0.5 def cheapestFirstSearch(self, searchType): """Realiza busca com a estratégia de custo uniforme ou A* conforme escolha realizada na chamada. @param searchType: 0=custo uniforme, 1=A* com heurística hn1; 2=A* com hn2 @return plano encontrado""" # Atributos para análise de desempenho treeNodesCt = 0 # contador de nós gerados incluídos na árvore # nós inseridos na árvore, mas que não necessitariam porque o estado # já foi explorado ou por já estar na fronteira exploredDicardedNodesCt = 0 frontierDiscardedNodesCt = 0 # Algoritmo de busca solution = None root = TreeNode(parent=None) root.state = self.prob.initialState root.gn = 0 root.hn = 0 root.action = -1 treeNodesCt += 1 # cria FRONTEIRA com estado inicial frontier = [] frontier.append(root) # cria EXPLORADOS - inicialmente vazia explored = {} print("\n*****\n***** INICIALIZAÇÃO ÁRVORE DE BUSCA\n*****\n") print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) while len(frontier): # Fronteira não vazia print("\n*****\n***** Início iteração\n*****\n") #printFrontier(frontier) selNode = frontier.pop(0) # retira nó da fronteira selState = selNode.state print("Selecionado para expansão: {}\n".format(selNode)) # Teste de objetivo if selState == self.prob.goalState: solution = selNode break explored[str(selState.row) + str(selState.col) + str(selState.boxes)] = selState #printExplored(explored) # Obtem ações possíveis para o estado selecionado para expansão actions = self.prob.possibleActions( selState) # actions é do tipo [-1, -1, -1, 1 ] if selNode.gn >= LIMITE_BUSCA and VERIFICA_LIMITE: continue for actionIndex, act in enumerate(actions): if (act < 0): # Ação não é possível continue # INSERE NÓ FILHO NA ÁRVORE DE BUSCA - SEMPRE INSERE, DEPOIS # VERIFICA SE O INCLUI NA FRONTEIRA OU NÃO # Obtem o estado sucessor pela execução da ação <act> sucState = self.prob.suc(selState, actionIndex) # verifica se a acao sucessora bloqueia o tabuleiro if (VERIFICA_ACAO_BLOQUEIO and self.prob.isBlockAction(sucState)): continue # Instancia o filho ligando-o ao nó selecionado (nSel) child = selNode.addChild() child.state = sucState # Custo g(n): custo acumulado da raiz até o nó filho gnChild = selNode.gn + self.prob.getActionCost(actionIndex) if searchType == UNIFORME_COST: child.setGnHn( gnChild, 0 ) # Deixa h(n) zerada porque é busca de custo uniforme elif searchType == HEURISTICA_DISTS: child.setGnHn(gnChild, self.hn(sucState)) elif searchType == HEURISTICA_DISTS_PEN_OBSTACULOS: child.setGnHn(gnChild, self.hnwall(sucState)) elif searchType == H_OPT: child.setGnHn(gnChild, self.hnOptm(sucState)) elif searchType == H_EUCL: child.setGnHn(gnChild, self.hnOptmEucl(sucState)) elif searchType == H_OPT_PEN: child.setGnHn(gnChild, self.hnOptmWall(sucState)) child.action = actionIndex # INSERE NÓ FILHO NA FRONTEIRA (SE SATISFAZ CONDIÇÕES) alreadyExplored = False # Testa se estado do nó filho foi explorado expHash = str(child.state.row) + str(child.state.col) + str( child.state.boxes) if expHash in explored: exp = explored[expHash] if (child.state.cost >= exp.cost): alreadyExplored = True # Testa se estado do nó filho está na fronteira, caso esteja # guarda o nó existente em nFront nodeFront = None if not alreadyExplored: for node in frontier: if (child.state == node.state and child.state.row == node.state.row and child.state.col == node.state.col): nodeFront = node break # Se ainda não foi explorado if not alreadyExplored: # e não está na fronteira, adiciona à fronteira if nodeFront == None: # adiciona na fronteira se a acao nao bloqueia a solucao frontier.append(child) frontier.sort( key=lambda x: (x.getFn(), x.hn) ) # Ordena a fronteira pelo f(n), usando o valor de hn como desempate treeNodesCt += 1 else: # Se já está na fronteira temos que ver se é melhor if nodeFront.getFn() > child.getFn( ): # Nó da fronteira tem custo maior que o filho frontier.remove( nodeFront ) # Remove nó da fronteira (pior e deve ser substituído) nodeFront.remove() # Retira-se da árvore frontier.append( child) # Adiciona filho que é melhor #frontier.sort(key=lambda x: x.getFn() ) # Ordena a fronteira pelo f(n), ascendente frontier.sort( key=lambda x: (x.getFn(), x.hn) ) # Ordena a fronteira pelo f(n), usando o valor de hn como desempate # treeNodesCt não é incrementado por inclui o melhor e retira o pior else: # Conta como descartado porque o filho é pior que o nó da fronteira e foi descartado frontierDiscardedNodesCt += 1 else: exploredDicardedNodesCt += 1 print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) if (solution != None): print("!!! Solução encontrada !!!") print("!!! Custo: {}".format(solution.gn)) print("!!! Profundidade: {}\n".format(solution.depth)) print("\n{0:<30}{1}".format("Nós na árvore: ", treeNodesCt)) print("{0:<30}{1}".format("Descartados já na fronteira: ", frontierDiscardedNodesCt)) print("{0:<30}{1}".format("Descartados já explorados: ", exploredDicardedNodesCt)) print("{0:<30}{1}".format( "Total de nós gerados: ", treeNodesCt + frontierDiscardedNodesCt + exploredDicardedNodesCt)) return buildPlan(solution) else: print("### Solução NÃO encontrada ###") return None def printPlan(self): """Apresenta o plano de busca.""" print("--- PLANO ---") # @TODO: Implementação do aluno for plannedAction in self.plan: print("{} > ".format(action[plannedAction]), end='') print("FIM\n\n")
class Agent: """""" counter = -1 # Contador de passos no plano, usado na deliberação def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model self.prob = Problem() # @TODO T_AAFP - criar crencas sobre as pareded do labirinto self.prob.createMaze(9, 9) self.prob.mazeBelief.putVerticalWall(0,1,0) # ... # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col) # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # @TODO T_AAFP - defina estado objetivo # Define o estado objetivo # self.prob.defGoalState(?, ?) # o metodo abaixo serve apenas para a view desenhar a pos objetivo # self.model.setGoalPos(2,8) # Plano de busca - inicialmente vazio (equivale a solucao) self.plan = None def printPlan(self): """Apresenta o plano de busca.""" print("--- PLANO ---") # @TODO: Implementação do aluno for plannedAction in self.plan: print("{} > ".format(action[plannedAction]),end='') print("FIM\n\n") def deliberate(self): # Primeira chamada, realiza busca para elaborar um plano # @TODO T_AAFP: Implementação do aluno if self.counter == -1: # @TODO T_AAFP: dar um plano fixo ao agente (preh-programado) - ver cardinal.py # @TODO T_AAFP: plano = solucao: contem acoes que levam o agente ateh o estado objetivo # self.plan = [] if self.plan != None: self.printPlan() else: print("SOLUÇÃO NÃO ENCONTRADA") return -1 # Nas demais chamadas, executa o plano já calculado self.counter += 1 # @TODO T_AAFP - testar se atingiu o estado objetivo ou se chegou ao final do plano sem alcancar o objetivo currentAction = self.plan[self.counter] # @TODO T_AAFP - fazer prints solicitados # @TODO T_AAFP - o agente deve executar a acao e atualizar seu estado atual return 1 def executeGo(self, direction): """Atuador: solicita ao agente física para executar a ação. @param direction: Direção da ação do agente @return 1 caso movimentação tenha sido executada corretamente.""" self.model.go(direction) return 1 def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0],pos[1])
class Agent: """""" counter = -1 # Contador de passos no plano, usado na deliberação def __init__(self, model): """Construtor do agente. @param model: Referência do ambiente onde o agente atuará.""" self.model = model self.prob = Problem() self.prob.createMaze(9, 9) self.prob.mazeBelief.putVerticalWall(0, 1, 0) self.prob.mazeBelief.putVerticalWall(0, 0, 1) self.prob.mazeBelief.putHorizontalWall(4, 6, 0) self.prob.mazeBelief.putVerticalWall(0, 1, 7) self.prob.mazeBelief.putHorizontalWall(3, 5, 2) self.prob.mazeBelief.putHorizontalWall(3, 5, 3) self.prob.mazeBelief.putHorizontalWall(7, 7, 3) self.prob.mazeBelief.putHorizontalWall(1, 2, 5) self.prob.mazeBelief.putVerticalWall(6, 7, 1) self.prob.mazeBelief.putVerticalWall(6, 7, 4) self.prob.mazeBelief.putVerticalWall(5, 6, 5) self.prob.mazeBelief.putVerticalWall(5, 7, 7) self.prob.mazeBelief.putHorizontalWall(1, 2, 8) # Posiciona fisicamente o agente no estado inicial initial = self.positionSensor() self.prob.defInitialState(initial.row, initial.col) # Define o estado atual do agente = estado inicial self.currentState = self.prob.initialState # Define o estado objetivo self.prob.defGoalState(2, 8) # o metodo abaixo serve apenas para a view desenhar a pos objetivo self.model.setGoalPos(2, 8) # Plano de busca - inicialmente vazio (equivale a solucao) self.plan = None def printPlan(self): """Apresenta o plano de busca.""" print("--- PLANO ---") # @TODO: Implementação do aluno for plannedAction in self.plan: print("{} > ".format(action[plannedAction]), end='') print("FIM\n\n") def deliberate(self): # Primeira chamada, realiza busca para elaborar um plano if self.counter == -1: self.plan = [N, N, N, NE, L, L, L, L, L, L, NE, N] if self.plan != None: self.printPlan() else: print("SOLUÇÃO NÃO ENCONTRADA") return -1 # Nas demais chamadas, executa o plano já calculado self.counter += 1 if self.prob.goalTest(self.positionSensor()): return -1 currentAction = self.plan[self.counter] self.executeGo(self.plan[self.counter]) self.currentState = self.positionSensor() cost = 0.0 for i in range(-1, self.counter): cost += self.prob.getActionCost(self.plan[i + 1]) print("*****************************************************") print("estado atual : ({0},{1})".format(self.model.agentPos[0], self.model.agentPos[1])) print("acoes possiveis:", end='') actions = self.prob.possibleActions(self.positionSensor()) for i in range(0, len(actions)): if actions[i] != -1: print(" {0}".format(action[i]), end='') print("\nct: {0} de {1}".format(self.counter + 1, len(self.plan))) print("custo ate o momento (com a acao escolhida): {0}".format(cost)) print("*****************************************************\n") return 1 def executeGo(self, direction): """Atuador: solicita ao agente física para executar a ação. @param direction: Direção da ação do agente @return 1 caso movimentação tenha sido executada corretamente.""" self.model.go(direction) return 1 def positionSensor(self): """Simula um sensor que realiza a leitura do posição atual no ambiente e traduz para uma instância da classe Estado. @return estado que representa a posição atual do agente no labirinto.""" pos = self.model.agentPos return State(pos[0], pos[1])