

def isBall(data):
    return 'x' in data \
       and 'y' in data \
       and 'r' in data \
       and isinstance(data['x'], float) \
       and isinstance(data['y'], float) \
       and isinstance(data['r'], float)

def mkBall(x,y,r):
    return {
        'x':float(x),'y':float(y),'r':float(r)
    }

def X(ball):
    assert 'x' in ball
    assert isinstance(ball['x'],float)
    return ball['x']

def Y(ball):
    assert 'x' in ball
    assert isinstance(ball['x'],float)
    return ball['y']

def R(ball):
    assert 'x' in ball
    assert isinstance(ball['x'],float)
    return ball['r']

##############################################

def collideInnerBox(x,y,w,h):
    def closure(ball):
        assert isBall(ball)
        return X(ball)+R(ball) < x \
            or X(ball)-R(ball) > x+w \
            or Y(ball)+R(ball) < y \
            or Y(ball)-R(ball) > y+h
    return closure

def distBall(ballA, ballB):
    assert isBall(ballA)
    assert isBall(ballB)
    deltaX = X(ballA) - X(ballB)
    deltaY = Y(ballA) - Y(ballB)
    distSQ = deltaX**2 + deltaY**2
    dist = distSQ**0.5
    dist = dist - R(ballA)
    dist = dist - R(ballB)
    return dist

def collideInnerCircle(circle):
    assert isBall(circle)
    def closure(ball):
        return distBall(ball,circle) < 0
    return closure








