ift7025-tp1/search/search.py
2019-04-11 00:08:48 -04:00

263 lines
11 KiB
Python

# -*- coding: utf-8 -*-
# search.py
# ---------
# Licensing Information: You are free to use or extend these projects for
# educational purposes provided that (1) you do not distribute or publish
# solutions, (2) you retain this notice, and (3) you provide clear
# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
#
# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
# The core projects and autograders were primarily created by John DeNero
# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
# Student side autograding was added by Brad Miller, Nick Hay, and
# Pieter Abbeel (pabbeel@cs.berkeley.edu).
#
# IFT-7025 Hier 2019
# François Pelletier
# 908144032
"""
In search.py, you will implement generic search algorithms which are called by
Pacman agents (in searchAgents.py).
"""
import util
class SearchProblem:
"""
This class outlines the structure of a search problem, but doesn't implement
any of the methods (in object-oriented terminology: an abstract class).
You do not need to change anything in this class, ever.
"""
def getStartState(self):
"""
Returns the start state for the search problem.
"""
util.raiseNotDefined()
def isGoalState(self, state):
"""
state: Search state
Returns True if and only if the state is a valid goal state.
"""
util.raiseNotDefined()
def getSuccessors(self, state):
"""
state: Search state
For a given state, this should return a list of triples, (successor,
action, stepCost), where 'successor' is a successor to the current
state, 'action' is the action required to get there, and 'stepCost' is
the incremental cost of expanding to that successor.
"""
util.raiseNotDefined()
def getCostOfActions(self, actions):
"""
actions: A list of actions to take
This method returns the total cost of a particular sequence of actions.
The sequence must be composed of legal moves.
"""
util.raiseNotDefined()
def tinyMazeSearch(problem):
"""
Returns a sequence of moves that solves tinyMaze. For any other maze, the
sequence of moves will be incorrect, so only use this for tinyMaze.
"""
from game import Directions
s = Directions.SOUTH
w = Directions.WEST
return [s, s, w, s, w, w, s, w]
def depthFirstSearch(problem):
"""
Search the deepest nodes in the search tree first.
Your search algorithm needs to return a list of actions that reaches the
goal. Make sure to implement a graph search algorithm.
To get started, you might want to try some of these simple commands to
understand the search problem that is being passed in:
print "Start:", problem.getStartState()
print "Is the start a goal?", problem.isGoalState(problem.getStartState())
print "Start's successors:", problem.getSuccessors(problem.getStartState())
"""
"*** YOUR CODE HERE ***"
maPile = util.Stack()
maListeFermee = []
# Verifier si le depart est un but
if problem.isGoalState(problem.getStartState()):
return []
# Mettre le premier noeud et un chemin vide dans la pile
maPile.push((problem.getStartState(),list()))
# Rechercher tant que la pile n'est pas vide
while (not maPile.isEmpty()):
# Extraire le noeud courant
noeudCourant, listeDirections = maPile.pop()
# print "Noeud courant: ", noeudCourant
# La marquer comme visite
maListeFermee.append(noeudCourant)
# Verifier si c'est un but
if(problem.isGoalState(noeudCourant)):
# print "Nous avons atteint le but !"
return listeDirections
# Effectuer la recherche de successeurs
for s in problem.getSuccessors(noeudCourant):
# Decomposer le tuple pour faciliter la lecture
succNoeudCourant, succDirection, succCost = s
# Verifier si le noeud n'est pas deja visite et n'est pas dans la pile
if (succNoeudCourant not in maListeFermee):
# Dans ce cas, ajouter le noeud et le chemin pour s'y rendre a la pile
# print "Ajout du noeud a la pile: ", succNoeudCourant
maPile.push((succNoeudCourant,listeDirections+[succDirection]))
# print "pas de solution"
util.raiseNotDefined()
def breadthFirstSearch(problem):
"""Search the shallowest nodes in the search tree first."""
"*** YOUR CODE HERE ***"
maFile = util.Queue()
maListeFermee = []
# Verifier si le depart est un but
if problem.isGoalState(problem.getStartState()):
return []
# Mettre le premier noeud et un chemin vide dans la file
maFile.push((problem.getStartState(),list()))
while (not maFile.isEmpty()):
# Extraire le noeud courant
noeudCourant, listeDirections = maFile.pop()
#print "Noeud courant: ", noeudCourant
# La marquer comme visite
maListeFermee.append(noeudCourant)
# Verifier si c'est un but
if(problem.isGoalState(noeudCourant)):
#print "Nous avons atteint le but !"
return listeDirections
# Effectuer la recherche de successeurs
for s in problem.getSuccessors(noeudCourant):
# Decomposer le tuple pour faciliter la lecture
succNoeudCourant, succDirection, succCost = s
# Verifier si le noeud n'est pas deja visite et n'est pas dans la file
if (succNoeudCourant not in maListeFermee+[i[0] for i in maFile.list]):
# Dans ce cas, ajouter le noeud et le chemin pour s'y rendre a la file
#print "Ajout du noeud a la file: ", succNoeudCourant
maFile.push((succNoeudCourant,listeDirections+[succDirection]))
# print "pas de solution"
util.raiseNotDefined()
def uniformCostSearch(problem):
"""Search the node of least total cost first."""
"*** YOUR CODE HERE ***"
maFileEtat = util.PriorityQueue()
# Je fais une 2e file parce que sinon je ne peux pas comparer le cout
# si je le met dans le meme tuple que le chemin
maFileChemin = util.PriorityQueue()
maListeFermee = []
# Verifier si le depart est un but
if problem.isGoalState(problem.getStartState()):
return []
# Mettre le premier noeud dans la file
maFileEtat.push(problem.getStartState(),0)
# Extraire le noeud courant
listeDirections = []
while (not maFileEtat.isEmpty()):
noeudCourant = maFileEtat.pop()
#print "Noeud courant: ", noeudCourant
# La marquer comme visite
if noeudCourant not in maListeFermee:
maListeFermee.append(noeudCourant)
# Verifier si c'est un but
if(problem.isGoalState(noeudCourant)):
#print "Nous avons atteint le but !"
return listeDirections
# Effectuer la recherche de successeurs
for s in problem.getSuccessors(noeudCourant):
# Decomposer le tuple pour faciliter la lecture
succNoeudCourant, succDirection, succCost = s
# Verifier si le noeud n'est pas deja visite
succCostChemin = None
if (succNoeudCourant not in maListeFermee+[i[0] for i in maFileEtat.heap]):
# obtenir le cout total du chemin
succCostChemin = problem.getCostOfActions(listeDirections+[succDirection])
# Si le noeud est encore dans la file, mettre a jour la priorite si elle devient inferieure
#print "Ajout du noeud a la file: ", succNoeudCourant
maFileEtat.push(succNoeudCourant,succCostChemin)
# Ajouter le nouveau chemin dans la file avec son cout
maFileChemin.push(listeDirections+[succDirection],succCostChemin)
# si noeud existant, mettre a jour le cout si meilleur
elif succNoeudCourant in [i[0] for i in maFileEtat.heap]:
maFileEtat.update(succNoeudCourant,succCostChemin)
listeDirections = maFileChemin.pop()
# print "pas de solution"
util.raiseNotDefined()
def nullHeuristic(state, problem=None):
"""
A heuristic function estimates the cost from the current state to the nearest
goal in the provided SearchProblem. This heuristic is trivial.
"""
return 0
def aStarSearch(problem, heuristic=nullHeuristic):
"""Search the node that has the lowest combined cost and heuristic first."""
"*** YOUR CODE HERE ***"
maFileEtat = util.PriorityQueue()
# Je fais une 2e file parce que sinon je ne peux pas comparer le cout
# si je le met dans le meme tuple que le chemin
maFileChemin = util.PriorityQueue()
maListeFermee = []
# Verifier si le depart est un but
if problem.isGoalState(problem.getStartState()):
return []
# Mettre le premier noeud dans la file
maFileEtat.push(problem.getStartState(),0)
# Extraire le noeud courant
listeDirections = []
while (not maFileEtat.isEmpty()):
noeudCourant = maFileEtat.pop()
# print "Noeud courant: ", noeudCourant
# La marquer comme visite
if noeudCourant not in maListeFermee:
maListeFermee.append(noeudCourant)
# Verifier si c'est un but
if(problem.isGoalState(noeudCourant)):
#print "Nous avons atteint le but !"
return listeDirections
# Effectuer la recherche de successeurs
for s in problem.getSuccessors(noeudCourant):
# Decomposer le tuple pour faciliter la lecture
succ_noeud_courant, succDirection, succCost = s
# Verifier si le noeud n'est pas deja visite
succ_cost_chemin = None
if succ_noeud_courant not in maListeFermee+[i[0] for i in maFileEtat.heap]:
# obtenir le cout total du chemin
succ_cost_chemin = problem.getCostOfActions(listeDirections+[succDirection])+heuristic(succ_noeud_courant,problem)
# Si le noeud est encore dans la file, mettre a jour la priorite si elle devient inferieure
# print "Ajout du noeud a la file: ", succ_noeud_courant
maFileEtat.push(succ_noeud_courant,succ_cost_chemin)
# Ajouter le nouveau chemin dans la file avec son cout
maFileChemin.push(listeDirections+[succDirection],succ_cost_chemin)
# si noeud existant, mettre a jour le cout si meilleur
elif succ_noeud_courant in [i[0] for i in maFileEtat.heap]:
maFileEtat.update(succ_noeud_courant,succ_cost_chemin)
listeDirections = maFileChemin.pop()
# print "pas de solution"
util.raiseNotDefined()
# Abbreviations
bfs = breadthFirstSearch
dfs = depthFirstSearch
astar = aStarSearch
ucs = uniformCostSearch