Takes a 2D array representing phenotypes or resource sets across the world,
    and integer rpresenting the maximum number of clusters allowed, and
    optionally a dictionary indicating the rank of the cluster of each
    phenotype/resource set. If this dictionary is not provided, one will be
    generated.

    Returns: - A 2d array of numbers indicating the ranks of the clusters
               of the resource set/phenotype in each cell
             - An integer representing the number of clusters created.

def assign_ranks_by_cluster(grid, n, ranks=None):
    """
    Takes a 2D array representing phenotypes or resource sets across the world,
    and integer rpresenting the maximum number of clusters allowed, and
    optionally a dictionary indicating the rank of the cluster of each
    phenotype/resource set. If this dictionary is not provided, one will be
    generated.

    Returns: - A 2d array of numbers indicating the ranks of the clusters
               of the resource set/phenotype in each cell
             - An integer representing the number of clusters created.
    """
    if ranks is None:
        ranks = generate_ranks(grid, n)
    return assign_ranks_to_grid(grid, ranks), len(ranks)