Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@
# ______________________________________________________________________________


class Thing(object):

class Thing:
"""This represents any physical object that can appear in an Environment.
You subclass Thing to get the things you want. Each thing can have a
.__name__ slot (used for output only)."""
Expand All @@ -69,7 +68,6 @@ def display(self, canvas, x, y, width, height):


class Agent(Thing):

"""An Agent is a subclass of Thing with one required slot,
.program, which should hold a function that takes one argument, the
percept, and returns an action. (What counts as a percept or action
Expand Down Expand Up @@ -222,8 +220,7 @@ def program(percept):
# ______________________________________________________________________________


class Environment(object):

class Environment:
"""Abstract class representing an Environment. 'Real' Environment classes
inherit from this. Your Environment will typically need to implement:
percept: Define the percept that an agent sees.
Expand Down Expand Up @@ -319,7 +316,8 @@ def delete_thing(self, thing):
if thing in self.agents:
self.agents.remove(thing)

class Direction():

class Direction:
"""A direction class for agents that want to move in a 2D plane
Usage:
d = Direction("down")
Expand Down Expand Up @@ -371,7 +369,6 @@ def move_forward(self, from_location):


class XYEnvironment(Environment):

"""This class is for environments on a 2D plane, with locations
labelled by (x, y) points, either discrete or continuous.

Expand Down Expand Up @@ -507,7 +504,6 @@ def turn_heading(self, heading, inc):


class Obstacle(Thing):

"""Something that can cause a bump, preventing an agent from
moving into the same square it's in."""
pass
Expand Down Expand Up @@ -724,7 +720,8 @@ def get_world(self, show_walls=True):
return result

def percepts_from(self, agent, location, tclass=Thing):
"""Returns percepts from a given location, and replaces some items with percepts from chapter 7."""
"""Returns percepts from a given location,
and replaces some items with percepts from chapter 7."""
thing_percepts = {
Gold: Glitter(),
Wall: Bump(),
Expand Down
61 changes: 28 additions & 33 deletions csp.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@


class CSP(search.Problem):

"""This class describes finite-domain Constraint Satisfaction Problems.
A CSP is specified by the following inputs:
variables A list of variables; each is atomic (e.g. int or string).
Expand Down Expand Up @@ -49,7 +48,7 @@ class CSP(search.Problem):
"""

def __init__(self, variables, domains, neighbors, constraints):
"Construct a CSP problem. If variables is empty, it becomes domains.keys()."
"""Construct a CSP problem. If variables is empty, it becomes domains.keys()."""
variables = variables or list(domains.keys())

self.variables = variables
Expand All @@ -61,7 +60,7 @@ def __init__(self, variables, domains, neighbors, constraints):
self.nassigns = 0

def assign(self, var, val, assignment):
"Add {var: val} to assignment; Discard the old value if any."
"""Add {var: val} to assignment; Discard the old value if any."""
assignment[var] = val
self.nassigns += 1

Expand All @@ -73,15 +72,15 @@ def unassign(self, var, assignment):
del assignment[var]

def nconflicts(self, var, val, assignment):
"Return the number of conflicts var=val has with other variables."
"""Return the number of conflicts var=val has with other variables."""
# Subclasses may implement this more efficiently
def conflict(var2):
return (var2 in assignment and
not self.constraints(var, val, var2, assignment[var2]))
return count(conflict(v) for v in self.neighbors[var])

def display(self, assignment):
"Show a human-readable representation of the CSP."
"""Show a human-readable representation of the CSP."""
# Subclasses can print in a prettier way, or display with a GUI
print('CSP:', self, 'with assignment:', assignment)

Expand All @@ -99,12 +98,12 @@ def actions(self, state):
if self.nconflicts(var, val, assignment) == 0]

def result(self, state, action):
"Perform an action and return the new state."
"""Perform an action and return the new state."""
(var, val) = action
return state + ((var, val),)

def goal_test(self, state):
"The goal is to assign all variables, with all constraints satisfied."
"""The goal is to assign all variables, with all constraints satisfied."""
assignment = dict(state)
return (len(assignment) == len(self.variables)
and all(self.nconflicts(variables, assignment[variables], assignment) == 0
Expand All @@ -119,37 +118,37 @@ def support_pruning(self):
self.curr_domains = {v: list(self.domains[v]) for v in self.variables}

def suppose(self, var, value):
"Start accumulating inferences from assuming var=value."
"""Start accumulating inferences from assuming var=value."""
self.support_pruning()
removals = [(var, a) for a in self.curr_domains[var] if a != value]
self.curr_domains[var] = [value]
return removals

def prune(self, var, value, removals):
"Rule out var=value."
"""Rule out var=value."""
self.curr_domains[var].remove(value)
if removals is not None:
removals.append((var, value))

def choices(self, var):
"Return all values for var that aren't currently ruled out."
"""Return all values for var that aren't currently ruled out."""
return (self.curr_domains or self.domains)[var]

def infer_assignment(self):
"Return the partial assignment implied by the current inferences."
"""Return the partial assignment implied by the current inferences."""
self.support_pruning()
return {v: self.curr_domains[v][0]
for v in self.variables if 1 == len(self.curr_domains[v])}

def restore(self, removals):
"Undo a supposition and all inferences from it."
"""Undo a supposition and all inferences from it."""
for B, b in removals:
self.curr_domains[B].append(b)

# This is for min_conflicts search

def conflicted_vars(self, current):
"Return a list of variables in current assignment that are in conflict"
"""Return a list of variables in current assignment that are in conflict"""
return [var for var in self.variables
if self.nconflicts(var, current[var], current) > 0]

Expand All @@ -174,7 +173,7 @@ def AC3(csp, queue=None, removals=None):


def revise(csp, Xi, Xj, removals):
"Return true if we remove a value."
"""Return true if we remove a value."""
revised = False
for x in csp.curr_domains[Xi][:]:
# If Xi=x conflicts with Xj=y for every possible y, eliminate Xi=x
Expand All @@ -190,12 +189,12 @@ def revise(csp, Xi, Xj, removals):


def first_unassigned_variable(assignment, csp):
"The default variable order."
"""The default variable order."""
return first([var for var in csp.variables if var not in assignment])


def mrv(assignment, csp):
"Minimum-remaining-values heuristic."
"""Minimum-remaining-values heuristic."""
return argmin_random_tie(
[v for v in csp.variables if v not in assignment],
key=lambda var: num_legal_values(csp, var, assignment))
Expand All @@ -212,12 +211,12 @@ def num_legal_values(csp, var, assignment):


def unordered_domain_values(var, assignment, csp):
"The default value order."
"""The default value order."""
return csp.choices(var)


def lcv(var, assignment, csp):
"Least-constraining-values heuristic."
"""Least-constraining-values heuristic."""
return sorted(csp.choices(var),
key=lambda val: csp.nconflicts(var, val, assignment))

Expand All @@ -229,7 +228,7 @@ def no_inference(csp, var, value, assignment, removals):


def forward_checking(csp, var, value, assignment, removals):
"Prune neighbor values inconsistent with var=value."
"""Prune neighbor values inconsistent with var=value."""
for B in csp.neighbors[var]:
if B not in assignment:
for b in csp.curr_domains[B][:]:
Expand All @@ -241,7 +240,7 @@ def forward_checking(csp, var, value, assignment, removals):


def mac(csp, var, value, assignment, removals):
"Maintain arc consistency."
"""Maintain arc consistency."""
return AC3(csp, [(X, var) for X in csp.neighbors[var]], removals)

# The search, proper
Expand All @@ -251,8 +250,7 @@ def backtracking_search(csp,
select_unassigned_variable=first_unassigned_variable,
order_domain_values=unordered_domain_values,
inference=no_inference):
"""[Figure 6.5]
"""
"""[Figure 6.5]"""

def backtrack(assignment):
if len(assignment) == len(csp.variables):
Expand Down Expand Up @@ -306,7 +304,7 @@ def min_conflicts_value(csp, var, current):


def tree_csp_solver(csp):
"[Figure 6.11]"
"""[Figure 6.11]"""
assignment = {}
root = csp.variables[0]
X, parent = topological_sort(csp.variables, root)
Expand All @@ -332,7 +330,6 @@ def make_arc_consistent(Xj, Xk, csp):


class UniversalDict:

"""A universal dict maps any key to the same value. We use it here
as the domains dict for CSPs in which all variables have the same domain.
>>> d = UniversalDict(42)
Expand All @@ -348,7 +345,7 @@ def __repr__(self): return '{{Any: {0!r}}}'.format(self.value)


def different_values_constraint(A, a, B, b):
"A constraint saying two neighboring variables must differ in value."
"""A constraint saying two neighboring variables must differ in value."""
return a != b


Expand Down Expand Up @@ -413,7 +410,6 @@ def queen_constraint(A, a, B, b):


class NQueensCSP(CSP):

"""Make a CSP for the nQueens problem for search with min_conflicts.
Suitable for large n, it uses only data structures of size O(n).
Think of placing queens one per column, from left to right.
Expand Down Expand Up @@ -453,7 +449,7 @@ def nconflicts(self, var, val, assignment):
return c

def assign(self, var, val, assignment):
"Assign var, and keep track of conflicts."
"""Assign var, and keep track of conflicts."""
oldval = assignment.get(var, None)
if val != oldval:
if oldval is not None: # Remove old val if there was one
Expand All @@ -462,20 +458,20 @@ def assign(self, var, val, assignment):
CSP.assign(self, var, val, assignment)

def unassign(self, var, assignment):
"Remove var from assignment (if it is there) and track conflicts."
"""Remove var from assignment (if it is there) and track conflicts."""
if var in assignment:
self.record_conflict(assignment, var, assignment[var], -1)
CSP.unassign(self, var, assignment)

def record_conflict(self, assignment, var, val, delta):
"Record conflicts caused by addition or deletion of a Queen."
"""Record conflicts caused by addition or deletion of a Queen."""
n = len(self.variables)
self.rows[val] += delta
self.downs[var + val] += delta
self.ups[var - val + n - 1] += delta

def display(self, assignment):
"Print the queens and the nconflicts values (for debugging)."
"""Print the queens and the nconflicts values (for debugging)."""
n = len(self.variables)
for val in range(n):
for var in range(n):
Expand Down Expand Up @@ -514,11 +510,10 @@ def flatten(seqs): return sum(seqs, [])
_NEIGHBORS = {v: set() for v in flatten(_ROWS)}
for unit in map(set, _BOXES + _ROWS + _COLS):
for v in unit:
_NEIGHBORS[v].update(unit - set([v]))
_NEIGHBORS[v].update(unit - {v})


class Sudoku(CSP):

"""A Sudoku problem.
The box grid is a 3x3 array of boxes, each a 3x3 array of cells.
Each cell holds a digit in 1..9. In each box, all digits are
Expand Down Expand Up @@ -587,7 +582,7 @@ def abut(lines1, lines2): return list(


def Zebra():
"Return an instance of the Zebra Puzzle."
"""Return an instance of the Zebra Puzzle."""
Colors = 'Red Yellow Blue Green Ivory'.split()
Pets = 'Dog Fox Snails Horse Zebra'.split()
Drinks = 'OJ Tea Coffee Milk Water'.split()
Expand Down
Loading