def test_example(): ''' From a state, x, the only possible successors are x+1 and x-1. Given a starting integer, find the shortest path to the integer 8. ''' State = named('Integer', 'x, action') start = State(5, None) def goal(state): return state.x == 8 def next(state): return [State(state.x+1, action='next'), State(state.x-1, action='prev')] expected = [State(5, None), State(6,'next'), State(7,'next'), State(8,'next')] assert shortest(start, next, goal) == expected start = State(10, None) expected = [State(10, None), State(9,'prev'), State(8,'prev')] assert shortest(start, next, goal) == expected
x = Path("a", "b", "c") y = Path("d", "e", "f") assert x.first is "a" assert y.first is "d" P = PathList(x, y) assert P.first is x assert P.last is y ## Example problem for shortest path search # # From a state, x, the only possible successors are x+1 and x-1. # Given a starting integer, find the shortest path to the integer 8. from collections import namedtuple as named State = named("Integer", "x, action") start = State(5, None) def goal(state): return state.x == 8 def next(state): return [State(state.x + 1, action="+"), State(state.x - 1, action="-")] expected = [State(5, None), State(6, "+"), State(7, "+"), State(8, "+")] assert shortest(start, next, goal) == expected start = State(10, None) expected = [State(10, None), State(9, "-"), State(8, "-")] assert shortest(start, next, goal) == expected
# Write the two action functions, hold and roll. Each should take a # state as input, apply the appropriate action, and return a new # state. # # States are represented as namedtuples with signature State(p, me, you, pending). # # p: an int, 0 or 1, indicating which player's turn it is. # me: an int, the player-to-move's current score # you: an int, the other player's current score. # pending: an int, the number of points accumulated on current turn, not yet scored from collections import namedtuple as named State = named('State', 'p, me, you, pending') def hold(state): ''' Apply the hold action to a state to yield a new state: Reap the 'pending' points and it becomes the other player's turn. ''' return State(int(not state.p), state.you, state.me+state.pending, 0) def roll(state, d): ''' Apply the roll action to a state (and a die roll d) to yield a new state: If d is 1, get 1 point (losing any accumulated 'pending' points), and it is the other player's turn. If d > 1, add d to 'pending' points. ''' if d > 1:
if state not in seen: seen.add(state) if goal(state): return path+[state] else: paths.append(path+[state]) if __name__ == '__main__': ''' From a state, x, the only possible successors are x+1 and x-1. Given a starting integer, find the shortest path to the integer 8. ''' State = named('Integer', 'x, action') start = State(5, None) def goal(state): return state.x == 8 def next(state): return [State(state.x+1, action='+'), State(state.x-1, action='-')] expected = [State(5, None), State(6,'+'), State(7,'+'), State(8,'+')] assert shortest_path(start, next, goal) == expected
from collections import namedtuple as named from search import shortest_path as search Glass = named('Glass', 'level, total') class State(named('State', 'glasses, action')): __slots__ = () def contains(self, goal): return any(glass.level == goal for glass in self.glasses) class Glasses(tuple): ''' Tuple-based representation of glasses. ''' def __new__(cls, seq): return tuple.__new__(cls, seq) def fill(self, i): ''' Fill glass with index i to capacity and return new state of glasses. ''' state = list(self) total = state[i].total state[i] = Glass(total, total) return Glasses(state)
The constructor takes the number of missionaries moved, cannibals moved, and the direction in which they were moved to produce the resulting state. ''' self.missionaries = missionaries self.cannibals = cannibals self.direction = direction # sent or returned def __repr__(self): msg = '{0} missionaries and {1} cannibals were {2}' return msg.format(self.missionaries, self.cannibals, self.direction) # named tuples representing ... Move = named('Move', 'missionaries, cannibals') # number of each to move Side = named('Side', 'missionaries, cannibals, boat') State = named('State', 'origin, target, action') def next(state): '''Return list of next possible states from a given state.''' next = [] moves = (Move(*t) for t in [(0,1), (1,0), (2,0), (1,1), (0,2)]) origin, target, action = state assert origin.boat or target.boat and not (origin.boat and target.boat) if origin.cannibals > origin.missionaries > 0 or \ target.cannibals > target.missionaries > 0: return next if origin.boat: for move in moves: