from itertools import product

def generate_solutions(n: int) -> list[tuple[int, ...]]:
    '''
    >>> generate_solutions(n=0)
    [()]
    >>> generate_solutions(n=1)
    [(0,)]
    >>> generate_solutions(n=2)
    [(0, 0), (0, 1), (1, 0), (1, 1)]
    >>> n = 3
    >>> x = generate_solutions(n)
    >>> x[:6]
    [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2)]
    >>> x[-6:]
    [(2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]
    >>> len(x) == n ** n
    True
    '''
    domain = list(range(n))
    return list(product(domain, repeat=n))

def check_constraints(q: list[int]) -> bool:
    '''

    Vérifie que toutes les contraintes du problème soient satisfaites dans
    la solution ``q`` représentant la ligne sur laquelle est placée chaque
    dames ``q[i]``.

    >>> check_constraints([0])
    True
    >>> check_constraints([1, 3, 0, 2])
    True
    >>> check_constraints([1, 3, 5, 0, 2, 4])
    True

    >>> check_constraints([0, 1, 2, 3])
    False
    >>> check_constraints([3, 2, 1, 0])
    False
    >>> check_constraints([1, 3, 0, 0])
    False
    >>> check_constraints([1, 4, 5, 2, 0, 4])
    False

    '''
    n = len(q)

    for i in range(n):
        for j in range(i + 1, n):
            if q[i] == q[j]: return False
            if q[i] - q[j] == i - j: return False
            if q[j] - q[i] == i - j: return False

    return True

def nqueens_solver(n: int) -> list[tuple[int, ...]]:
    '''
    >>> nqueens_solver(n=1)
    [(0,)]
    >>> nqueens_solver(n=2)
    []
    >>> nqueens_solver(n=3)
    []
    >>> nqueens_solver(n=4)
    [(1, 3, 0, 2), (2, 0, 3, 1)]
    >>> nqueens_solver(n=5)
    [(0, 2, 4, 1, 3), (0, 3, 1, 4, 2), (1, 3, 0, 2, 4), (1, 4, 2, 0, 3), (2, 0, 3, 1, 4), (2, 4, 1, 3, 0), (3, 0, 2, 4, 1), (3, 1, 4, 2, 0), (4, 1, 3, 0, 2), (4, 2, 0, 3, 1)]
    '''
    solutions = generate_solutions(n)
    return [s for s in solutions if check_constraints(s)]

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