def successors(x, y, X, Y):
    """
    Return a dict of {state: action} pairs describing what can be reached from the 
    (x, y) state, and how. Note, tuple is hashable.
    """
    assert x <= X and y <= Y # (x, y) is glass levels; X and Y are glass sizes
    # 1. x pour to y, post-state: (0, y+x)
    # 2. y pour to x, post-state: (y+x, 0)
    # 3. fill x, post-state: (X, y)
    # 4. empty x, post-state: (0, y)
    # 5. fill y, post-state: (x,Y),
    # 6. empty y, post-state: (x, 0)
    return {((0, y+x) if y + x <= Y else (x-(Y-y), y+(Y-y))):'X->Y',
            ((x+y, 0) if x + y <= X else (x+(X-x), y-(X-x))):'X<-Y',
            (X, y): 'fill X', (x, Y): 'fill Y',
            (0, y): 'empty X', (x, 0): 'empty Y'}