def great_deluge(a, step_factor=500, max_iter=100, max_total_iters=1000):
    """This generator makes random variations of the object a to minimize cost.

       Yields are performed at the end of each iteration and a tuple containing
       ((iter_count, total_iters), a) is returned. iter_count is used to
       kill the while loop in the event that no new objects are found with a
       better cost. iter_count gets reset each time an object with a better
       cost is found. total_iters will kill the while loop when the total
       number of iterations through the loop reaches max_total_iters

       Object a must implement methods cost() and perturb() for evaluating
       the score and making mutations respectively. Usually, you'll want to
       write a wrapper that passes these through to methods of an internal
       data object, or functions acting on that object.
    """
    water_level = curr_cost = a.cost()
    step_size = abs(water_level) / step_factor
    iter_count = 0
    total_iters = 0
    while iter_count < max_iter and total_iters < max_total_iters:
        new = a.perturb()
        new_cost = new.cost()
        if new_cost < water_level:
            if new_cost < curr_cost:
                water_level = max(curr_cost, water_level - step_size)
                iter_count = 0
            curr_cost = new_cost
            a = new
        else:
            iter_count += 1
        yield (iter_count, total_iters), a
        total_iters += 1
