﻿""" Programme de validation (et fabrication) d'un carré magique"""


# la fonction renvoie la somme de la liste d'entiers ligne
def somme_liste_simple(ligne : list) -> int:
    somme = 0
    for k in range(len(ligne)):
        somme += ligne[k]
    return somme


# version récursive de la fonction précédente
def somme_liste_recursive(ligne : list) -> int:
    if ligne == []:
        return 0
    else:
        *tete, queue = ligne
        return queue + somme_liste_recursive(tete)


# version récursive avec mémoïsation
def somme_rapide(ligne : list, somme = 0) -> int:
    if ligne == []:
        return somme
    else:
        return somme_rapide(ligne[:-1], somme + ligne[-1])


# la fonction vérifie les lignes d'un carré magique
def lignes(tableau : list) -> bool:
    densite = somme_rapide(tableau[0])
    for i in range(1, len(tableau)):
        if somme_rapide(tableau[i]) != densite:
            return False
    return True


# la fonction vérifie les colonnes d'un carré magique
def colonnes(tableau : list) -> bool:
    densite = somme_rapide([tableau[i][0] for i in range(len(tableau))])
    for j in range(1, len(tableau)):
        colonne = [tableau[i][j] for i in range(len(tableau))]
        if somme_rapide(colonne) != densite:
            return False
    return True


# la fonction vérifie la diagonale gauche d'un carré magique
def diag_gauche(tableau : list) -> bool:
    densite = somme_rapide(tableau[0])
    diag_gauche = [tableau[i][i] for i in range(len(tableau))]
    return somme_rapide(diag_gauche) == densite


# la fonction vérifie la diagonale droite d'un carré magique
def diag_droite(tableau : list) -> bool:
    densite = somme_rapide(tableau[0])
    diag_droite = [tableau[i][len(tableau) - i - 1] for i in range(len(tableau))]
    return somme_rapide(diag_droite) == densite


# la fonction vérifie si un carré est magique
def is_carre_magic(tableau : list) -> bool:
    assert len(tableau) and len(tableau[0])
    return diag_droite(tableau) and diag_gauche(tableau)\
            and lignes(tableau) and colonnes(tableau)


# la fonction fabrique un carré magique parfait d'ordre impair, selon la méthode siamoise en diagonale NE
def make_perfect_magic_square(size):
    assert isinstance(size, int) and size % 2 == 1
    perfect_magic_square = [[0 for _ in range(size)] for _ in range(size)]
    number = 1
    num_line = 0
    num_column = (size - 1) // 2
    perfect_magic_square[num_line][num_column] = number
    while number < size**2:
        number += 1
        if not perfect_magic_square[(num_line - 1) % size][(num_column + 1) % size]:
            num_line = (num_line - 1) % size
            num_column = (num_column + 1) % size
            perfect_magic_square[num_line][num_column] = number
        else:
            num_line = (num_line + 1) % size
            perfect_magic_square[num_line][num_column] = number

    return perfect_magic_square


# programme principal
carre_1 = [[1, 14, 14, 4], [11, 7, 6, 9], [8, 10, 10, 5], [13, 2, 3, 15]]
carre_2 = [[6, 32, 3, 34, 35, 1], [7, 11, 27, 28, 8, 30], [19, 14, 16, 15, 23, 24],\
            [18, 20, 22, 21, 17, 13], [25, 29, 10, 9, 26, 12], [36, 5, 33, 4, 2, 31]]
print(is_carre_magic(carre_2))
carre_3 = make_perfect_magic_square(5)
print(carre_3)
print(is_carre_magic(carre_3))
