CoddyRun
Blog

Articles & Actualités

Les publications CoddyRun : nouveautés du logiciel, astuces de pseudo-code, retours d'expérience et actualités de l'environnement pédagogique.

74 publications

Construire et Animer le Triangle de Pascal
Article

Construire et Animer le Triangle de Pascal

Analyse d’un Programme Visuel et Algorithmique

Lire l'articleReplier l'article

Le programme présenté réalise une tâche aussi élégante que pédagogique : générer le triangle de Pascal, puis l’animer ligne par ligne en révélant progressivement sa structure mathématique… et même sa dimension fractale.

Ce mélange d’algorithmique, de mathématiques et de rendu graphique en fait un excellent exemple de programmation créative.

Génération du triangle de Pascal

Le triangle de Pascal est une structure mathématique où chaque nombre est la somme des deux nombres situés au-dessus de lui.
Le programme commence par définir :

  • nbLignes = 9 : le nombre de lignes à générer

triangle : un tableau de tableaux, chaque sous-tableau représentant une ligne

Construction ligne par ligne

Pour chaque ligne ligneIdx, le programme crée un tableau nouvelleLigne.
Ensuite, pour chaque colonne col :

Si col = 0 ou col = ligneIdx : bord du triangle, valeur = 1

Sinon : valeur = somme des deux valeurs de la ligne précédente :

gauche = triangle[ligneIdx - 1][col - 1]
droite = triangle[ligneIdx - 1][col]
nouvelleLigne ajoute gauche + droite

Chaque ligne est ensuite ajoutée au tableau global triangle.

Résultat : un triangle de Pascal complet, stocké en mémoire.

Préparation du rendu graphique

Le programme prépare une animation en définissant :

  • une toile de 500 × 380 px
  • un fond en dégradé sombre
  • un espacement horizontal (pasX = 50) et vertical (pasY = 38)
  • une taille de texte (tailleTexte = 12)

Ces paramètres permettent de placer chaque nombre dans un cercle, de façon harmonieuse et centrée.

Animation : révéler le triangle progressivement

L’animation se déroule en plusieurs étapes.
Pour chaque étape etape :

  • Une nouvelle image est créée.
  • On dessine toutes les lignes de 0 à etape - 1.
  • Chaque valeur est représentée par un cercle coloré.

Code couleur intelligent Le programme met en évidence une propriété fascinante du triangle de Pascal :

  • Si la valeur est paire : couleur #415a77
  • Si la valeur est impair : couleur #e0aaff

Cette simple règle révèle la fractale de Sierpinski, cachée dans le triangle de Pascal.

  • La dernière ligne révélée est mise en avant avec une couleur spéciale : #ffd166.
  • Centrage du texte
  • Pour afficher chaque nombre au centre du cercle, le programme calcule :

# la moitié de la largeur du texte (demiLargeur)
# la moitié de sa hauteur (demiHauteur)

  • Puis il ajuste la position du label.

Conclusion

Ce programme est un excellent exemple de programmation visuelle appliquée à une structure mathématique classique.
Il combine :

  • algorithmique (construction du triangle)
  • mathématiques (propriétés combinatoires)
  • graphisme (placement, couleurs, animation)
  • esthétique (dégradé, mise en avant, rythme)

En révélant le triangle ligne par ligne, il permet de comprendre sa logique interne tout en offrant une animation agréable et instructive.

La mise en évidence des valeurs paires et impaires ajoute une dimension fractale qui enrichit encore la démonstration.

Programme :

graph est un tableau

// Nombre total de lignes du triangle
nbLignes est un nombre vaut 9

// Le triangle : un tableau de tableaux (chaque ligne = un tableau)
triangle est un tableau

// --- Construction ligne par ligne ---
ligneIdx est un nombre
pour ligneIdx de 0 a nbLignes - 1
    // Nouvelle ligne
    nouvelleLigne est un tableau

    col est un nombre
    pour col de 0 a ligneIdx
        si col = 0 ou col = ligneIdx alors
            // Les bords valent toujours 1
            nouvelleLigne ajoute 1
        sinon
            // Somme des deux nombres de la ligne precedente
            gauche est un nombre
            gauche vaut triangle[ligneIdx - 1][col - 1]
            droite est un nombre
            droite vaut triangle[ligneIdx - 1][col]
            nouvelleLigne ajoute gauche + droite
        fin si
    fin pour

    triangle ajoute nouvelleLigne
fin pour

// --- Rendu anime : on revele une ligne de plus a chaque etape ---
largeurToile est un nombre vaut 500
hauteurToile est un nombre vaut 380

// Espacement horizontal entre deux cases voisines
pasX est un nombre vaut 50
// Espacement vertical entre deux lignes
pasY est un nombre vaut 38

// Taille du texte des nombres
tailleTexte est un nombre vaut 12

etape est un nombre
pour etape de 1 a nbLignes
    img est une toile
    dimension(img, largeurToile, hauteurToile)
    degrade(img, [#0d1b2a, #1b263b])

    // On dessine toutes les lignes deja revelees (de 0 a etape-1)
    lig est un nombre
    pour lig de 0 a etape - 1
        // Centre horizontal : la ligne "lig" a (lig+1) cases
        departX est un nombre
        departX vaut largeurToile / 2 - lig * pasX / 2

        posY est un nombre
        posY vaut 30 + lig * pasY

        c est un nombre
        pour c de 0 a lig
            cx est un nombre
            cx vaut departX + c * pasX
            cy est un nombre
            cy vaut posY

            valeur est un nombre
            valeur vaut triangle[lig][c]

            // Couleur selon la parite (revele la fractale de Sierpinski)
            teinte est un texte
            si valeur mod 2 = 0 alors
                teinte vaut #415a77
            sinon
                teinte vaut #e0aaff
            fin si

            // Mise en avant de la derniere ligne apparue
            si lig = etape - 1 alors
                teinte vaut #ffd166
            fin si

            cercle(img, cx, cy, 16, teinte)

            // Centrage du nombre : on retire la moitie de sa largeur reelle
            // et la moitie de sa hauteur pour le placer au centre du cercle
            texteVal est un texte
            texteVal vaut convertir_texte(valeur)
            demiLargeur est un nombre
            demiLargeur vaut label_largeur(texteVal, tailleTexte) / 2
            demiHauteur est un nombre
            demiHauteur vaut label_hauteur(tailleTexte) / 2

            label(img, cx - demiLargeur, cy + demiHauteur - 3, texteVal, #0d1b2a, tailleTexte)
        fin pour
    fin pour

    graph ajoute img
fin pour

// Pause sur le triangle complet
pause est un nombre
pour pause de 0 a 14
    graph ajoute graph[longueur(graph) - 1]
fin pour

animation(graph, 500, 0)
Pas encore noté
Connect Circuit : Anatomie d’un jeu de réflexion basé sur la rotation de tuiles
Article

Connect Circuit

Anatomie d’un jeu de réflexion basé sur la rotation de tuiles

Lire l'articleReplier l'article

Le programme présenté met en œuvre un jeu de réflexion élégant : Connect Circuit, un puzzle où le joueur doit faire pivoter des tuiles pour former un circuit électrique fermé.

Chaque tuile représente un morceau de câble, et l’objectif est de relier toutes les pièces à une source d’énergie centrale.

Ce jeu repose sur une combinaison de génération procédurale, décodage binaire, propagation logique, et interface graphique dynamique.

Configuration générale et variables globales

Le jeu s’affiche dans une zone de :

  • 360 px de large
  • une zone d’en-tête de 40 px
  • une zone de pied de 44 px

La grille varie selon le niveau :

  • Petit : 4×4
  • Moyen : 6×6
  • Grand : 8×8

Chaque tuile est codée par un nombre représentant ses connexions :

  • 1 = Nord
  • 2 = Est
  • 4 = Sud
  • 8 = Ouest

Ce codage binaire permet de combiner les directions :
par exemple, une tuile en T vers le nord-est-sud vaut 1 + 2 + 4 = 7.

Le programme gère plusieurs tableaux :

  • map : structure du circuit
  • visite : utilisé pour la génération
  • alimente : indique quelles tuiles reçoivent le courant
  • historique et hist_sens : pour annuler les coups
  • pile : pour la génération en profondeur

Lecture des bits : décoder les tuiles

Quatre fonctions permettent de lire les directions d’une tuile :

  • bit_nord(v)
  • bit_est(v)
  • bit_sud(v)
  • bit_ouest(v)

Elles extraient les bits correspondants.
Ce système rend le code très compact : une tuile peut être manipulée comme un simple entier.

Rotation des tuiles

Deux fonctions gèrent les rotations :

  • tourner_droite(v)
  • tourner_gauche(v)

Elles réorganisent les bits pour simuler une rotation de 90°.
Par exemple, tourner à droite fait passer :

  • Nord ? Est
  • Est ? Sud
  • Sud ? Ouest
  • Ouest ? Nord

Ces transformations sont réalisées en recomposant les bits dans un nouvel ordre.

Vérification de la victoire : un circuit parfaitement fermé

La fonction verifier_victoire() inspecte chaque tuile :

  • si une tuile a un fil vers le nord, la tuile au-dessus doit avoir un fil vers le sud
  • si elle a un fil vers l’est, la tuile à droite doit avoir un fil vers l’ouest
  • etc.

Si une connexion débouche dans le vide ou sur une tuile incompatible, la victoire est impossible.

Cette vérification garantit que le circuit est totalement fermé, sans extrémité libre.

Dessin de la scène : interface et feedback visuel

La procédure dessiner_scene() construit l’affichage :

Fond et titre
Fond sombre bleu nuit

Titre rouge ou vert selon l’état (jeu / victoire)

Barre de progression
Elle indique la proportion de tuiles alimentées par le courant.

Grille de tuiles
Chaque tuile est dessinée avec :

  • un fond plus clair si elle est alimentée
  • des segments représentant les fils

une forme centrale selon le nombre de branches :

  • source d’énergie
  • extrémité
  • jonction

Les couleurs changent selon l’alimentation, donnant un feedback immédiat au joueur.

Barre de boutons
Quatre boutons :

  • Nouveau
  • Annuler
  • Sens de rotation
  • Taille de la grille

Génération du circuit : un labyrinthe électrique

Le circuit est généré par une fouille en profondeur (DFS) :

  • La source est placée au centre.
  • On explore les voisins non visités.
  • Chaque déplacement crée une connexion entre les tuiles.
  • On continue jusqu’à avoir visité toute la grille.

Le résultat est un circuit parfaitement connecté.

Brouillage
Ensuite, toutes les tuiles sont rotées aléatoirement.
Si par hasard le circuit reste correct, on recommence.
Cela garantit que le joueur doit réellement résoudre le puzzle.

Boucle de jeu : interaction et propagation du courant

À chaque clic :

  • la tuile est tournée dans le sens choisi
  • l’historique est mis à jour
  • la propagation du courant est recalculée

La propagation fonctionne comme un flood-fill :

  • on part de la source
  • on avance dans les directions compatibles
  • chaque tuile alimentée est ajoutée à une pile
  • on continue jusqu’à ne plus pouvoir avancer

Cela permet d’afficher en temps réel quelles tuiles sont correctement connectées.

Victoire : circuit complet

Lorsque verifier_victoire() retourne vrai :

  • toutes les tuiles sont marquées comme alimentées
  • la barre de progression se remplit
  • le titre devient vert
  • le joueur peut cliquer pour rejouer ou changer de taille

Conclusion

Ce programme est un excellent exemple de jeu de réflexion procédural, combinant :

  • codage binaire intelligent
  • génération de labyrinthe
  • propagation logique
  • interface graphique dynamique
  • gestion des interactions utilisateur

Le résultat est un puzzle fluide, lisible, et agréable à jouer, où chaque rotation de tuile rapproche le joueur de la satisfaction d’un circuit parfaitement fermé.

Programme :

@ Configuration et Variables Globales
LARGEUR est un nombre vaut 360
HAUT_ENTETE est un nombre vaut 40
HAUT_PIED est un nombre vaut 44

niveau est un nombre vaut 1 // 0 = Petit (4x4), 1 = Moyen (6x6), 2 = Grand (8x8)
COLS est un nombre vaut 6
LIGNES est un nombre vaut 6
pxtuile est un nombre vaut 60 // 360 / COLS : 90, 60 ou 45 selon le niveau

map est un tableau // valeur de chaque tuile : 1=Nord, 2=Est, 4=Sud, 8=Ouest
visite est un tableau // utilisé par la génération
alimente est un tableau // 1 si la tuile est reliée à la source
historique est un tableau // indices des tuiles tournées (pour Annuler)
hist_sens est un tableau // sens utilisé pour chaque coup
pile est un tableau

gagne est un booléen vaut faux
rejouer est un booléen vaut faux
continuer est un booléen vaut vrai
sens est un nombre vaut 1 // 1 = horaire, 0 = anti-horaire
source est un nombre vaut 0 // tuile "génératrice" du courant
nb_alim est un nombre vaut 0 // nombre de tuiles alimentées

maToile est une toile
dimension(maToile, LARGEUR, HAUT_ENTETE + LARGEUR + HAUT_PIED)

@ Fonctions de lecture des bits
// Évite de répéter partout les mêmes calculs de décodage
fonction bit_nord(v)
    retourne v mod 2
fin fonction

fonction bit_est(v)
    retourne arrondi_inferieur(v / 2) mod 2
fin fonction

fonction bit_sud(v)
    retourne arrondi_inferieur(v / 4) mod 2
fin fonction

fonction bit_ouest(v)
    retourne arrondi_inferieur(v / 8) mod 2
fin fonction

@ Fonctions Logiques
// Rotation de 90 degrés vers la droite : Nord -> Est -> Sud -> Ouest -> Nord
fonction tourner_droite(v)
    retourne bit_ouest(v) + bit_nord(v) * 2 + bit_est(v) * 4 + bit_sud(v) * 8
fin fonction

// Rotation de 90 degrés vers la gauche : Nord -> Ouest -> Sud -> Est -> Nord
fonction tourner_gauche(v)
    retourne bit_est(v) + bit_sud(v) * 2 + bit_ouest(v) * 4 + bit_nord(v) * 8
fin fonction

// Vérifie que le circuit est fermé : aucune extrémité dans le vide
fonction verifier_victoire()
    pour y de 0 à LIGNES - 1
        pour x de 0 à COLS - 1
            idx est un nombre
            idx vaut y * COLS + x
            val est un nombre
            val vaut map[idx]

            // Connexion Nord
            si bit_nord(val) = 1 alors
                si y = 0 alors
                    retourne faux
                fin si
                si bit_sud(map[idx - COLS]) = 0 alors
                    retourne faux
                fin si
            fin si

            // Connexion Est
            si bit_est(val) = 1 alors
                si x = COLS - 1 alors
                    retourne faux
                fin si
                si bit_ouest(map[idx + 1]) = 0 alors
                    retourne faux
                fin si
            fin si

            // Connexion Sud
            si bit_sud(val) = 1 alors
                si y = LIGNES - 1 alors
                    retourne faux
                fin si
                si bit_nord(map[idx + COLS]) = 0 alors
                    retourne faux
                fin si
            fin si

            // Connexion Ouest
            si bit_ouest(val) = 1 alors
                si x = 0 alors
                    retourne faux
                fin si
                si bit_est(map[idx - 1]) = 0 alors
                    retourne faux
                fin si
            fin si
        fin pour
    fin pour
    retourne vrai
fin fonction

@ Interface et Dessin
procédure dessiner_scene()
    // On efface la toile précédente avant de redessiner,
    // sinon les images s'empilent à chaque tour de boucle
    effacer(maToile)
    remplir(maToile, #0f0f1e)

    couleur_on est un texte
    couleur_on vaut #00d4ff
    couleur_off est un texte
    couleur_off vaut #35476b
    si gagne = vrai alors
        couleur_on vaut #4ade80
        couleur_off vaut #4ade80
    fin si

    // Titre
    si gagne = vrai alors
        label(maToile, 8, 17, "CIRCUIT COMPLET ! Cliquez pour rejouer", #4ade80, 12)
    sinon
        label(maToile, 8, 17, "Connect Circuit - pivotez les tuiles", #e94560, 12)
    fin si

    // Barre de progression : proportion de tuiles alimentées
    rectangle_arrondi(maToile, 8, 24, LARGEUR - 16, 8, 4, #1b1b2f)
    larg est un nombre
    larg vaut (LARGEUR - 16) * nb_alim / (COLS * LIGNES)
    si larg > 0 alors
        rectangle_arrondi(maToile, 8, 24, larg, 8, 4, couleur_on)
    fin si

    // Grille
    pour y de 0 à LIGNES - 1
        pour x de 0 à COLS - 1
            idx est un nombre
            idx vaut y * COLS + x
            val est un nombre
            val vaut map[idx]

            px est un nombre
            px vaut x * pxtuile
            py est un nombre
            py vaut y * pxtuile + HAUT_ENTETE

            // Fond de la tuile : plus clair si elle reçoit le courant
            fond est un texte
            fond vaut #1b1b2f
            si alimente[idx] = 1 alors
                fond vaut #232b4d
            fin si
            rectangle_arrondi(maToile, px + 2, py + 2, pxtuile - 4, pxtuile - 4, 5, fond)

            // Couleur du fil : vif si alimenté, terne sinon
            cfil est un texte
            cfil vaut couleur_off
            si alimente[idx] = 1 alors
                cfil vaut couleur_on
            fin si

            cx est un nombre
            cx vaut px + pxtuile / 2
            cy est un nombre
            cy vaut py + pxtuile / 2
            ep est un nombre
            ep vaut arrondi_inferieur(pxtuile / 9)

            si bit_nord(val) = 1 alors
                ligne(maToile, cx, cy, cx, py + 2, cfil, ep)
            fin si
            si bit_est(val) = 1 alors
                ligne(maToile, cx, cy, px + pxtuile - 2, cy, cfil, ep)
            fin si
            si bit_sud(val) = 1 alors
                ligne(maToile, cx, cy, cx, py + pxtuile - 2, cfil, ep)
            fin si
            si bit_ouest(val) = 1 alors
                ligne(maToile, cx, cy, px + 2, cy, cfil, ep)
            fin si

            // Nombre de branches de la tuile
            deg est un nombre
            deg vaut bit_nord(val) + bit_est(val) + bit_sud(val) + bit_ouest(val)

            si idx = source alors
                // La source d'énergie
                rectangle_arrondi(maToile, cx - pxtuile / 6, cy - pxtuile / 6, pxtuile / 3, pxtuile / 3, 5, #ffd166)
                cercle(maToile, cx, cy, ep, #0f0f1e)
            sinon si deg = 1 alors
                // Extrémité : dessinée comme une petite ampoule carrée
                rectangle_arrondi(maToile, cx - pxtuile / 8, cy - pxtuile / 8, pxtuile / 4, pxtuile / 4, 4, cfil)
                cercle(maToile, cx, cy, ep / 2, #0f0f1e)
            sinon si deg > 0 alors
                cercle(maToile, cx, cy, ep + 2, cfil)
                cercle(maToile, cx, cy, ep / 2, #0f0f1e)
            fin si
        fin pour
    fin pour

    // Barre de boutons
    by est un nombre
    by vaut HAUT_ENTETE + LARGEUR + 5
    pour b de 0 à 3
        bx est un nombre
        bx vaut 4 + b * 88
        rectangle_arrondi(maToile, bx, by, 84, 32, 6, #1b1b2f)
    fin pour

    label(maToile, 26, by + 21, "Nouveau", #e6e6e6, 11)
    label(maToile, 115, by + 21, "Annuler", #e6e6e6, 11)
    si sens = 1 alors
        label(maToile, 200, by + 21, "Sens : D", #e6e6e6, 11)
    sinon
        label(maToile, 200, by + 21, "Sens : G", #e6e6e6, 11)
    fin si
    si niveau = 0 alors
        label(maToile, 297, by + 21, "Petit", #e6e6e6, 11)
    sinon si niveau = 1 alors
        label(maToile, 293, by + 21, "Moyen", #e6e6e6, 11)
    sinon
        label(maToile, 293, by + 21, "Grand", #e6e6e6, 11)
    fin si

    affiche maToile
fin procédure

@ Programme Principal
tant que continuer = vrai

    @ Préparation d'une partie
    pxtuile vaut LARGEUR / COLS

    // Vide les tableaux de la partie précédente
    tant que longueur(map) > 0
        map supprime (longueur(map) - 1)
    fin tant que
    tant que longueur(visite) > 0
        visite supprime (longueur(visite) - 1)
    fin tant que
    tant que longueur(alimente) > 0
        alimente supprime (longueur(alimente) - 1)
    fin tant que
    tant que longueur(historique) > 0
        historique supprime (longueur(historique) - 1)
    fin tant que
    tant que longueur(hist_sens) > 0
        hist_sens supprime (longueur(hist_sens) - 1)
    fin tant que
    tant que longueur(pile) > 0
        pile supprime (longueur(pile) - 1)
    fin tant que

    pour i de 0 à LIGNES * COLS - 1
        map ajoute 0
        visite ajoute 0
        alimente ajoute 0
    fin pour

    // La source est placée au centre de la grille
    source vaut arrondi_inferieur(LIGNES / 2) * COLS + arrondi_inferieur(COLS / 2)

    @ Génération du circuit (fouille en profondeur)
    pile ajoute source
    visite[source] vaut 1

    tant que longueur(pile) > 0
        courant est un nombre
        courant vaut pile[longueur(pile) - 1]

        cx_gen est un nombre
        cx_gen vaut courant mod COLS
        cy_gen est un nombre
        cy_gen vaut arrondi_inferieur(courant / COLS)

        voisins est un tableau

        si cy_gen > 0 alors
            si visite[courant - COLS] = 0 alors
                voisins ajoute 0
            fin si
        fin si
        si cx_gen < COLS - 1 alors
            si visite[courant + 1] = 0 alors
                voisins ajoute 1
            fin si
        fin si
        si cy_gen < LIGNES - 1 alors
            si visite[courant + COLS] = 0 alors
                voisins ajoute 2
            fin si
        fin si
        si cx_gen > 0 alors
            si visite[courant - 1] = 0 alors
                voisins ajoute 3
            fin si
        fin si

        si longueur(voisins) = 0 alors
            pile supprime (longueur(pile) - 1)
        sinon
            r est un nombre
            r vaut hasard(longueur(voisins) - 1)
            choix est un nombre
            choix vaut voisins[r]

            n_idx est un nombre
            si choix = 0 alors
                n_idx vaut courant - COLS
                map[courant] vaut map[courant] + 1
                map[n_idx] vaut map[n_idx] + 4
            sinon si choix = 1 alors
                n_idx vaut courant + 1
                map[courant] vaut map[courant] + 2
                map[n_idx] vaut map[n_idx] + 8
            sinon si choix = 2 alors
                n_idx vaut courant + COLS
                map[courant] vaut map[courant] + 4
                map[n_idx] vaut map[n_idx] + 1
            sinon
                n_idx vaut courant - 1
                map[courant] vaut map[courant] + 8
                map[n_idx] vaut map[n_idx] + 2
            fin si

            visite[n_idx] vaut 1
            pile ajoute n_idx
        fin si
    fin tant que

    @ Brouillage
    // On rebrouille tant que le circuit tombe par hasard sur la solution
    gagne vaut vrai
    tant que gagne = vrai
        pour i de 0 à longueur(map) - 1
            rots est un nombre
            rots vaut hasard(3)
            pour r de 1 à rots
                map[i] vaut tourner_droite(map[i])
            fin pour
        fin pour
        gagne vaut verifier_victoire()
    fin tant que

    rejouer vaut faux

    @ Boucle de jeu
    tant que gagne = faux et rejouer = faux

        // --- Propagation du courant depuis la source ---
        pour i de 0 à longueur(alimente) - 1
            alimente[i] vaut 0
        fin pour
        alimente[source] vaut 1
        nb_alim vaut 1

        pile_p est un tableau
        pile_p ajoute source

        tant que longueur(pile_p) > 0
            c est un nombre
            c vaut pile_p[longueur(pile_p) - 1]
            pile_p supprime (longueur(pile_p) - 1)

            cxp est un nombre
            cxp vaut c mod COLS
            cyp est un nombre
            cyp vaut arrondi_inferieur(c / COLS)

            si cyp > 0 alors
                si bit_nord(map[c]) = 1 alors
                    vN est un nombre
                    vN vaut c - COLS
                    si alimente[vN] = 0 alors
                        si bit_sud(map[vN]) = 1 alors
                            alimente[vN] vaut 1
                            nb_alim vaut nb_alim + 1
                            pile_p ajoute vN
                        fin si
                    fin si
                fin si
            fin si

            si cxp < COLS - 1 alors
                si bit_est(map[c]) = 1 alors
                    vE est un nombre
                    vE vaut c + 1
                    si alimente[vE] = 0 alors
                        si bit_ouest(map[vE]) = 1 alors
                            alimente[vE] vaut 1
                            nb_alim vaut nb_alim + 1
                            pile_p ajoute vE
                        fin si
                    fin si
                fin si
            fin si

            si cyp < LIGNES - 1 alors
                si bit_sud(map[c]) = 1 alors
                    vS est un nombre
                    vS vaut c + COLS
                    si alimente[vS] = 0 alors
                        si bit_nord(map[vS]) = 1 alors
                            alimente[vS] vaut 1
                            nb_alim vaut nb_alim + 1
                            pile_p ajoute vS
                        fin si
                    fin si
                fin si
            fin si

            si cxp > 0 alors
                si bit_ouest(map[c]) = 1 alors
                    vO est un nombre
                    vO vaut c - 1
                    si alimente[vO] = 0 alors
                        si bit_est(map[vO]) = 1 alors
                            alimente[vO] vaut 1
                            nb_alim vaut nb_alim + 1
                            pile_p ajoute vO
                        fin si
                    fin si
                fin si
            fin si
        fin tant que

        appelle dessiner_scene()

        clic_x est un nombre
        clic_y est un nombre
        cliquer maToile dans clic_x, clic_y

        // --- Clic dans la grille ---
        si clic_y >= HAUT_ENTETE alors
            si clic_y < HAUT_ENTETE + LARGEUR alors
                cx_clic est un nombre
                cx_clic vaut arrondi_inferieur(clic_x / pxtuile)
                cy_clic est un nombre
                cy_clic vaut arrondi_inferieur((clic_y - HAUT_ENTETE) / pxtuile)

                si cx_clic >= 0 et cx_clic < COLS et cy_clic >= 0 et cy_clic < LIGNES alors
                    idx_clic est un nombre
                    idx_clic vaut cy_clic * COLS + cx_clic
                    si sens = 1 alors
                        map[idx_clic] vaut tourner_droite(map[idx_clic])
                    sinon
                        map[idx_clic] vaut tourner_gauche(map[idx_clic])
                    fin si
                    historique ajoute idx_clic
                    hist_sens ajoute sens
                fin si
            fin si
        fin si

        // --- Clic sur la barre de boutons ---
        si clic_y >= HAUT_ENTETE + LARGEUR alors

            // Nouveau
            si clic_x >= 4 et clic_x < 88 alors
                rejouer vaut vrai
            fin si

            // Annuler le dernier coup
            si clic_x >= 92 et clic_x < 176 alors
                si longueur(historique) > 0 alors
                    tuile_annulee est un nombre
                    tuile_annulee vaut historique[longueur(historique) - 1]
                    sens_annule est un nombre
                    sens_annule vaut hist_sens[longueur(hist_sens) - 1]
                    historique supprime (longueur(historique) - 1)
                    hist_sens supprime (longueur(hist_sens) - 1)
                    si sens_annule = 1 alors
                        map[tuile_annulee] vaut tourner_gauche(map[tuile_annulee])
                    sinon
                        map[tuile_annulee] vaut tourner_droite(map[tuile_annulee])
                    fin si
                fin si
            fin si

            // Sens de rotation
            si clic_x >= 180 et clic_x < 264 alors
                si sens = 1 alors
                    sens vaut 0
                sinon
                    sens vaut 1
                fin si
            fin si

            // Taille de la grille
            si clic_x >= 268 et clic_x < 352 alors
                niveau vaut (niveau + 1) mod 3
                si niveau = 0 alors
                    COLS vaut 4
                sinon si niveau = 1 alors
                    COLS vaut 6
                sinon
                    COLS vaut 8
                fin si
                LIGNES vaut COLS
                rejouer vaut vrai
            fin si
        fin si

        si rejouer = faux alors
            gagne vaut verifier_victoire()
        fin si
    fin tant que

    @ Écran de victoire
    si gagne = vrai alors
        // Le circuit est fermé : tout est alimenté
        pour i de 0 à longueur(alimente) - 1
            alimente[i] vaut 1
        fin pour
        nb_alim vaut COLS * LIGNES

        appelle dessiner_scene()

        clic_fin_x est un nombre
        clic_fin_y est un nombre
        cliquer maToile dans clic_fin_x, clic_fin_y

        // On peut changer de taille directement depuis l'écran de victoire
        si clic_fin_y >= HAUT_ENTETE + LARGEUR alors
            si clic_fin_x >= 268 et clic_fin_x < 352 alors
                niveau vaut (niveau + 1) mod 3
                si niveau = 0 alors
                    COLS vaut 4
                sinon si niveau = 1 alors
                    COLS vaut 6
                sinon
                    COLS vaut 8
                fin si
                LIGNES vaut COLS
            fin si
        fin si
    fin si

fin tant que
Pas encore noté
Voxel 3D Engine
Actualité

Voxel 3D Engine v2

Grosse mise à jour du moteur Voxel 3D codé en EduCode !

Lire l'articleReplier l'article

Mon petit "Minecraft isométrique" a bien grandi, voici les nouveautés :

  • Rendu corrigé : les constructions s'affichent maintenant parfaitement sous tous les angles (ordre du peintre par diagonales)
  • Mode jour/nuit avec la touche N
  • Nouveau matériau : l'Or (6 matériaux au total !)
  • Sélection directe du matériau avec les touches 1 à 6
  • Un monde de départ pré-généré : tour de pierre, arbre, mur de briques, colonne de verre...
  • Escalade limitée : on ne monte que d'un bloc à la fois, il faut construire des escaliers !
  • Pose de blocs devant soi avec F : en alternant F et Z, on se construit un escalier vers le ciel
  • Compteur de blocs, marqueur lumineux sous le personnage, retour à l'origine...

Tout ça uniquement avec des boucles, des conditions, des tableaux et des dictionnaires. La preuve qu'on peut faire des choses sérieuses avec un langage d'apprentissage !

Apprendre à coder, c'est avant tout apprendre à penser ?

Pas encore noté
Nouvelle version du UNO programmé en EduCode
Actualité

Uno v2

Nouvelle version du UNO programmé en EduCode

Lire l'articleReplier l'article

Nouvelle version du UNO programmé en EduCode

À l’origine, c’était un petit jeu en menus texte. Aujourd’hui, c’est devenu une vraie mini-application jouable entièrement à la souris. Voici les nouveautés :

  • Contrôles intuitifs : clique sur une carte pour la jouer, sur la pioche pour piocher
  • Cartes interactives : les cartes jouables brillent d’un halo doré et se soulèvent automatiquement
  • Design modernisé : fond bleu nuit lumineux, cartes redessinées avec l’ovale UNO, ombres portées, pastilles de joueurs façon jeu en ligne
  • Choix de couleur simplifié : un panneau dédié pour les Jokers et +4
  • Badge "UNO !" : s’affiche dès qu’un joueur n’a plus qu’une carte
  • IA plus intelligente : elle garde ses Jokers pour plus tard et choisit la couleur qu’elle possède le plus
  • Règles fidèles au vrai UNO : les +2 et +4 font désormais passer le tour de la victime

Tout ça grâce aux procédures, fonctions, tableaux… et beaucoup de logique.

La programmation, c’est aussi ça : partir d’une idée simple et la faire grandir, étape après étape.

Pas encore noté
Réutiliser une toile pour optimiser le dessin
Astuce

Réutiliser une toile

Réutiliser une toile pour optimiser le dessin

Lire l'articleReplier l'article

Dans de nombreux langages ou moteurs graphiques, dessiner plusieurs fois un même élément peut devenir coûteux : chaque redessin implique de recalculer formes, couleurs, coordonnées…
Pour éviter cela, une technique simple et efficace consiste à dessiner une fois l’élément sur une toile dédiée, puis à réutiliser cette toile comme une image que l’on peut insérer, redimensionner ou déplacer à volonté.

Le programme ci-dessous illustre parfaitement ce principe en créant un badge une seule fois, puis en l’incrustant quatre fois dans une planche (frame) à des tailles différentes.

Création d’une toile source : le badge

La première partie du programme définit une toile appelée badge.
Cette toile est un carré de 100×100 pixels dans lequel on dessine :

  • un cercle jaune (#FEF08A),
  • un polygone brun (#B45309) représentant une forme décorative.
// --- La vignette source : un badge réutilisable ---
badge est une toile
dimension(badge, 100, 100)
cercle(badge, 50, 50, 45, #FEF08A)
polygone(badge, 50, 10, 61, 42, 89, 42, 66, 60, 75, 87, 50, 70, 25, 87, 34, 60, 11, 42, 39, 42, #B45309)

Ce badge est dessiné une seule fois.
Il devient ensuite un objet graphique autonome que l’on peut réutiliser comme une image.

Création de la planche de destination

On crée une seconde toile, frame, qui servira de planche d’affichage.

frame est une toile
dimension(frame, 400, 200)
remplir(frame, #1E2430)

Elle est remplie d’un fond sombre (#1E2430), ce qui mettra en valeur les badges.

Réutilisation du badge : incrustation multiple

La boucle suivante insère quatre fois la même toile badge dans frame, en modifiant sa taille et sa position à chaque itération :

x est un nombre vaut 20
t est un nombre vaut 30

pour i de 1 à 4
    svg(frame, x, 100 - t / 2, badge, t, t)
    x vaut x + t + 15
    t vaut t + 20
fin pour

Ce qui se passe :

  • svg(frame, x, y, badge, t, t) importe la toile badge comme une image SVG dans frame.
  • t augmente à chaque tour ? le badge est de plus en plus grand.
  • x avance ? les badges sont alignés horizontalement.

Aucun redessin du badge n’est effectué.
On réutilise simplement la toile déjà calculée, ce qui est plus rapide, plus propre, et plus modulaire.

Conclusion : un exemple parfait de réutilisation graphique

Ce programme démontre une bonne pratique essentielle en programmation graphique :

  • Dessiner une fois, réutiliser plusieurs fois.

En créant un badge dans une toile dédiée, puis en l’insérant comme une image dans une autre toile, on évite :

  • les recalculs inutiles,
  • la duplication de code,
  • les pertes de performance.

Programme :

// --- La vignette source : un badge réutilisable ---
badge est une toile
dimension(badge, 100, 100)
cercle(badge, 50, 50, 45, #FEF08A)
polygone(badge, 50, 10, 61, 42, 89, 42, 66, 60, 75, 87, 50, 70, 25, 87, 34, 60, 11, 42, 39, 42, #B45309)

// --- La planche de destination ---
frame est une toile
dimension(frame, 330, 200)
remplir(frame, #1E2430)

// on incruste la même toile 4 fois, à des tailles différentes
x est un nombre vaut 20
t est un nombre vaut 30

pour i de 1 à 4
    svg(frame, x, 100 - t / 2, badge, t, t)
    x vaut x + t + 15
    t vaut t + 20
fin pour

label(frame, 20, 30, "badge réutilisé 4x", #94A3B8, 14)
affiche frame
Pas encore noté
Nouveauté à venir dans la prochaine version d'EduCode v3.3
Nouveauté

« interagir » : le clavier et la souris, enfin réunis !

Nouveauté à venir dans la prochaine version d'EduCode v3.3

Lire l'articleReplier l'article

Vous connaissez déjà cliquer, qui met votre programme en pause jusqu'à un clic sur la toile. Vous connaissez aussi appuyer, qui attend qu'une touche du clavier soit pressée. Deux instructions bien pratiques… mais jusqu'ici, il fallait choisir : soit l'une, soit l'autre.

La prochaine version d'EduCode apporte la réponse à une demande récurrente : interagir, une instruction qui attend les deux à la fois. Un clic sur la toile ou une touche du clavier — le premier événement qui arrive relance le programme.

Pourquoi c'est utile ?

Imaginez un petit jeu : le joueur déplace son personnage avec les touches Z, Q, S, D, mais peut aussi cliquer sur la toile pour viser une cible ou appuyer sur un bouton dessiné à l'écran. Avant, impossible de gérer les deux en même temps : pendant que le programme attendait une touche, les clics étaient ignorés, et inversement.

Avec interagir, votre programme écoute tout en même temps, sur une seule ligne.

Comment ça marche ?

La syntaxe combine ce que vous connaissez déjà :

interagir maToile, ['z', 's', 'd', 'q'] dans action, x, y

On donne la toile à surveiller, la liste des touches acceptées, puis trois variables de type nombre qui reçoivent le résultat :

  • L'utilisateur a cliqué ? Alors action vaut 0, et x et y contiennent les coordonnées du clic sur la toile.
  • L'utilisateur a appuyé sur une touche ? Alors action contient le numéro de la touche dans la liste (1 pour la première, 2 pour la deuxième, etc.), et x et y valent -1.

Un simple si action = 0 permet ensuite de savoir ce qui s'est passé.

Un exemple complet

maToile est une toile
action est un nombre
x est un nombre
y est un nombre

interagir maToile, ['z', 's', 'd', 'q'] dans action, x, y

si action = 0 alors
    affiche "Clic en " + x + " ; " + y
sinon
    affiche "Touche numéro " + action
fin si

Six lignes de logique, et votre programme réagit aussi bien à la souris qu'au clavier. Placez le tout dans une boucle tant que, et vous avez la base d'un vrai jeu interactif.

Et mes programmes existants ?

Rien ne change ! cliquer et appuyer continuent de fonctionner exactement comme avant. interagir est un nouveau mot-clé qui vient s'ajouter à la famille, vos programmes actuels n'ont besoin d'aucune modification.

Seule petite conséquence : interagir devient un mot réservé du langage, il ne pourra donc plus servir de nom de variable ou de fonction.

Pas encore noté