# Fichier: python_cheats/cheatsheets/patterns.txt
# Cheatsheet Patterns Python - Guide Complet pour Débutants


[OK] INTRODUCTION AUX PATTERNS

# Les patterns sont des motifs géométriques créés avec des caractères
# Exemples: triangles, carrés, pyramides, losanges...
# Utilise: boucles for, boucles imbriquées, conditions
# Concepts clés: lignes (rows), colonnes (columns), espaces, symboles

# Structure de base d'un pattern
for ligne in range(nombre_lignes):
    # Pour chaque ligne
    for colonne in range(nombre_colonnes):
        # Afficher caractère
        print("*", end="")
    print()  # Nouvelle ligne

# === COMPRENDRE print() et end="" ===

# print() normal: ajoute un retour à la ligne automatiquement
print("Hello")
print("World")
# Sortie:
# Hello
# World

# print() avec end="": n'ajoute PAS de retour à la ligne
print("Hello", end="")
print("World")
# Sortie:
# HelloWorld

# print() avec end=" ": ajoute un espace au lieu d'un retour à la ligne
print("Hello", end=" ")
print("World")
# Sortie:
# Hello World

# Utilisation dans les patterns:
for i in range(3):
    print("*", end="")  # Affiche * sans retour à la ligne
print()  # Retour à la ligne après la boucle
# Sortie: ***


[OK] CARRÉ PLEIN (SQUARE - FILLED)

# Principe: Même nombre de caractères sur chaque ligne

# === Exemple 1: Carré 5x5 avec EXPLICATION DÉTAILLÉE ===
n = 5
for i in range(n):
    for j in range(n):
        print("*", end="")
    print()

# EXPLICATION PAS À PAS:
# i=0, j=0: affiche * | i=0, j=1: affiche * | i=0, j=2: affiche * | i=0, j=3: affiche * | i=0, j=4: affiche * | puis print()
# Ligne 1: *****
# 
# i=1, j=0: affiche * | i=1, j=1: affiche * | i=1, j=2: affiche * | i=1, j=3: affiche * | i=1, j=4: affiche * | puis print()
# Ligne 2: *****
#
# Et ainsi de suite pour les 5 lignes...

# SORTIE FINALE:
# *****  <- Ligne 0: 5 étoiles
# *****  <- Ligne 1: 5 étoiles
# *****  <- Ligne 2: 5 étoiles
# *****  <- Ligne 3: 5 étoiles
# *****  <- Ligne 4: 5 étoiles

# ANALYSE:
# - Nombre total de lignes: 5 (contrôlé par range(n))
# - Nombre d'étoiles par ligne: 5 (contrôlé par range(n) interne)
# - Nombre total d'étoiles: 5 × 5 = 25
# - Forme: carré parfait (hauteur = largeur)

# === Exemple 2: Carré 4x4 avec TRACE D'EXÉCUTION ===
n = 4
print("Début du programme")
for i in range(n):
    print(f"[Ligne {i}] début ->", end=" ")
    for j in range(n):
        print("*", end="")
    print(" <- fin")
print("Fin du programme")

# SORTIE AVEC TRACE:
# Début du programme
# [Ligne 0] début -> **** <- fin
# [Ligne 1] début -> **** <- fin
# [Ligne 2] début -> **** <- fin
# [Ligne 3] début -> **** <- fin
# Fin du programme

# SANS TRACE (sortie normale):
# ****
# ****
# ****
# ****

# === Exemple 2: Carré avec taille variable ===
def carre_plein(taille):
    for i in range(taille):
        for j in range(taille):
            print("*", end="")
        print()

carre_plein(4)
# ****
# ****
# ****
# ****

# === Exemple 3: Carré avec symbole personnalisé ===
def carre_plein_custom(taille, symbole="*"):
    for i in range(taille):
        for j in range(taille):
            print(symbole, end="")
        print()

carre_plein_custom(3, "#")

# SORTIE:
# ###  <- 3 symboles #
# ###  <- 3 symboles #
# ###  <- 3 symboles #

# Comparaison avec différents symboles:
carre_plein_custom(3, "@")
# @@@
# @@@
# @@@

carre_plein_custom(3, "█")
# ███
# ███
# ███

# === Exemple 4: Méthode simplifiée EXPLIQUÉE ===
n = 5
for i in range(n):
    print("*" * n)

# EXPLICATION:
# "*" * 5 = "*****" (multiplie la chaîne par 5)
# Cette ligne est répétée 5 fois

# SORTIE:
# *****  <- Itération 0: print("*" * 5)
# *****  <- Itération 1: print("*" * 5)
# *****  <- Itération 2: print("*" * 5)
# *****  <- Itération 3: print("*" * 5)
# *****  <- Itération 4: print("*" * 5)

# COMPARAISON MÉTHODES:
# Méthode 1 (boucles imbriquées): Plus lente, plus de code
for i in range(5):
    for j in range(5):
        print("*", end="")
    print()

# Méthode 2 (multiplication): Plus rapide, moins de code
for i in range(5):
    print("*" * 5)

# Les deux produisent la même sortie!


[OK] CARRÉ VIDE (SQUARE - HOLLOW)

# Principe: Caractères seulement sur les bordures

# === Exemple 1: Carré vide 5x5 avec EXPLICATION COMPLÈTE ===
n = 5
for i in range(n):
    for j in range(n):
        # Bordures: première/dernière ligne OU première/dernière colonne
        if i == 0 or i == n-1 or j == 0 or j == n-1:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# ANALYSE LIGNE PAR LIGNE:
# 
# Ligne 0 (i=0): TOUTE LA LIGNE EST UNE BORDURE (i == 0)
#   j=0: i==0 -> True -> affiche *
#   j=1: i==0 -> True -> affiche *
#   j=2: i==0 -> True -> affiche *
#   j=3: i==0 -> True -> affiche *
#   j=4: i==0 -> True -> affiche *
# Sortie ligne 0: *****
#
# Ligne 1 (i=1): SEULEMENT PREMIÈRE ET DERNIÈRE COLONNE
#   j=0: j==0 -> True -> affiche *
#   j=1: aucune condition vraie -> affiche espace
#   j=2: aucune condition vraie -> affiche espace
#   j=3: aucune condition vraie -> affiche espace
#   j=4: j==4 (n-1) -> True -> affiche *
# Sortie ligne 1: *   *
#
# Ligne 2 (i=2): MÊME LOGIQUE QUE LIGNE 1
# Sortie ligne 2: *   *
#
# Ligne 3 (i=3): MÊME LOGIQUE QUE LIGNE 1
# Sortie ligne 3: *   *
#
# Ligne 4 (i=4): DERNIÈRE LIGNE, TOUTE UNE BORDURE (i == n-1)
# Sortie ligne 4: *****

# SORTIE FINALE:
# *****  <- Ligne 0: bordure supérieure (tous des *)
# *   *  <- Ligne 1: bordures gauche et droite seulement
# *   *  <- Ligne 2: bordures gauche et droite seulement
# *   *  <- Ligne 3: bordures gauche et droite seulement
# *****  <- Ligne 4: bordure inférieure (tous des *)

# VISUALISATION DES CONDITIONS:
# Position (i,j) | i==0 | i==n-1 | j==0 | j==n-1 | Résultat
# (0,0)         | OUI  | NON   | OUI  | NON   | * (bordure)
# (0,2)         | OUI  | NON   | NON  | NON   | * (bordure)
# (1,1)         | NON  | NON   | NON  | NON   | espace (intérieur)
# (2,2)         | NON  | NON   | NON  | NON   | espace (intérieur)
# (4,4)         | NON  | OUI   | NON  | OUI   | * (bordure)

# === Exemple 2: Carré vide 7x7 avec DÉCOMPOSITION ===
n = 7
print("Carré vide 7x7:")
for i in range(n):
    for j in range(n):
        if i == 0 or i == n-1 or j == 0 or j == n-1:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# SORTIE:
# *******  <- 7 étoiles (ligne 0)
# *     *  <- 1 étoile + 5 espaces + 1 étoile (ligne 1)
# *     *  <- 1 étoile + 5 espaces + 1 étoile (ligne 2)
# *     *  <- 1 étoile + 5 espaces + 1 étoile (ligne 3)
# *     *  <- 1 étoile + 5 espaces + 1 étoile (ligne 4)
# *     *  <- 1 étoile + 5 espaces + 1 étoile (ligne 5)
# *******  <- 7 étoiles (ligne 6)

# COMPTE DES CARACTÈRES:
# - Ligne 0: 7 étoiles, 0 espaces
# - Lignes 1-5: 2 étoiles, 5 espaces chacune
# - Ligne 6: 7 étoiles, 0 espaces
# Total étoiles: 7 + (5 × 2) + 7 = 24 étoiles
# Total espaces: 5 × 5 = 25 espaces

# === Exemple 3: Méthode simplifiée avec EXPLICATION ===
n = 5
for i in range(n):
    if i == 0 or i == n-1:
        print("*" * n)  # Ligne complète d'étoiles
    else:
        print("*" + " " * (n-2) + "*")  # Étoile + espaces + étoile

# DÉCOMPOSITION DE LA LIGNE CENTRALE:
# "*" -> première étoile
# " " * (n-2) -> espaces intérieurs (5-2 = 3 espaces)
# "*" -> dernière étoile
# Résultat: "*   *"

# SORTIE:
# *****  <- i=0: ligne complète
# *   *  <- i=1: "*" + "   " + "*"
# *   *  <- i=2: "*" + "   " + "*"
# *   *  <- i=3: "*" + "   " + "*"
# *****  <- i=4: ligne complète

# === Exemple 4: Carré vide avec BORDURES DOUBLES ===
n = 9
for i in range(n):
    for j in range(n):
        # Bordure externe
        if i == 0 or i == n-1 or j == 0 or j == n-1:
            print("█", end="")
        # Bordure interne (distance 2 des bords)
        elif i == 2 or i == n-3 or j == 2 or j == n-3:
            print("▓", end="")
        else:
            print(" ", end="")
    print()

# SORTIE:
# █████████  <- Bordure externe (tous █)
# █       █  <- Bordure externe gauche/droite
# █▓▓▓▓▓▓█  <- Bordure interne commence
# █▓   ▓█  <- Bordure interne + intérieur vide
# █▓   ▓█  <- Bordure interne + intérieur vide
# █▓   ▓█  <- Bordure interne + intérieur vide
# █▓▓▓▓▓▓█  <- Bordure interne se termine
# █       █  <- Bordure externe gauche/droite
# █████████  <- Bordure externe (tous █)


[OK] RECTANGLE PLEIN

# Principe: Largeur différente de la hauteur

# === Exemple 1: Rectangle basique ===
hauteur = 4
largeur = 7

for i in range(hauteur):
    for j in range(largeur):
        print("*", end="")
    print()

# Résultat:
# *******
# *******
# *******
# *******

# === Exemple 2: Rectangle vide ===
def rectangle_vide(hauteur, largeur):
    for i in range(hauteur):
        for j in range(largeur):
            if i == 0 or i == hauteur-1 or j == 0 or j == largeur-1:
                print("*", end="")
            else:
                print(" ", end="")
        print()

rectangle_vide(5, 10)
# **********
# *        *
# *        *
# *        *
# **********


[OK] TRIANGLE RECTANGLE CROISSANT (RIGHT TRIANGLE - ASCENDING)

# Principe: Chaque ligne a plus de caractères que la précédente

# === Exemple 1: Triangle 5 lignes avec ANALYSE DÉTAILLÉE ===
n = 5
for i in range(1, n+1):
    for j in range(i):
        print("*", end="")
    print()

# EXÉCUTION PAS À PAS:
#
# Itération 1 (i=1):
#   range(1) -> j=0
#   Affiche: *
#   print() -> nouvelle ligne
# Sortie ligne 1: *
#
# Itération 2 (i=2):
#   range(2) -> j=0, j=1
#   Affiche: * puis *
#   print() -> nouvelle ligne
# Sortie ligne 2: **
#
# Itération 3 (i=3):
#   range(3) -> j=0, j=1, j=2
#   Affiche: * puis * puis *
#   print() -> nouvelle ligne
# Sortie ligne 3: ***
#
# Itération 4 (i=4):
#   range(4) -> j=0, j=1, j=2, j=3
#   Affiche: * * * *
# Sortie ligne 4: ****
#
# Itération 5 (i=5):
#   range(5) -> j=0, j=1, j=2, j=3, j=4
#   Affiche: * * * * *
# Sortie ligne 5: *****

# SORTIE FINALE:
# *        <- 1 étoile (ligne 1)
# **       <- 2 étoiles (ligne 2)
# ***      <- 3 étoiles (ligne 3)
# ****     <- 4 étoiles (ligne 4)
# *****    <- 5 étoiles (ligne 5)

# OBSERVATIONS:
# - Numéro de ligne = nombre d'étoiles
# - Ligne i contient i étoiles
# - Total d'étoiles: 1+2+3+4+5 = 15
# - Forme: triangle rectangle (angle droit en bas à gauche)

# === Exemple 2: COMPARAISON range(1, n+1) vs range(n) ===

# Méthode A: range(1, n+1)
print("Méthode A:")
n = 4
for i in range(1, n+1):  # i: 1, 2, 3, 4
    print("*" * i)
# Sortie:
# *
# **
# ***
# ****

# Méthode B: range(n)
print("\nMéthode B:")
n = 4
for i in range(n):  # i: 0, 1, 2, 3
    print("*" * (i + 1))  # On ajoute 1 pour avoir 1, 2, 3, 4
# Sortie:
# *
# **
# ***
# ****

# Les deux produisent le même résultat!

# === Exemple 3: Triangle avec NUMÉROS au lieu d'étoiles ===
n = 5
for i in range(1, n+1):
    print(str(i) * i)

# EXPLICATION:
# i=1: str(1) * 1 = "1" -> affiche 1
# i=2: str(2) * 2 = "22" -> affiche 22
# i=3: str(3) * 3 = "333" -> affiche 333
# i=4: str(4) * 4 = "4444" -> affiche 4444
# i=5: str(5) * 5 = "55555" -> affiche 55555

# SORTIE:
# 1        <- Une fois le chiffre 1
# 22       <- Deux fois le chiffre 2
# 333      <- Trois fois le chiffre 3
# 4444     <- Quatre fois le chiffre 4
# 55555    <- Cinq fois le chiffre 5

# === Exemple 4: Triangle avec COMPTEUR CONTINU ===
n = 5
num = 1
for i in range(1, n+1):
    for j in range(i):
        print(num, end=" ")
        num += 1  # Incrémenter après chaque affichage
    print()

# TRACE D'EXÉCUTION:
# Ligne 1 (i=1): affiche 1, num devient 2
# Ligne 2 (i=2): affiche 2 3, num devient 4
# Ligne 3 (i=3): affiche 4 5 6, num devient 7
# Ligne 4 (i=4): affiche 7 8 9 10, num devient 11
# Ligne 5 (i=5): affiche 11 12 13 14 15, num devient 16

# SORTIE:
# 1           <- 1 nombre
# 2 3         <- 2 nombres
# 4 5 6       <- 3 nombres
# 7 8 9 10    <- 4 nombres
# 11 12 13 14 15  <- 5 nombres

# ANALYSE:
# - Les nombres augmentent continuellement
# - Chaque ligne a un nombre de plus que la précédente
# - Total de nombres affichés: 1+2+3+4+5 = 15 nombres

# === Exemple 5: Triangle avec NUMÉROS DE COLONNE ===
n = 5
for i in range(1, n+1):
    for j in range(1, i+1):
        print(j, end=" ")
    print()

# EXPLICATION DÉTAILLÉE:
# Ligne 1 (i=1): range(1,2) -> j=1 -> affiche "1 "
# Ligne 2 (i=2): range(1,3) -> j=1,2 -> affiche "1 2 "
# Ligne 3 (i=3): range(1,4) -> j=1,2,3 -> affiche "1 2 3 "
# Ligne 4 (i=4): range(1,5) -> j=1,2,3,4 -> affiche "1 2 3 4 "
# Ligne 5 (i=5): range(1,6) -> j=1,2,3,4,5 -> affiche "1 2 3 4 5 "

# SORTIE:
# 1           <- Commence à 1
# 1 2         <- Recommence à 1
# 1 2 3       <- Recommence à 1
# 1 2 3 4     <- Recommence à 1
# 1 2 3 4 5   <- Recommence à 1

# DIFFÉRENCE AVEC EXEMPLE 4:
# Exemple 4: compteur continu (1,2,3,4,5,6...)
# Exemple 5: compteur reset à chaque ligne (1,2,3 | 1,2,3,4 | ...)


[OK] TRIANGLE RECTANGLE DÉCROISSANT (RIGHT TRIANGLE - DESCENDING)

# Principe: Commence avec beaucoup de caractères, diminue

# === Exemple 1: Triangle décroissant ===
n = 5
for i in range(n, 0, -1):
    for j in range(i):
        print("*", end="")
    print()

# Résultat:
# *****
# ****
# ***
# **
# *

# === Exemple 2: Méthode simplifiée ===
n = 5
for i in range(n, 0, -1):
    print("*" * i)

# === Exemple 3: Avec numéros ===
n = 5
for i in range(n, 0, -1):
    for j in range(1, i+1):
        print(j, end=" ")
    print()

# Résultat:
# 1 2 3 4 5 
# 1 2 3 4 
# 1 2 3 
# 1 2 
# 1


[OK] TRIANGLE RECTANGLE VIDE

# Principe: Seulement les bordures du triangle

# === Exemple 1: Triangle croissant vide ===
n = 5
for i in range(1, n+1):
    for j in range(i):
        # Bordure gauche, bordure droite, ou dernière ligne
        if j == 0 or j == i-1 or i == n:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
# *
# **
# * *
# *  *
# *****

# === Exemple 2: Triangle décroissant vide ===
n = 5
for i in range(n, 0, -1):
    for j in range(i):
        if j == 0 or j == i-1 or i == n:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
# *****
# *   *
# *  *
# * *
# *


[OK] PYRAMIDE CENTRÉE PLEINE (PYRAMID - CENTERED)

# Principe: Triangle centré avec espaces avant

# === Exemple 1: Pyramide 5 lignes avec EXPLICATION COMPLÈTE ===
n = 5
for i in range(n):
    # Espaces avant
    for j in range(n - i - 1):
        print(" ", end="")
    # Étoiles
    for j in range(2 * i + 1):
        print("*", end="")
    print()

# DÉCOMPOSITION MATHÉMATIQUE PAR LIGNE:
#
# Ligne 0 (i=0):
#   Espaces: range(5-0-1) = range(4) -> 4 espaces
#   Étoiles: range(2*0+1) = range(1) -> 1 étoile
#   Résultat: "    *"
#
# Ligne 1 (i=1):
#   Espaces: range(5-1-1) = range(3) -> 3 espaces
#   Étoiles: range(2*1+1) = range(3) -> 3 étoiles
#   Résultat: "   ***"
#
# Ligne 2 (i=2):
#   Espaces: range(5-2-1) = range(2) -> 2 espaces
#   Étoiles: range(2*2+1) = range(5) -> 5 étoiles
#   Résultat: "  *****"
#
# Ligne 3 (i=3):
#   Espaces: range(5-3-1) = range(1) -> 1 espace
#   Étoiles: range(2*3+1) = range(7) -> 7 étoiles
#   Résultat: " *******"
#
# Ligne 4 (i=4):
#   Espaces: range(5-4-1) = range(0) -> 0 espaces
#   Étoiles: range(2*4+1) = range(9) -> 9 étoiles
#   Résultat: "*********"

# SORTIE FINALE AVEC REPÈRES:
#     *        <- 4 espaces + 1 étoile (ligne 0)
#    ***       <- 3 espaces + 3 étoiles (ligne 1)
#   *****      <- 2 espaces + 5 étoiles (ligne 2)
#  *******     <- 1 espace + 7 étoiles (ligne 3)
# *********    <- 0 espace + 9 étoiles (ligne 4)

# VISUALISATION AVEC POINTS (. = espace):
# ....*.
# ...***
# ..*****
# .*******
# *********

# FORMULES IMPORTANTES:
# - Espaces avant ligne i: n - i - 1
# - Étoiles ligne i: 2 * i + 1
# - Total caractères par ligne: (n-i-1) + (2*i+1) = n + i

# TABLEAU RÉCAPITULATIF:
# Ligne | i | Espaces | Étoiles | Total | Formule étoiles
# ------|---|---------|---------|-------|----------------
#   0   | 0 |    4    |    1    |   5   | 2*0+1 = 1
#   1   | 1 |    3    |    3    |   6   | 2*1+1 = 3
#   2   | 2 |    2    |    5    |   7   | 2*2+1 = 5
#   3   | 3 |    1    |    7    |   8   | 2*3+1 = 7
#   4   | 4 |    0    |    9    |   9   | 2*4+1 = 9

# OBSERVATION: Les étoiles sont toujours impaires (1,3,5,7,9)
# Pourquoi? 2*i+1 donne toujours un nombre impair

# === Exemple 2: MÊME PYRAMIDE avec méthode simplifiée ===
n = 5
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# Cette ligne fait EXACTEMENT la même chose!
# " " * X -> répète l'espace X fois
# "*" * Y -> répète l'étoile Y fois
# Les concatène ensemble

# SORTIE (identique):
#     *
#    ***
#   *****
#  *******
# *********

# === Exemple 3: Pyramide avec BORDURES VISIBLES ===
n = 5
for i in range(n):
    espaces = " " * (n - i - 1)
    etoiles = "*" * (2 * i + 1)
    ligne = espaces + etoiles + espaces  # Ajout espaces après pour voir la symétrie
    print(f"|{ligne}|")  # Bordures pour visualisation

# SORTIE AVEC BORDURES:
# |    *    |  <- 4 espaces à gauche, 1 étoile, 4 espaces à droite
# |   ***   |  <- 3 espaces à gauche, 3 étoiles, 3 espaces à droite
# |  *****  |  <- 2 espaces à gauche, 5 étoiles, 2 espaces à droite
# | ******* |  <- 1 espace à gauche, 7 étoiles, 1 espace à droite
# |*********|  <- 0 espace à gauche, 9 étoiles, 0 espace à droite

# On voit clairement la symétrie!

# === Exemple 4: Pyramide NUMÉROTÉE pour comprendre ===
n = 5
for i in range(n):
    # Espaces numérotés
    for j in range(n - i - 1):
        print(".", end="")  # . pour voir les espaces
    
    # Étoiles numérotées
    for j in range(2 * i + 1):
        print(j, end="")  # Affiche le numéro au lieu de *
    
    print()

# SORTIE:
# ....0        <- 4 points, 1 chiffre (0)
# ...012       <- 3 points, 3 chiffres (0,1,2)
# ..01234      <- 2 points, 5 chiffres (0,1,2,3,4)
# .0123456     <- 1 point, 7 chiffres (0,1,2,3,4,5,6)
# 012345678    <- 0 point, 9 chiffres (0,1,2,3,4,5,6,7,8)

# On voit clairement combien d'espaces et de caractères!

# === Exemple 5: Pyramide avec HAUTEUR VARIABLE ===
def pyramide(hauteur, symbole="*"):
    """
    Crée une pyramide de hauteur donnée
    
    Args:
        hauteur: nombre de lignes
        symbole: caractère à utiliser
    """
    for i in range(hauteur):
        espaces = " " * (hauteur - i - 1)
        symboles = symbole * (2 * i + 1)
        print(espaces + symboles)

# Petite pyramide (3 lignes):
pyramide(3)
#   *
#  ***
# *****

# Grande pyramide (8 lignes):
pyramide(8)
#        *
#       ***
#      *****
#     *******
#    *********
#   ***********
#  *************
# ***************

# Pyramide avec #:
pyramide(4, "#")
#    #
#   ###
#  #####
# #######


[OK] PYRAMIDE INVERSÉE (INVERTED PYRAMID)

# Principe: Pyramide à l'envers

# === Exemple 1: Pyramide inversée basique ===
n = 5
for i in range(n, 0, -1):
    # Espaces avant
    for j in range(n - i):
        print(" ", end="")
    # Étoiles
    for j in range(2 * i - 1):
        print("*", end="")
    print()

# Résultat:
# *********
#  *******
#   *****
#    ***
#     *

# === Exemple 2: Méthode simplifiée ===
n = 5
for i in range(n, 0, -1):
    print(" " * (n - i) + "*" * (2 * i - 1))

# === Exemple 3: Avec fonction ===
def pyramide_inversee(hauteur):
    for i in range(hauteur, 0, -1):
        espaces = " " * (hauteur - i)
        etoiles = "*" * (2 * i - 1)
        print(espaces + etoiles)


[OK] PYRAMIDE VIDE (HOLLOW PYRAMID)

# Principe: Seulement les bordures de la pyramide

# === Exemple 1: Pyramide vide ===
n = 5
for i in range(n):
    # Espaces avant
    for j in range(n - i - 1):
        print(" ", end="")
    # Étoiles et espaces intérieurs
    for j in range(2 * i + 1):
        # Premier, dernier caractère, ou dernière ligne
        if j == 0 or j == 2 * i or i == n - 1:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
#     *
#    * *
#   *   *
#  *     *
# *********

# === Exemple 2: Avec fonction ===
def pyramide_vide(hauteur):
    for i in range(hauteur):
        ligne = " " * (hauteur - i - 1)
        
        if i == 0:
            ligne += "*"
        elif i == hauteur - 1:
            ligne += "*" * (2 * i + 1)
        else:
            ligne += "*" + " " * (2 * i - 1) + "*"
        
        print(ligne)

pyramide_vide(6)
#      *
#     * *
#    *   *
#   *     *
#  *       *
# ***********


[OK] LOSANGE PLEIN (DIAMOND - FILLED)

# Principe: Pyramide + pyramide inversée (sans répéter la ligne du milieu)

# === Exemple 1: Losange 5 lignes avec ANALYSE COMPLÈTE ===
n = 5

# PARTIE 1: Moitié supérieure (pyramide)
print("=== PARTIE SUPÉRIEURE ===")
for i in range(n):
    ligne = " " * (n - i - 1) + "*" * (2 * i + 1)
    print(f"Ligne {i}: {ligne}")

# SORTIE PARTIE SUPÉRIEURE:
# Ligne 0:     *        (4 espaces, 1 étoile)
# Ligne 1:    ***       (3 espaces, 3 étoiles)
# Ligne 2:   *****      (2 espaces, 5 étoiles)
# Ligne 3:  *******     (1 espace, 7 étoiles)
# Ligne 4: *********    (0 espace, 9 étoiles) <- Ligne la plus large

# PARTIE 2: Moitié inférieure (pyramide inversée)
print("=== PARTIE INFÉRIEURE ===")
for i in range(n - 2, -1, -1):  # n-2 pour ne pas répéter la ligne du milieu
    ligne = " " * (n - i - 1) + "*" * (2 * i + 1)
    print(f"Ligne {i}: {ligne}")

# SORTIE PARTIE INFÉRIEURE:
# Ligne 3:  *******     (1 espace, 7 étoiles)
# Ligne 2:   *****      (2 espaces, 5 étoiles)
# Ligne 1:    ***       (3 espaces, 3 étoiles)
# Ligne 0:     *        (4 espaces, 1 étoile)

# LOSANGE COMPLET:
#     *        <- Ligne 0 (haut)
#    ***       <- Ligne 1
#   *****      <- Ligne 2
#  *******     <- Ligne 3
# *********    <- Ligne 4 (milieu) - LA PLUS LARGE
#  *******     <- Ligne 3 (répétée)
#   *****      <- Ligne 2 (répétée)
#    ***       <- Ligne 1 (répétée)
#     *        <- Ligne 0 (bas)

# EXPLICATION range(n-2, -1, -1):
# n = 5
# range(n-2, -1, -1) = range(3, -1, -1)
# Produit: 3, 2, 1, 0
# On s'arrête à 0 (inclus)
# On NE répète PAS la ligne 4 (ligne du milieu)

# === Exemple 2: TRACE D'EXÉCUTION complète ===
n = 4
print("Construction du losange 4 lignes:")
print("\n--- Partie haute ---")
for i in range(n):
    espaces = n - i - 1
    etoiles = 2 * i + 1
    print(f"i={i}: {espaces} espaces + {etoiles} étoiles = {' '*espaces + '*'*etoiles}")

print("\n--- Partie basse ---")
for i in range(n - 2, -1, -1):
    espaces = n - i - 1
    etoiles = 2 * i + 1
    print(f"i={i}: {espaces} espaces + {etoiles} étoiles = {' '*espaces + '*'*etoiles}")

# SORTIE DÉTAILLÉE:
# Construction du losange 4 lignes:
#
# --- Partie haute ---
# i=0: 3 espaces + 1 étoiles =    *
# i=1: 2 espaces + 3 étoiles =   ***
# i=2: 1 espaces + 5 étoiles =  *****
# i=3: 0 espaces + 7 étoiles = *******
#
# --- Partie basse ---
# i=2: 1 espaces + 5 étoiles =  *****
# i=1: 2 espaces + 3 étoiles =   ***
# i=0: 3 espaces + 1 étoiles =    *

# LOSANGE FINAL:
#    *       <- i=0
#   ***      <- i=1
#  *****     <- i=2
# *******    <- i=3 (milieu, apparaît une seule fois)
#  *****     <- i=2 (répété)
#   ***      <- i=1 (répété)
#    *       <- i=0 (répété)

# === Exemple 3: Losange avec BORDURES pour visualisation ===
n = 5
largeur_totale = 2 * n - 1  # Largeur max de la ligne du milieu

# Partie haute
for i in range(n):
    espaces = " " * (n - i - 1)
    etoiles = "*" * (2 * i + 1)
    espaces_apres = " " * (n - i - 1)
    print(f"|{espaces + etoiles + espaces_apres}|")

# Partie basse
for i in range(n - 2, -1, -1):
    espaces = " " * (n - i - 1)
    etoiles = "*" * (2 * i + 1)
    espaces_apres = " " * (n - i - 1)
    print(f"|{espaces + etoiles + espaces_apres}|")

# SORTIE AVEC BORDURES:
# |    *    |  <- Centré dans une largeur de 9
# |   ***   |
# |  *****  |
# | ******* |
# |*********|  <- Remplit toute la largeur
# | ******* |
# |  *****  |
# |   ***   |
# |    *    |

# On voit la parfaite symétrie verticale!

# === Exemple 4: COMPTE des caractères ===
n = 5
total_lignes = 0
total_etoiles = 0

print("Analyse du losange:")
# Partie haute
for i in range(n):
    nb_etoiles = 2 * i + 1
    total_etoiles += nb_etoiles
    total_lignes += 1
    print(f"Ligne {total_lignes}: {nb_etoiles} étoiles")

# Partie basse
for i in range(n - 2, -1, -1):
    nb_etoiles = 2 * i + 1
    total_etoiles += nb_etoiles
    total_lignes += 1
    print(f"Ligne {total_lignes}: {nb_etoiles} étoiles")

print(f"\nTotal: {total_lignes} lignes, {total_etoiles} étoiles")

# SORTIE:
# Analyse du losange:
# Ligne 1: 1 étoiles
# Ligne 2: 3 étoiles
# Ligne 3: 5 étoiles
# Ligne 4: 7 étoiles
# Ligne 5: 9 étoiles    <- Ligne du milieu
# Ligne 6: 7 étoiles
# Ligne 7: 5 étoiles
# Ligne 8: 3 étoiles
# Ligne 9: 1 étoiles
#
# Total: 9 lignes, 45 étoiles
# Formule: (2*n-1) lignes pour un losange de taille n

# === Exemple 5: Losange ASYMÉTRIQUE (erreur courante) ===
print("[X] ERREUR: Losange avec ligne milieu répétée")
n = 4
# Partie haute
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Partie basse AVEC ligne milieu répétée (mauvais!)
for i in range(n - 1, -1, -1):  # range(3, -1, -1) -> 3,2,1,0
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# SORTIE (MAUVAISE):
#    *
#   ***
#  *****
# *******
# *******  <- RÉPÉTITION! Deux fois la même ligne
#  *****
#   ***
#    *

print("\n[OK] CORRECT: Sans répétition")
n = 4
# Partie haute
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Partie basse SANS ligne milieu (correct!)
for i in range(n - 2, -1, -1):  # range(2, -1, -1) -> 2,1,0
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# SORTIE (CORRECTE):
#    *
#   ***
#  *****
# *******  <- Une seule fois
#  *****
#   ***
#    *


[OK] LOSANGE VIDE (DIAMOND - HOLLOW)

# Principe: Seulement les bordures du losange

# === Exemple 1: Losange vide ===
n = 5

# Partie supérieure
for i in range(n):
    ligne = " " * (n - i - 1)
    if i == 0:
        ligne += "*"
    else:
        ligne += "*" + " " * (2 * i - 1) + "*"
    print(ligne)

# Partie inférieure
for i in range(n - 2, -1, -1):
    ligne = " " * (n - i - 1)
    if i == 0:
        ligne += "*"
    else:
        ligne += "*" + " " * (2 * i - 1) + "*"
    print(ligne)

# Résultat:
#     *
#    * *
#   *   *
#  *     *
# *       *
#  *     *
#   *   *
#    * *
#     *

# === Exemple 2: Fonction complète ===
def losange_vide(taille):
    # Moitié supérieure
    for i in range(taille):
        espaces = " " * (taille - i - 1)
        if i == 0:
            print(espaces + "*")
        else:
            print(espaces + "*" + " " * (2 * i - 1) + "*")
    
    # Moitié inférieure
    for i in range(taille - 2, -1, -1):
        espaces = " " * (taille - i - 1)
        if i == 0:
            print(espaces + "*")
        else:
            print(espaces + "*" + " " * (2 * i - 1) + "*")


[OK] SABLIER (HOURGLASS)

# Principe: Pyramide inversée + pyramide normale

# === Exemple 1: Sablier plein ===
n = 5

# Partie supérieure (pyramide inversée)
for i in range(n, 0, -1):
    print(" " * (n - i) + "*" * (2 * i - 1))

# Partie inférieure (pyramide)
for i in range(2, n + 1):
    print(" " * (n - i) + "*" * (2 * i - 1))

# Résultat:
# *********
#  *******
#   *****
#    ***
#     *
#    ***
#   *****
#  *******
# *********

# === Exemple 2: Sablier vide ===
def sablier_vide(taille):
    # Partie supérieure
    for i in range(taille, 0, -1):
        espaces = " " * (taille - i)
        if i == 1:
            print(espaces + "*")
        elif i == taille:
            print(espaces + "*" * (2 * i - 1))
        else:
            print(espaces + "*" + " " * (2 * i - 3) + "*")
    
    # Partie inférieure
    for i in range(2, taille + 1):
        espaces = " " * (taille - i)
        if i == taille:
            print(espaces + "*" * (2 * i - 1))
        else:
            print(espaces + "*" + " " * (2 * i - 3) + "*")


[OK] TRIANGLE PASCAL (PASCAL'S TRIANGLE)

# Principe: Chaque nombre est la somme des deux nombres au-dessus

# === Exemple 1: Triangle de Pascal basique ===
def triangle_pascal(n):
    for i in range(n):
        # Espaces pour centrer
        print(" " * (n - i), end="")
        
        # Calculer les valeurs
        nombre = 1
        for j in range(i + 1):
            print(nombre, end="   ")
            nombre = nombre * (i - j) // (j + 1)
        print()

triangle_pascal(6)
# Résultat:
#       1   
#      1   1   
#     1   2   1   
#    1   3   3   1   
#   1   4   6   4   1   
#  1   5   10  10  5   1

# === Exemple 2: Avec liste ===
def triangle_pascal_liste(n):
    for i in range(n):
        ligne = [1]
        for j in range(1, i):
            ligne.append(ligne[j-1] * (i - j + 1) // j)
        if i > 0:
            ligne.append(1)
        
        print(" " * (n - i), end="")
        print("  ".join(str(x) for x in ligne))


[OK] PATTERNS AVEC NOMBRES

# === Exemple 1: Triangle avec compteur ===
n = 5
compteur = 1
for i in range(1, n + 1):
    for j in range(i):
        print(compteur, end=" ")
        compteur += 1
    print()

# Résultat:
# 1 
# 2 3 
# 4 5 6 
# 7 8 9 10 
# 11 12 13 14 15

# === Exemple 2: Triangle avec numéros de ligne ===
n = 5
for i in range(1, n + 1):
    for j in range(i):
        print(i, end=" ")
    print()

# Résultat:
# 1 
# 2 2 
# 3 3 3 
# 4 4 4 4 
# 5 5 5 5 5

# === Exemple 3: Triangle avec numéros de colonne ===
n = 5
for i in range(1, n + 1):
    for j in range(1, i + 1):
        print(j, end=" ")
    print()

# Résultat:
# 1 
# 1 2 
# 1 2 3 
# 1 2 3 4 
# 1 2 3 4 5

# === Exemple 4: Carré avec coordonnées ===
n = 5
for i in range(1, n + 1):
    for j in range(1, n + 1):
        print(f"{i}{j}", end=" ")
    print()

# Résultat:
# 11 12 13 14 15 
# 21 22 23 24 25 
# 31 32 33 34 35 
# 41 42 43 44 45 
# 51 52 53 54 55


[OK] PATTERNS AVEC LETTRES

# === Exemple 1: Triangle avec lettres croissantes ===
n = 5
for i in range(n):
    for j in range(i + 1):
        print(chr(65 + j), end=" ")
    print()

# Résultat:
# A 
# A B 
# A B C 
# A B C D 
# A B C D E

# === Exemple 2: Triangle avec même lettre par ligne ===
n = 5
for i in range(n):
    for j in range(i + 1):
        print(chr(65 + i), end=" ")
    print()

# Résultat:
# A 
# B B 
# C C C 
# D D D D 
# E E E E E

# === Exemple 3: Pyramide de lettres ===
n = 5
for i in range(n):
    # Espaces
    print(" " * (n - i - 1), end="")
    
    # Lettres croissantes
    for j in range(i + 1):
        print(chr(65 + j), end="")
    
    # Lettres décroissantes
    for j in range(i - 1, -1, -1):
        print(chr(65 + j), end="")
    
    print()

# Résultat:
#     A
#    ABA
#   ABCBA
#  ABCDCBA
# ABCDEDCBA

# === Exemple 4: Alphabet en triangle ===
def triangle_alphabet(n):
    lettre = 65  # 'A' en ASCII
    for i in range(n):
        for j in range(i + 1):
            print(chr(lettre), end=" ")
            lettre += 1
            if lettre > 90:  # Retour à 'A' après 'Z'
                lettre = 65
        print()


[OK] PATTERNS AVANCÉS

# === Exemple 1: Croix ===
n = 7
for i in range(n):
    for j in range(n):
        # Diagonale principale ou anti-diagonale
        if i == j or i + j == n - 1:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
# *     *
#  *   *
#   * *
#    *
#   * *
#  *   *
# *     *

# === Exemple 2: Diagonale ===
n = 5
for i in range(n):
    for j in range(n):
        if i == j:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
# *
#  *
#   *
#    *
#     *

# === Exemple 3: Cadre double ===
n = 9
for i in range(n):
    for j in range(n):
        # Bordure extérieure
        if i == 0 or i == n-1 or j == 0 or j == n-1:
            print("*", end="")
        # Bordure intérieure
        elif i == 2 or i == n-3 or j == 2 or j == n-3:
            print("#", end="")
        else:
            print(" ", end="")
    print()

# Résultat:
# *********
# *       *
# *#####  *
# *#   #  *
# *#   #  *
# *#   #  *
# *#####  *
# *       *
# *********

# === Exemple 4: Escalier ===
n = 5
for i in range(n):
    print(" " * (2 * i) + "**")
    print(" " * (2 * i) + "**")

# Résultat:
# **
# **
#   **
#   **
#     **
#     **
#       **
#       **
#         **
#         **

# === Exemple 5: Zigzag ===
n = 5
largeur = 15
for i in range(n):
    for j in range(largeur):
        # Pattern en zigzag
        if (i + j) % 4 == 0 or (i + j) % 4 == 2:
            print("*", end="")
        else:
            print(" ", end="")
    print()

# === Exemple 6: Damier ===
n = 8
for i in range(n):
    for j in range(n):
        if (i + j) % 2 == 0:
            print("█", end="")
        else:
            print(" ", end="")
    print()


[OK] PATTERNS AVEC SYMBOLES MIXTES

# === Exemple 1: Pyramide alternée ===
n = 5
symboles = ["*", "#", "@", "$", "%"]
for i in range(n):
    print(" " * (n - i - 1) + symboles[i] * (2 * i + 1))

# Résultat:
#     *
#    ###
#   @@@@@
#  $$$$$$$
# %%%%%%%%%

# === Exemple 2: Triangle arc-en-ciel ===
def triangle_colore(n):
    symboles = ["*", "+", "#", "@", "=", "%", "&"]
    for i in range(n):
        for j in range(i + 1):
            print(symboles[j % len(symboles)], end="")
        print()

triangle_colore(7)
# *
# *+
# *+#
# *+#@
# *+#@=
# *+#@=%
# *+#@=%&

# === Exemple 3: Carré avec bordure différente ===
n = 7
for i in range(n):
    for j in range(n):
        if i == 0 or i == n-1 or j == 0 or j == n-1:
            print("#", end="")
        else:
            print("*", end="")
    print()

# Résultat:
# #######
# #*****#
# #*****#
# #*****#
# #*****#
# #*****#
# #######


[OK] PATTERNS INTERACTIFS

# === Exemple 1: Pattern au choix de l'utilisateur ===
def menu_patterns():
    print("\n=== GÉNÉRATEUR DE PATTERNS ===")
    print("1. Carré plein")
    print("2. Triangle croissant")
    print("3. Pyramide")
    print("4. Losange")
    print("5. Quitter")
    
    choix = int(input("\nVotre choix: "))
    
    if choix == 1:
        n = int(input("Taille: "))
        for i in range(n):
            print("*" * n)
    
    elif choix == 2:
        n = int(input("Hauteur: "))
        for i in range(1, n + 1):
            print("*" * i)
    
    elif choix == 3:
        n = int(input("Hauteur: "))
        for i in range(n):
            print(" " * (n - i - 1) + "*" * (2 * i + 1))
    
    elif choix == 4:
        n = int(input("Taille: "))
        # Moitié supérieure
        for i in range(n):
            print(" " * (n - i - 1) + "*" * (2 * i + 1))
        # Moitié inférieure
        for i in range(n - 2, -1, -1):
            print(" " * (n - i - 1) + "*" * (2 * i + 1))

# === Exemple 2: Pattern personnalisé ===
def pattern_personnalise():
    hauteur = int(input("Hauteur: "))
    symbole = input("Symbole à utiliser: ")
    type_pattern = input("Type (carre/triangle/pyramide): ")
    
    if type_pattern == "carre":
        for i in range(hauteur):
            print(symbole * hauteur)
    
    elif type_pattern == "triangle":
        for i in range(1, hauteur + 1):
            print(symbole * i)
    
    elif type_pattern == "pyramide":
        for i in range(hauteur):
            print(" " * (hauteur - i - 1) + symbole * (2 * i + 1))


[OK] ASTUCES ET OPTIMISATIONS

# === Astuce 1: Utiliser la multiplication de chaînes ===
# [X] Lent (boucle)
for i in range(5):
    ligne = ""
    for j in range(5):
        ligne += "*"
    print(ligne)

# [OK] Rapide (multiplication)
for i in range(5):
    print("*" * 5)

# === Astuce 2: Fonction générique ===
def pattern_generique(hauteur, type_pattern="triangle", symbole="*", rempli=True):
    """
    Génère différents types de patterns
    
    type_pattern: 'triangle', 'pyramide', 'carre', 'losange'
    rempli: True pour plein, False pour vide
    """
    if type_pattern == "carre":
        for i in range(hauteur):
            if rempli or i == 0 or i == hauteur - 1:
                print(symbole * hauteur)
            else:
                print(symbole + " " * (hauteur - 2) + symbole)
    
    elif type_pattern == "triangle":
        for i in range(1, hauteur + 1):
            if rempli:
                print(symbole * i)
            else:
                if i == 1 or i == hauteur:
                    print(symbole * i)
                else:
                    print(symbole + " " * (i - 2) + symbole)
    
    elif type_pattern == "pyramide":
        for i in range(hauteur):
            espaces = " " * (hauteur - i - 1)
            if rempli:
                print(espaces + symbole * (2 * i + 1))
            else:
                if i == 0:
                    print(espaces + symbole)
                elif i == hauteur - 1:
                    print(espaces + symbole * (2 * i + 1))
                else:
                    print(espaces + symbole + " " * (2 * i - 1) + symbole)
    
    elif type_pattern == "losange":
        # Moitié supérieure
        for i in range(hauteur):
            espaces = " " * (hauteur - i - 1)
            if rempli:
                print(espaces + symbole * (2 * i + 1))
            else:
                if i == 0:
                    print(espaces + symbole)
                else:
                    print(espaces + symbole + " " * (2 * i - 1) + symbole)
        
        # Moitié inférieure
        for i in range(hauteur - 2, -1, -1):
            espaces = " " * (hauteur - i - 1)
            if rempli:
                print(espaces + symbole * (2 * i + 1))
            else:
                if i == 0:
                    print(espaces + symbole)
                else:
                    print(espaces + symbole + " " * (2 * i - 1) + symbole)

# Exemples d'utilisation
pattern_generique(5, "pyramide", "#", True)
pattern_generique(4, "losange", "@", False)

# === Astuce 3: Liste comprehension ===
# Générer toutes les lignes d'un coup
n = 5
triangle = [("*" * i) for i in range(1, n + 1)]
for ligne in triangle:
    print(ligne)

# === Astuce 4: Join pour performance ===
# [X] Concaténation lente
n = 100
for i in range(n):
    ligne = ""
    for j in range(n):
        ligne += "*"
    print(ligne)

# [OK] Join rapide
n = 100
for i in range(n):
    print("".join(["*" for j in range(n)]))

# === Astuce 5: F-strings pour formatting ===
n = 5
for i in range(1, n + 1):
    print(f"{'*' * i:^{n}}")  # Centré sur n caractères


[OK] COMPRENDRE LES SORTIES - GUIDE VISUEL

# === CONCEPT 1: Espaces vs Caractères visibles ===

# Les espaces sont INVISIBLES mais COMPTENT dans le positionnement
print("Sans espaces:")
print("*")
print("**")
print("***")
# Sortie:
# *
# **
# ***

print("\nAvec espaces avant:")
print("  *")    # 2 espaces avant
print(" **")    # 1 espace avant
print("***")    # 0 espace avant
# Sortie:
#   *      <- Décalé à droite de 2
#  **      <- Décalé à droite de 1
# ***      <- Pas de décalage

# === CONCEPT 2: end="" vs print() normal ===

# Sans end="" (comportement par défaut)
print("A")
print("B")
print("C")
# Sortie:
# A
# B
# C
# (chaque print fait un retour à la ligne)

# Avec end=""
print("A", end="")
print("B", end="")
print("C")
# Sortie:
# ABC
# (pas de retour à la ligne jusqu'au dernier print)

# Avec end=" "
print("A", end=" ")
print("B", end=" ")
print("C")
# Sortie:
# A B C
# (espaces entre chaque, puis retour à la ligne)

# === CONCEPT 3: Multiplication de chaînes ===

# Répétition avec *
print("=" * 10)
# Sortie:
# ==========
# (10 fois le caractère =)

print("*" * 5)
# Sortie:
# *****
# (5 fois le caractère *)

print("12" * 3)
# Sortie:
# 121212
# (3 fois la chaîne "12")

# === CONCEPT 4: Concaténation ===

# Combiner des chaînes avec +
espaces = " " * 3
etoiles = "*" * 5
ligne = espaces + etoiles
print(ligne)
# Sortie:
#    *****
# (3 espaces suivis de 5 étoiles)

# Ordre important!
print("*" * 3 + "-" * 3)
# Sortie:
# ***---

print("-" * 3 + "*" * 3)
# Sortie:
# ---***

# === CONCEPT 5: Visualiser les espaces ===

# Utiliser des caractères visibles pour comprendre
n = 5
print("Pyramide avec points (.) au lieu d'espaces:")
for i in range(n):
    print("." * (n - i - 1) + "*" * (2 * i + 1))

# Sortie:
# ....*
# ..***
# .*****
# *******
# *********

# On voit clairement où sont les espaces!

# Maintenant avec de vrais espaces:
print("\nPyramide normale:")
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# Sortie:
#     *
#    ***
#   *****
#  *******
# *********

# === CONCEPT 6: Déboguer un pattern ===

# Afficher les valeurs des variables
n = 4
print("Débogage d'une pyramide:")
for i in range(n):
    nb_espaces = n - i - 1
    nb_etoiles = 2 * i + 1
    print(f"i={i} | espaces={nb_espaces} | étoiles={nb_etoiles} | Résultat: {' '*nb_espaces + '*'*nb_etoiles}")

# Sortie:
# Débogage d'une pyramide:
# i=0 | espaces=3 | étoiles=1 | Résultat:    *
# i=1 | espaces=2 | étoiles=3 | Résultat:   ***
# i=2 | espaces=1 | étoiles=5 | Résultat:  *****
# i=3 | espaces=0 | étoiles=7 | Résultat: *******

# === CONCEPT 7: Utiliser des bordures ===

# Ajouter | au début et à la fin pour voir les alignements
n = 5
for i in range(n):
    ligne = " " * (n - i - 1) + "*" * (2 * i + 1)
    print(f"|{ligne}|")

# Sortie:
# |    *|      <- On voit les 4 espaces à gauche
# |   ***|     <- On voit les 3 espaces à gauche
# |  *****|    <- On voit les 2 espaces à gauche
# | *******|   <- On voit 1 espace à gauche
# |*********|  <- Aucun espace à gauche

# === CONCEPT 8: Compter les caractères ===

# Vérifier qu'on a le bon nombre
n = 5
for i in range(n):
    espaces = " " * (n - i - 1)
    etoiles = "*" * (2 * i + 1)
    ligne = espaces + etoiles
    print(f"Longueur={len(ligne):2} | {ligne}")

# Sortie:
# Longueur= 5 |     *
# Longueur= 6 |    ***
# Longueur= 7 |   *****
# Longueur= 8 |  *******
# Longueur= 9 | *********

# Observation: la longueur augmente!
# C'est normal car on enlève des espaces mais on ajoute plus d'étoiles

# === CONCEPT 9: Comprendre range() dans les patterns ===

print("range(5) produit:")
for i in range(5):
    print(f"  i = {i}")
# Sortie:
#   i = 0
#   i = 1
#   i = 2
#   i = 3
#   i = 4

print("\nrange(1, 6) produit:")
for i in range(1, 6):
    print(f"  i = {i}")
# Sortie:
#   i = 1
#   i = 2
#   i = 3
#   i = 4
#   i = 5

print("\nrange(5, 0, -1) produit:")
for i in range(5, 0, -1):
    print(f"  i = {i}")
# Sortie:
#   i = 5
#   i = 4
#   i = 3
#   i = 2
#   i = 1

# === CONCEPT 10: Symétrie dans les patterns ===

# Pyramide = symétrie verticale
n = 4
print("Pyramide (symétrie verticale):")
for i in range(n):
    ligne = " " * (n - i - 1) + "*" * (2 * i + 1)
    print(ligne)

# Sortie:
#    *       <- Centre: colonne 3
#   ***      <- Centre: colonne 3
#  *****     <- Centre: colonne 3
# *******    <- Centre: colonne 3

# Losange = double symétrie (verticale ET horizontale)
print("\nLosange (double symétrie):")
n = 4
# Haut
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Bas
for i in range(n - 2, -1, -1):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# Sortie:
#    *       <- Ligne miroir entre haut et bas
#   ***
#  *****
# *******    <- Axe de symétrie horizontal
#  *****
#   ***
#    *       <- Symétrique avec la première ligne


[OK] EXERCICES PROGRESSIFS

# === Niveau 1: Débutant ===

# Exercice 1: Ligne horizontale
# Afficher: **********
for i in range(10):
    print("*", end="")
print()

# Exercice 2: Colonne verticale
# Afficher:
# *
# *
# *
# *
# *
for i in range(5):
    print("*")

# Exercice 3: Carré 4x4
for i in range(4):
    for j in range(4):
        print("*", end="")
    print()

# === Niveau 2: Intermédiaire ===

# Exercice 4: Triangle croissant simple
n = 5
for i in range(1, n + 1):
    print("*" * i)

# Exercice 5: Triangle décroissant simple
n = 5
for i in range(n, 0, -1):
    print("*" * i)

# Exercice 6: Carré vide 6x6
n = 6
for i in range(n):
    if i == 0 or i == n - 1:
        print("*" * n)
    else:
        print("*" + " " * (n - 2) + "*")

# === Niveau 3: Avancé ===

# Exercice 7: Pyramide centrée
n = 5
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# Exercice 8: Losange complet
n = 5
# Partie haute
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))
# Partie basse
for i in range(n - 2, -1, -1):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))

# Exercice 9: Pyramide vide
n = 7
for i in range(n):
    espaces = " " * (n - i - 1)
    if i == 0:
        print(espaces + "*")
    elif i == n - 1:
        print(espaces + "*" * (2 * i + 1))
    else:
        print(espaces + "*" + " " * (2 * i - 1) + "*")

# === Niveau 4: Expert ===

# Exercice 10: Pattern personnalisé - Flèche
def fleche(hauteur):
    # Partie pointue
    for i in range(hauteur):
        print(" " * (hauteur - i - 1) + "*" * (2 * i + 1))
    
    # Corps de la flèche
    largeur = 2 * hauteur - 1
    corps = largeur // 3
    for i in range(hauteur // 2):
        espaces = (largeur - corps) // 2
        print(" " * espaces + "*" * corps)

fleche(5)
#     *
#    ***
#   *****
#  *******
# *********
#    ***
#    ***

# Exercice 11: Sapin de Noël
def sapin(hauteur):
    # Étages du sapin
    for etage in range(3):
        for i in range(hauteur):
            espaces = hauteur - i - 1 + (2 - etage) * 2
            etoiles = 2 * i + 1 + etage * 4
            print(" " * espaces + "*" * etoiles)
    
    # Tronc
    for i in range(2):
        print(" " * (hauteur + 1) + "***")

sapin(3)


[OK] PATTERNS MATHÉMATIQUES

# === Pattern 1: Nombre triangulaire ===
# Somme: 1+2+3+...+n
n = 5
for i in range(1, n + 1):
    somme = sum(range(1, i + 1))
    print(f"Ligne {i}: {' '.join(str(j) for j in range(1, i + 1))} = {somme}")

# Résultat:
# Ligne 1: 1 = 1
# Ligne 2: 1 2 = 3
# Ligne 3: 1 2 3 = 6
# Ligne 4: 1 2 3 4 = 10
# Ligne 5: 1 2 3 4 5 = 15

# === Pattern 2: Fibonacci en triangle ===
def fibonacci_triangle(n):
    a, b = 0, 1
    for i in range(1, n + 1):
        for j in range(i):
            print(b, end=" ")
            a, b = b, a + b
        print()

fibonacci_triangle(5)
# Résultat:
# 1 
# 1 2 
# 3 5 8 
# 13 21 34 55 
# 89 144 233 377 610

# === Pattern 3: Carré magique simple ===
n = 3
for i in range(1, n * n + 1, n):
    for j in range(n):
        print(f"{i + j:2}", end=" ")
    print()

# Résultat:
#  1  2  3 
#  4  5  6 
#  7  8  9

# === Pattern 4: Table de multiplication ===
n = 5
for i in range(1, n + 1):
    for j in range(1, n + 1):
        print(f"{i * j:3}", end=" ")
    print()

# Résultat:
#   1   2   3   4   5 
#   2   4   6   8  10 
#   3   6   9  12  15 
#   4   8  12  16  20 
#   5  10  15  20  25


[OK] PATTERNS ARTISTIQUES

# === Pattern 1: Vague ===
def vague(largeur, hauteur):
    for i in range(hauteur):
        for j in range(largeur):
            if (i + j) % 4 == 0:
                print("~", end="")
            elif (i + j) % 4 == 1:
                print("^", end="")
            else:
                print(" ", end="")
        print()

vague(20, 5)
# ~   ~   ~   ~   ~   
#  ^   ^   ^   ^   ^  
#   ~   ~   ~   ~   ~ 
#    ^   ^   ^   ^   ^
#     ~   ~   ~   ~   

# === Pattern 2: Échiquier avec chiffres ===
n = 8
for i in range(n):
    for j in range(n):
        if (i + j) % 2 == 0:
            print(f"{(i * n + j + 1) % 10}", end="")
        else:
            print(".", end="")
    print()

# === Pattern 3: Spirale (simple) ===
def spirale_simple(n):
    for i in range(n):
        if i % 2 == 0:
            print("*" * n)
        else:
            print(" " * (n - 1) + "*")

spirale_simple(5)
# *****
#     *
# *****
#     *
# *****

# === Pattern 4: Cœur ===
def coeur(taille):
    # Partie supérieure
    for i in range(taille // 2, taille, 2):
        # Première moitié
        print(" " * (taille - i), end="")
        print("*" * i, end="")
        print(" " * (taille - i), end="")
        # Deuxième moitié
        print("*" * i)
    
    # Partie inférieure (pyramide inversée)
    for i in range(taille * 2, 0, -1):
        print(" " * (taille * 2 - i), end="")
        print("*" * i)

# coeur(3) pour un petit cœur


[OK] PATTERNS AVEC COULEURS (ANSI)

# Codes couleur ANSI
ROUGE = '\033[91m'
VERT = '\033[92m'
JAUNE = '\033[93m'
BLEU = '\033[94m'
MAGENTA = '\033[95m'
CYAN = '\033[96m'
RESET = '\033[0m'

# === Pattern 1: Triangle multicolore ===
couleurs = [ROUGE, JAUNE, VERT, CYAN, BLEU, MAGENTA]
n = 6
for i in range(n):
    print(" " * (n - i - 1) + couleurs[i] + "*" * (2 * i + 1) + RESET)

# === Pattern 2: Arc-en-ciel ===
def arc_en_ciel(largeur):
    couleurs = [ROUGE, JAUNE, VERT, CYAN, BLEU, MAGENTA]
    for i, couleur in enumerate(couleurs):
        print(couleur + "█" * largeur + RESET)

arc_en_ciel(20)

# === Pattern 3: Damier coloré ===
n = 8
for i in range(n):
    for j in range(n):
        if (i + j) % 2 == 0:
            print(ROUGE + "█" + RESET, end="")
        else:
            print(BLEU + "█" + RESET, end="")
    print()


[OK] PATTERNS ANIMÉS (AVEC TIME)

import time
import os

# === Animation 1: Triangle qui grandit ===
def triangle_anime(hauteur_max):
    for h in range(1, hauteur_max + 1):
        os.system('clear' if os.name == 'posix' else 'cls')
        for i in range(h):
            print(" " * (hauteur_max - i - 1) + "*" * (2 * i + 1))
        time.sleep(0.3)

# triangle_anime(10)

# === Animation 2: Chargement ===
def barre_chargement(largeur=20):
    for i in range(largeur + 1):
        barre = "█" * i + "░" * (largeur - i)
        pourcentage = int((i / largeur) * 100)
        print(f"\r[{barre}] {pourcentage}%", end="")
        time.sleep(0.1)
    print()

# barre_chargement()

# === Animation 3: Vague animée ===
def vague_animee(largeur=30, iterations=20):
    for frame in range(iterations):
        ligne = ""
        for i in range(largeur):
            position = (i + frame) % 6
            if position < 2:
                ligne += "~"
            elif position < 4:
                ligne += "^"
            else:
                ligne += " "
        print(f"\r{ligne}", end="")
        time.sleep(0.1)
    print()

# vague_animee()


[OK] PATTERNS AVEC TKINTER (GUI)

# Pour créer des patterns graphiques
try:
    import tkinter as tk
    
    def dessiner_pattern_gui():
        fenetre = tk.Tk()
        fenetre.title("Pattern Graphique")
        
        canvas = tk.Canvas(fenetre, width=400, height=400, bg="white")
        canvas.pack()
        
        # Grille de carrés
        taille_case = 40
        for i in range(10):
            for j in range(10):
                if (i + j) % 2 == 0:
                    couleur = "black"
                else:
                    couleur = "white"
                
                x1 = j * taille_case
                y1 = i * taille_case
                x2 = x1 + taille_case
                y2 = y1 + taille_case
                
                canvas.create_rectangle(x1, y1, x2, y2, fill=couleur)
        
        fenetre.mainloop()
    
    # dessiner_pattern_gui()

except ImportError:
    print("Tkinter n'est pas disponible")


[OK] BONNES PRATIQUES

# [OK] FAIRE:

# 1. Utiliser des noms de variables clairs
hauteur = 5
symbole = "*"
for ligne in range(hauteur):
    print(symbole * (ligne + 1))

# 2. Commenter la logique complexe
n = 5
for i in range(n):
    # Calculer le nombre d'espaces avant les étoiles
    espaces = n - i - 1
    # Calculer le nombre d'étoiles (formule: 2*i + 1)
    etoiles = 2 * i + 1
    print(" " * espaces + "*" * etoiles)

# 3. Créer des fonctions réutilisables
def pattern(type_p, taille, symbole="*"):
    """Génère un pattern selon le type choisi"""
    if type_p == "carre":
        for i in range(taille):
            print(symbole * taille)
    elif type_p == "triangle":
        for i in range(1, taille + 1):
            print(symbole * i)

# 4. Valider les entrées utilisateur
def pattern_securise():
    try:
        taille = int(input("Taille (1-20): "))
        if 1 <= taille <= 20:
            for i in range(1, taille + 1):
                print("*" * i)
        else:
            print("Erreur: taille invalide")
    except ValueError:
        print("Erreur: entrez un nombre")

# [X] ÉVITER:

# 1. Noms de variables non descriptifs
n = 5
for x in range(n):
    for y in range(x):  # Confus!
        print("*", end="")

# 2. Logique trop complexe sans commentaires
for i in range(n):
    print(" " * (n - i - 1) + "*" * (2 * i + 1))  # Quoi?

# 3. Code dupliqué
# Mauvais
for i in range(5):
    print("*" * (i + 1))
for i in range(5):
    print("*" * (i + 1))

# Bon
def triangle(h):
    for i in range(h):
        print("*" * (i + 1))
triangle(5)
triangle(5)


[OK] FORMULES IMPORTANTES

# === Pyramide centrée ===
# Ligne i:
#   - Espaces avant: (n - i - 1)
#   - Étoiles: (2 * i + 1)
#   - Espaces après: (n - i - 1)

# === Losange ===
# Moitié supérieure: comme pyramide
# Moitié inférieure: pyramide inversée (sans dernière ligne)

# === Triangle rectangle ===
# Ligne i: i caractères (ou i+1 selon l'indice de départ)

# === Carré vide ===
# Bordure si: i == 0 OU i == n-1 OU j == 0 OU j == n-1

# === Diagonale principale ===
# Condition: i == j

# === Diagonale secondaire ===
# Condition: i + j == n - 1

# === Damier ===
# Condition: (i + j) % 2 == 0


[OK] RESSOURCES ET APPRENTISSAGE

# Progression recommandée:
# 1. Maîtriser les boucles for simples
# 2. Comprendre les boucles imbriquées
# 3. Pratiquer carré et rectangle
# 4. Passer aux triangles simples
# 5. Aborder les pyramides centrées
# 6. Expérimenter avec les patterns vides
# 7. Créer des patterns complexes (losange, sablier)
# 8. Innover avec ses propres patterns

# Concepts clés à maîtriser:
# - range() et ses paramètres
# - Boucles imbriquées (nested loops)
# - print() avec end=""
# - Multiplication de chaînes (* opérateur)
# - Conditions dans les boucles
# - Calculs mathématiques (espaces, étoiles)

# Sites pour pratiquer:
# - HackerRank (Pattern problems)
# - LeetCode (Matrix problems)
# - CodeWars (ASCII art challenges)
# - GeeksforGeeks (Pattern programs)

# Exercices progressifs:
# Niveau 1: Lignes et carrés
# Niveau 2: Triangles simples
# Niveau 3: Pyramides et losanges
# Niveau 4: Patterns créatifs
# Niveau 5: Patterns animés et interactifs


[OK] CHALLENGES FINAUX

# Challenge 1: Créer votre propre pattern unique
# Challenge 2: Pattern qui accepte n'importe quelle taille
# Challenge 3: Pattern avec animations
# Challenge 4: Pattern interactif (menu complet)
# Challenge 5: Pattern avec couleurs ANSI
# Challenge 6: Générateur de patterns aléatoires
# Challenge 7: Pattern qui dessine votre initiale
# Challenge 8: Pattern fractal (récursif)
# Challenge 9: Pattern 3D (illusion d'optique)
# Challenge 10: Jeu basé sur des patterns

# Bon apprentissage! [RAPIDE]