""" Example of top-down programming """

# an example of a grid, for testing
_GRID = [[5, 3, 4, 6, 7, 8, 9, 1, 2],
         [6, 7, 2, 1, 9, 5, 3, 4, 8],
         [1, 9, 8, 3, 4, 2, 5, 6, 7],
         [8, 5, 9, 7, 6, 1, 4, 2, 3],
         [4, 2, 6, 8, 5, 3, 7, 9, 1],
         [7, 1, 3, 9, 2, 4, 8, 5, 6],
         [9, 6, 1, 5, 3, 7, 2, 8, 4],
         [2, 8, 7, 4, 1, 9, 6, 3, 5],
         [3, 4, 5, 2, 8, 6, 1, 7, 9]]

# an example of a digit_set, for testing
_DIGIT_SET = {1, 2, 3, 4, 5, 6, 7, 8, 9}


def valid_sudoku(grid, digit_set):
    """
    Return whether grid represents a valid,
    complete sudoku.

    @type grid: list[list]
    @type digit_set: set
    @rtype: bool

    Assume grid is square (as many rows as columns)
    and has the same number of rows as elements of
    digit_set.

    >>> valid_sudoku(_GRID, _DIGIT_SET)
    True
    >>> g = [[x for x in row] for row in _GRID]
    >>> g[0][1] = 5
    >>> valid_sudoku(g, _DIGIT_SET)
    False
    """
    assert len(grid) == len(digit_set), 'length does not match'
    assert all([len(grid) == len(row) for row in grid])
    return (_all_rows_valid(grid, digit_set) and
    _all_columns_valid(grid, digit_set) and
    _all_subsquares_valid(grid, digit_set))

def _all_rows_valid(grid, digit_set):
    """ Return whether all rows in grid are valid
    based on digit_set."""

    # all rows are valid if each individual row is valid
    return all([_list_valid(row, digit_set) for row in grid])

def _list_valid(L, digit_set):
    """ Return whether row is valid based on digit_set."""

    # row has everything from digit_set
    return set(L) == digit_set

def _all_columns_valid(grid, digit_set):
    """ Return whether all columns in grid are valid
    based on digit_set."""

    # all columns are valid if each column is valid
    return all([_list_valid(column, digit_set)
                for column in _columns(grid)])

def _columns(grid):
    """Return a list of columns in grid. """

    return [_column(grid, i) for i in range(len(grid))]

def _column(grid, i):
    return [row[i] for row in grid]

# already wrote code that does this
# def _column_valid(column, digit_set):
#    return set(column) == digit_set


if __name__ == "__main__":
    import doctest
    doctest.testmod()
