Étiquette : image

Art

De l’art sur la NumWorks

Les calculatrices graphiques programmables sont bien plus que de simples outils pour les calculs. Elles ouvrent un monde de possibilités aux élèves, en permettant d’explorer les mathématiques d’une manière interactive et visuelle. Mais leur potentiel va au-delà des formules et des graphiques : elles peuvent être utilisées pour créer de l’art numérique, des animations, et même des jeux !

En programmant ces machines, les étudiants développent leur créativité tout en renforçant leurs compétences en logique et en résolution de problèmes. Ces calculatrices deviennent ainsi des alliées indispensables pour apprendre de manière ludique et innovante, et pour repousser les limites de l’imagination.

Depuis 2019, j’invite mes élèves à explorer leur potentiel créatif en réalisant des dessins uniques, soit avec l’application Grapheur, soit avec l’application Python de la calculatrice. Chaque année, leurs œuvres sont soumises à l’éditeur de la calculatrice, NumWorks, qui sélectionne la plus belle réalisation. L’auteur de cette création se voit offrir une coque au design original pour sa calculatrice. Si vous croisez un élève au lycée Louis Pasteur arborant une telle coque, il est fort probable qu’il soit lauréat de l’un de ces concours.

Certaines de ces réalisations sont également partagées sur les réseaux sociaux, notamment sur Instagram et X (anciennement Twitter). Une quinzaine de ces images ont même été sélectionnées et publiées, avec l’accord de leurs auteurs, dans un livre intitulé Découvrir la calculatrice graphique NumWorks édité en Français et en Anglais.

Il est vrai que se lancer dans la programmation sur une calculatrice graphique peut sembler déroutant au premier abord. Le défi de traduire des idées créatives en code peut déstabiliser, surtout pour ceux qui n’ont jamais exploré cet univers. Cependant, une fois les premières hésitations surmontées, les élèves découvrent rapidement le plaisir de voir leurs concepts prendre vie à l’écran. Ce processus, bien qu’exigeant, devient une source de satisfaction personnelle, les encourageant à se dépasser. En fin de compte, ils s’amusent tout en repoussant leurs propres limites, transformant un défi intimidant en une expérience enrichissante.

Tout à commencé en 2019 …

En 2019, après réflexion et concertation de l’équipe des enseignants de mathématiques, nous avons pris la décision collective de passer aux calculatrices NumWorks dans toutes nos classes. Pour familiariser les élèves avec cet outil, leur premier travail a été de réaliser un projet simple, destiné à leur faire découvrir les différentes fonctionnalités de la calculatrice. Sans attente particulière, j’ai été agréablement surpris par l’enthousiasme et la créativité dont ils ont fait preuve. Certaines productions, bien au-delà de ce que j’avais imaginé, ont révélé un potentiel insoupçonné chez les élèves, ouvrant la voie à des projets encore plus ambitieux par la suite.

Le titre du sujet était : Les mathématiques sont belles. Voici les 30 réalisations des élèves.

Certaines de ces images sont issues de scripts bien connus, adaptés et optimisés pour la NumWorks. Elles ont été réalisées à distance, en ligne, pendant le confinement de mars 2020. J’ai alors demandé à mes élèves de Terminale de constituer un jury pour évaluer ces créations, en insistant sur l’importance d’une bienveillance maximale dans leurs délibérations. Bien que les codes Python aient parfois été maladroits, ces erreurs faisaient partie intégrante du processus d’apprentissage. Se tromper, tâtonner, recommencer et s’améliorer sont autant d’étapes essentielles dans le développement de leurs compétences.

Quelques thread colorés publiés sur X (Twitter)

J’ai rejoint X (anciennement Twitter) durant le confinement, à l’origine pour passer le temps. Depuis, j’ai régulièrement partagé des threads mettant en avant les créations de mes élèves. En voici quelques exemples. (Un tableau à la fin de cet article propose davantage de liens.)

De l’art sur la NumWorks depuis 2020

Le tableau ci-dessous récapitule tous les fils de discussion publiés sur X (anciennement Twitter). Malheureusement, depuis le rachat de Twitter par Elon Musk, il n’est plus possible de consulter ces fils sans posséder un compte sur la plateforme. Cette restriction illustre bien les défis liés à l’utilisation d’outils fermés, qui peuvent rapidement se transformer en véritables obstacles à l’accès à l’information. 🥴

Création
(1er éd.)
Titre du travail à rendre
Classe cible
Thread X (Twitter)
2019
(2020)
Les mathématiques sont belles.
Seconde, mathématiques
2020 2021 2022 2023 2024 2025
2021
(2021)
Le Python et la Tortue.
1ère, spécialité NSI
2021 2022 2023 2024
2021
(2021)
Le python et les fractales
Tale, spécialité NSI
2021 2022 2023 2024
2022
(2022)
Les mathématiques sont belles ! ed. spéciale cercle
Tale, option Mathématiques Expertes
2022 2023 2024
2022
(2023)
Les mathématiques sont belles ! ed. spéciale polynôme
Tale, option Mathématiques Expertes
2023, 2024 2025
2022
(2024)
Un feu d’artifice en python
Tale, option Mathématiques Expertes
2024 2025
2023
(2023)
Le Python et la Tortue.
Seconde, SNT
2023 2024
2024
(2024)
Pixel Art en python
Tale, option Mathématiques Expertes
2024

Projets

Un Explorateur de fractales en Python

Plongez dans des mondes visuels éblouissants créés à partir de simples équations mathématiques, les fractales. Découvrez des fractales emblématiques telles que Julia et Mandelbrot, personnalisez votre expérience avec des palettes de couleurs. Embarquez pour un voyage captivant au cœur de l’art mathématique !

Les prémices du projet

Tout débute durant mon année de seconde. En math, j’ai utilisé le script Mandelbrot initialement présent dans la calculatrice Numworks. Je me suis amusé à analyser le script et grâce à ça et à mon père, je suis tombé dans les fractales. 

Ensuite, j’ai commencé la NSI en première et j’ai réalisé mon premier tutoriel sur ledit script. Et en fin d’année, j’ai modifié ce script afin de faire de plus belles couleurs.

Cette année, j’ai eu envie d’aller bien plus loin, l’idée vient du fait que pour  réaliser de belles images de fractale, j’utilise des explorateurs de fractales trouvables facilement sur internet pour trouver des coordonnées intéressantes. Mais l’expression le dit bien, on n’est jamais mieux servi que par soi-même, et j’ai donc choisi pour mon dernier projet de lycée de faire mon propre explorateur de fractale.

Le début du projet

Je suis parti du script Julia que j’avais fait durant mon projet de fin d’année de première, vous pourrez retrouver l’explication du script ici (lien vers le tuto Julia palette). Ainsi, nous partons de ce script : 

from kandinsky import*
def julia(N_iteration):
    palette = []
    xmax = 2
    xmin = -2
    ymax = 1.3875
    ymin = -1.387
    r = 255
    g = 255
    b = 255
    for j in range(0,128):
        b = 255 -2 * j
        palette.append([r,g,b])
    for j in range(128,256):
        r = 255 -2 * (j-128)
        g = 255 -2 * (j-128)
        palette.append([r,g,b])
    for x in range(320):
        for y in range(222):
            i = 0
            z = complex(xmin+(xmax-xmin)*x/320+(ymax-(ymax-ymin)*y/222)*1J)
            c = complex(0.36,0.36)
            while i < N_iteration and abs(z) < 2:
                i = i + 1
                z = z*z+c
            couleur = palette[int(255*i/N_iteration)]
            col = color(couleur[0],couleur[1],couleur[2])
            set_pixel(x,y,col)

La logique

I – optimisation

Pour faire mon explorateur, je veux générer une nouvelle fractale à chaque zoom, dézoome, déplacement, sur la droite, la gauche, le haut, le bas en modifiant les valeurs des coins de l’image. Mais si je suis cette logique, le script Julia pose déjà un problème. En effet, le script met des dizaines de secondes à fabriquer une seule image, vous conviendrez qu’un zoom en deux minutes, c’est un peu lent non ? Étrangement, un tutoriel a été écrit durant les vacances de Noël 2023 et bizarrement ce script présente exactement ce dont j’ai besoin ici.

Ainsi, j’ai un script qui me permet de générer des images en .png de fractale rapidement. Maintenant, j’ai remplacé la bibliothèque Kandinsky par Pillow et j’ai entièrement modifié les calculs de la fractale pour utiliser NumPy. Nous avons donc ce script :

from PIL import Image
import time
import tkinter as tk
from tkinter import PhotoImage
import keyboard
import numpy as np

global xmax, xmin, ymax, ymin, réso_x, réso_y
#valeurs de base
xmax = 2
xmin = -2
ymax = 1.3875
ymin = -1.387
réso_x = 30720 
réso_y = 21312

def julia_PIL(N_iteration = 100):
    palette = []
    r = 255
    g = 255
    b = 255
    for j in range(0, 128):
        b = 255 - 2 * j
        palette.append((r, g, b))
    for j in range(128, 256):
        r = 255 - 2 * (j - 128)
        g = 255 - 2 * (j - 128)
        palette.append((r, g, b))

    palette = np.array(palette, dtype=np.uint8)

    # Créer une grille de coordonnées complexes
    x = np.linspace(xmin, xmax, réso_x)
    y = np.linspace(ymin, ymax, réso_y)
    X, Y = np.meshgrid(x, y)
    Z = X + 1J * Y

    # Initialiser une matrice d'indices pour la palette
    indices_matrix = np.zeros((réso_y, réso_x), dtype=int)

    for i in range(N_iteration):
        print(i)
        # Mettre à jour les pixels
        mask = np.logical_and(i < N_iteration, np.abs(Z) < 2)
        indices_matrix[mask] = np.round(255 * i / N_iteration).astype(int)

        # Mettre à jour Z pour les pixels actifs
        Z[mask] = Z[mask] ** 2 + complex(0.36, 0.36)

    # Créer une image à partir de la matrice d'indices
    img_array = palette[indices_matrix]

    # Créer une image PIL à partir de l'array
    img = Image.fromarray(img_array, 'RGB')

    # Sauvegarder l'image
    img.save('fractales_images/test.png')

II – Affichage de l’image 

Pour afficher l’image, j’utilise la fonction Pillow mixé à Tkinter. Pillow génère une image en .png et l’enregistre dans un dossier et à chaque nouvelle génération la nouvelle image remplace l’ancienne. 

Tkinter lui génère une fenêtre de la même résolution que l’image générée par Pillow. Ensuite, il va chercher dans le dossier cette image faite par Pillow et l’affiche dans la fenêtre précédemment créée.

def fractal_builder(N_iteration = 100,nom_img='Explorer_image/Image.png'):
  """
  script de génération de la fractale
  """
    # Créer une image à partir de la matrice des indices
    img_array = palette[indices_matrix]

    # Créer une image à partir de l'array
    img = Image.fromarray(img_array, 'RGB')

    # Sauvegarder l'image
    img.save(nom_img)    

def afficher_image():
    img = PhotoImage(file=chemin_image)
    # stocke l'image dans la variable img
    canvas.create_image(0, 0, anchor=tk.NW, image=img)
    #affiche l'image

III – déplacement et zoom 

Afin de me déplacer et de zoomer, je vais utiliser la bibliothèque keyboard. Elle me permet de détecter quand j’appuie sur les touches de mon clavier. Je crée donc une fonction “explorer” qui s’occupe des déplacements et de leur logique. Je vais ainsi modifier les valeurs des coordonnées des coins de l’image que je prends de la fractale puis la générer avec ses nouvelles valeurs dans la fenêtre de Tkinter.

def explorer(action):
    global xmax, xmin, ymax, ymin,img,nbr_img    
    x = xmax - xmin
    y = ymax - ymin
    
    if keyboard.is_pressed('up'):# zoom avant
        xmax = xmax - (x/20)
        xmin = xmin - (x/20)*-1
        ymax = ymax - (y/20)
        ymin = ymin - (y/20)*-1
        fractal_builder()
        afficher_image()      
    elif keyboard.is_pressed('down'):# zoom arrière
        xmax = xmax + (x/20)
        xmin = xmin + (x/20)*-1
        ymax = ymax + (y/20)
        ymin = ymin + (y/20)*-1
        fractal_builder()
        afficher_image()
    elif keyboard.is_pressed('z'): # déplacement haut
        ymax = ymax - (y/40)
        ymin = ymin - (y/40)
        fractal_builder()
        afficher_image()
    elif keyboard.is_pressed('s'): # déplacement bas
        ymax = ymax + (y/40)
        ymin = ymin + (y/40)
        fractal_builder()
        afficher_image()
    elif keyboard.is_pressed('q'): # déplacement gauche
        xmax = xmax - (x/40)
        xmin = xmin - (x/40)
        fractal_builder()
        afficher_image()
    elif keyboard.is_pressed('d'): # déplacement droite
        xmax = xmax + (x/40)
        xmin = xmin + (x/40)
        fractal_builder()
        afficher_image()

IV – Menu, accueil

Au début du projet, ma volonté était qu’à la fin, j’ai réussi à faire un explorateur de fractaleS. Pouvoir explorer des fractales comme Julia et Mandelbrot que je maîtrise déjà et peut-être même d’autres.

Mais pour faire ça il faut que l’utilisateur puisse choisir dans un menu quelle fractale veut-il explorer et faire un menu, quand j’ai commencé le projet été pour moi le plus dur à réaliser.

Durant les vacances de février 2024 il nous a été demandé de faire un gestionnaire de base de données, d’ailleurs voici ce que j’ai réalisé (lien vers le projet). Mais quel rapport avec des fractales ? Eh bien le fait que ce projet utilise Tkinter pour réaliser un menu, exactement ce que cherche à faire et surtout, c’est simple ! (même si honnêtement, on ne dirait pas).

Parallèlement à ce projet de base de données, j’ai donc piqué des bouts de mon code pour le mettre dans mon explorateur et en seulement quelques minutes, j’ai un menu ! Il ne sert à rien et il est moche (et il le restera, je suis pas designer).

Faire une fenêtre avec Tkinter est plutôt simple à comprendre, on crée des variables qui vont être chaque élément de la page, texte, menu déroulant, champs pour écrire, etc. Pour les construire, Tkinter nous offre des fonctions comme Label() pour les textes, Entry() pour les champs d’écritures entre autres. Il ne nous reste qu’à trouver sur internet les paramètres à mettre à l’intérieur (comme text = “le texte que l’on veut afficher” pour un texte).

titre_acceuil = tk.Label(cadre_acceuil, text="Bienvenue sur cet explorateur de fractales", font=("Consolas", 20), bg="#C2C2C2", fg="black")
soustitre_acceuil = tk.Label(cadre_acceuil, text="Choisissez les paramètres de votre fractale", font=("Consolas", 15), bg="#C2C2C2", fg="black")
titre_acceuil.pack(pady=10)
soustitre_acceuil.place(x=130,y=50)

#création de la liste déroulante de choix des palettes
desc_liste_deroul_palette = tk.Label(cadre_acceuil, text="Choisissez la palette de couleur que vous voulez utiliser", font=("Consolas", 12), bg="#C2C2C2", fg="black")
desc_liste_deroul_palette.place(x=15,y=100)
liste_choix = ["Blanc - Jaune - Noir","Blanc - Noir"] # élément de la liste déroulante
variable_palette = tk.StringVar() # élément initial
variable_palette.set("Blanc - Noir")
liste_deroulante_palette = ttk.Combobox(cadre_acceuil, textvariable=variable_palette, values=liste_choix)
liste_deroulante_palette.place(x=15,y=125)
select = liste_deroulante_palette.get() # sélection de l'élément choisi dans la liste

#création de la liste déroulante de choix de la fractale
desc_liste_deroul_fractale = tk.Label(cadre_acceuil, text="Choisissez la fractale que vous voulez voir", font=("Consolas", 12), bg="#C2C2C2", fg="black")
desc_liste_deroul_fractale.place(x=15,y=145)
liste_choix = ["Julia","Mandelbrot"] # élément de la liste déroulante
variable_fractal = tk.StringVar() # élément intiaux
variable_fractal.set("Julia")
liste_deroulante_fractal = ttk.Combobox(cadre_acceuil, textvariable=variable_fractal, values=liste_choix)
liste_deroulante_fractal.place(x=15,y=170)

# création du champ de texte pour choisir la valeur de c
desc1_chmp_val_julia = tk.Label(cadre_acceuil, text="Si vous avez choisi de générer une fractale de Julia :", font=("Consolas", 12), bg="#C2C2C2", fg="black")
desc2_chmp_val_julia = tk.Label(cadre_acceuil, text="Choisissez la valeur de la constante c (où laisser par défaut), sachant c est un complexe", font=("Consolas", 10), bg="#C2C2C2", fg="black")
desc1_chmp_val_julia.place(x=15,y=195)
desc2_chmp_val_julia.place(x=25,y=220)
variable_r = tk.StringVar()
variable_r.set("0.36")
chmp_str_c_r_julia = tk.Entry(cadre_acceuil, textvariable=variable_r, font=("Helvetica",12), bg="#ffffff", fg="black", width=5)
chmp_str_c_r_julia.place(x=40,y=245)
variable_i = tk.StringVar()
variable_i.set("0.36")
chmp_str_c_i_julia = tk.Entry(cadre_acceuil, textvariable=variable_i, font=("Helvetica",12), bg="#ffffff", fg="black", width=5)
chmp_str_c_i_julia.place(x=100,y=245)

#création de la liste déroulante de choix de la résolution
desc_liste_deroul_resolution = tk.Label(cadre_acceuil, text="Choisissez la résolution de l'explorateurr", font=("Consolas", 12), bg="#C2C2C2", fg="black")
desc_liste_deroul_resolution.place(x=15,y=270)
liste_choix = ["320x222","480x333","720x555"]
variable_resolution = tk.StringVar()
variable_resolution.set("320x222")
liste_deroulante_resolution = ttk.Combobox(cadre_acceuil, textvariable=variable_resolution, values=liste_choix)
liste_deroulante_resolution.place(x=15,y=295)

V – Menu, faire devenir utile l’accueil

Maintenant qu’on a un superbe menu, rendons le utile. Pour cela, je crée des fonctions pour sélectionner la palette, la résolution, la fractale etc que j’affecte à une grande fonction start que j’affecte elle au bouton qui lance l’explorateur. Les fonctions de sélection récupèrent ce qui est écrit dans les champs de textes, menu déroulant pour pouvoir donner c’est paramètre à la fonction mère, start().

start (), elle initialise toutes les variables utiles à l’explorateur, supprime la fenêtre du menu, crée la fenêtre de l’explorateur, initialise l’explorateur avec la première image et lance les dernières fonctions nécessaires comme explorer().

def selection_reso(): # fonction de sélection de la résolution utilisée
    global réso_x,réso_y
    if liste_deroulante_resolution.get() == "320x222":
        réso_x = 320
        réso_y = 222
    if liste_deroulante_resolution.get() == "480x333":
        réso_x = 480
        réso_y = 333
    if liste_deroulante_resolution.get() == "720x555":
        réso_x = 720
        réso_y = 555

def selection_palette(): # fonction de sélection de la palette utilisée
    global palette
    palette = []
    select = liste_deroulante_palette.get()
    if select == "Blanc - Jaune - Noir":
        r, g, b = 255, 255, 255
        for j in range(0, 128):
            b = 255 - 2 * j
            palette.append((r, g, b))
        for j in range(128, 256):
            r = 255 - 2 * (j - 128)
            g = 255 - 2 * (j - 128)
            palette.append((r, g, b))
    else :
        palette = [[i,i,i] for i in range(255)]

def start(): # fonction de lancement de l'exploration
    global img,chemin_image,canvas,choix_fract,compl_r,compl_i, réso_x, réso_y
    selection_palette()
    # sélèction de la fractale
    if liste_deroulante_fractal.get() == "Julia":
        choix_fract = 0
    if liste_deroulante_fractal.get() == "Mandelbrot":
        choix_fract = 1
    selection_reso()
    compl_r,compl_i = chmp_str_c_r_julia.get(),chmp_str_c_i_julia.get() # sélection des valeurs de c
    
    fenetre.destroy() #supprime la fenêtre de l'accueil
    cadre_acceuil_explo = tk.Tk() # crée la fenètre de l'explorateur
    cadre_acceuil_explo.title("Affichage d'une Image")
    
    chemin_image = "Explorer_image/Image.png"
    # Charge l'image
    img = PhotoImage(file=chemin_image)
    # Crée un widget Canvas pour afficher l'image
    canvas = tk.Canvas(cadre_acceuil_explo, width=réso_x, height=réso_y)
    canvas.pack()
    # initialisation de la 1ère fractale
    fractal_builder()
    afficher_image()
    cadre_acceuil_explo.mainloop()

# création et placement du bouton de lancement de l'explorateur
bouton_start_explo = tk.Button(cadre_acceuil, text="Commencer l'exploration", font=("Consolas",15), bg="white", fg="black", command = start)
bouton_start_explo.place(x=230,y=495)

VI – Menu, prévisualisation

Actuellement, j’ai donc un menu qui me permet d’explorer 2 fractales différentes avec x palette différente et une infinité de fractales de Julia. Mais pendant que je joue avec mon script, je me rends compte que c’est lourd de devoir mettre les paramètres, lancer l’exploration, se rendre compte que ce n’est pas ce qu’on veut, donc on relance le script et ainsi de suite… Une idée me vient alors en tête : “pouvoir prévisualiser la fractale qu’on génère dans le menu, ce serait bien non ?” et voilà un nouvel objectif et pas des moindres, il me demande de mettre plusieurs variables en global pour y accéder, d’utiliser les fonctions de sélection, etc.

Pour réaliser cette fonction, on fait la même chose que la fonction start(). Mais cette fois, on ne supprime ni ne crée aucune fenêtre, on vient juste placer un canvas, l’image de la fractale que nous voulons prévisualiser au bon endroit avec les bons paramètres.

def previsu():
    global palette, choix_fract,compl_r,compl_i, réso_x, réso_y
    #sélèction des diffèrents paramètres
    réso_x, réso_y = 240,167
    selection_palette()
    if liste_deroulante_fractal.get() == "Julia":
        choix_fract = 0
    if liste_deroulante_fractal.get() == "Mandelbrot":
        choix_fract = 1
    compl_r,compl_i = chmp_str_c_r_julia.get(),chmp_str_c_i_julia.get()
    
    fractal_builder() # génération d'une fractale avec ces paramètres
    prévi = PhotoImage(file="Explorer_image/Image.png") # récupération de l'image
    # création du cardre et placement de l'image dans le cadre
    label_image = tk.Label(cadre_acceuil, image=prévi)
    label_image.place(x=245,y=310)
    label_image.mainloop()

VII – Menu, tutoriel

La dernière barrière entre mon explorateur et l’utilisateur est ainsi ma logique. En effet, les touches que j’ai choisies pour mon explorateur ne sont sûrement pas les meilleures, donc je rajoute une nouvelle page à mon menu pour y écrire un petit guide des touches. Je profite de ça pour ajouter deux nouvelles fonctions. La première fonction récupère les coordonnées de la fractale qu’on voit pour les nerds. La seconde, plus complexe, prend des “screenshot” de ce qu’on voit dans l’explorateur. En réalité, elle génère une fractale avec les mêmes paramètres que celle que l’on voit dans l’explorateur, mais change son nom au moment de l’enregistrer.

#création du cadre de tutoriel dans la fenêtre de l'accueil
cadre_acceuil = tk.Frame(fenetre, bg="#C2C2C2",heigh = 555,width=720)
cadre_acceuil.pack_propagate(False) 
cadre_tuto = tk.Frame(fenetre, bg="#C2C2C2",heigh = 555,width=720)
cadre_tuto.pack_propagate(False) 
# création et placement du texte du tuto
titre_tuto = tk.Label(cadre_tuto, text="Guide des Touches", font=("Consolas", 20), bg="#C2C2C2", fg="black")
soustitre_tuto = tk.Label(cadre_tuto, text="Vous vous sentez un peu  perdu ?", font=("Consolas", 15), bg="#C2C2C2", fg="black")
titre_tuto.pack()
soustitre_tuto.pack(pady=10)
texte_tuto = tk.Label(cadre_tuto, text="z - aller vers le haut \ns - aller vers le bas \nq - aller à droite \nd - aller à gauche \n\nflèche du haut - zoom avant \nflèche du bas - zoom arrière \n\nm - renvoie les coordonnées de \n    où vous êtes dans la fractale \n\nc - sauvegarde un PNG de ce que \n    vous voyez dans le dossier Explorer_image \n", font=("Consolas", 13), bg="#C2C2C2", fg="black")
texte_tuto.pack()
fin = tk.Label(cadre_tuto, text="Amusez-vous !", font=("Consolas", 15), bg="#C2C2C2", fg="black")
fin.pack(pady=20)

#nouvelles fonctions ajoutées à l'explorateur
def explorer(action):
    global xmax, xmin, ymax, ymin,img,nbr_img
    x = xmax - xmin
    y = ymax - ymin
    """
    différentes fonctions de déplacements
    """
    elif keyboard.is_pressed('m'): # récupération de nos coordonnées (pour les nerds)
        print("xmax = ",xmax)
        print("xmin = ",xmin)
        print("ymax = ",ymax)
        print("ymin = ",ymin)
    elif keyboard.is_pressed('c'): # prend un screenshot de la fractale
        print("Image enregistrée !")
        nbr_img +=1
        fractal_builder(100,'Explorer_image/Image_saved'+str(nbr_img)+'.png')
        afficher_image()
        print(nbr_img)

Conclusion

En conclusion, ce projet ma permis d’utiliser la plupart de mes compétences. Il m’a suivi durant la moitié de mon année de terminale.

Galerie

Quelques exemples de fractale que vous pourrez à votre tour explorer :

Script complet

Voici le script final en .7z, il vous suffit de l’extraire et vous pourrez directement commencer à explorer !

vous pouvez également voir les futures mise à jour sur GitHub ici.

Art

La Citrouille et la Tortue

Pour notre premier projet en classe de 1ère NSI, nous nous sommes basées sur le thème d’halloween.
Ici vous trouverez nos démarches pour créer cette image de style pop. Notre image est composée de quatre parties comportant chacune un fond et une citrouille de couleur différente.

Vidéo de présentation du projet :

Le projet :

Ce projet consiste à créer de l’art génératif grâce à un script python qui doit principalement utiliser des fonctions. Pour le réaliser, nous avons utilisé le module turtle pour tracer l’image et la fonction randint du module random pour pouvoir transformer notre image (.py) en png. Le thème de l’image générée était libre, elle pouvait même être abstraite !

Le processus de création :

Durant ce projet, nous sommes passées par plusieurs étapes pour concevoir l’image et répondre aux attendus.

Nous avons tout d’abord dû trouver une idée de l’image que l’on voulait créer. Pour cela, nous nous sommes inspirées de l’artiste américain Andy Warhol et de ses oeuvres comme « Shot Marilyns » et nous avons transposé son style dans le thème d’Halloween.

Après avoir dessiné un croquis à la main, nous avons créé le script d’une citrouille puis nous l’avons transformé en plusieurs fonctions pour pouvoir la reproduire en quatre exemplaires. Nous avons fait de même pour les rectangles.

Contrairement aux citrouilles et aux rectangles, nous avons tout de suite codé les lettres en tant que fonctions ce qui nous a permis d’aller plus vite dans la conception de l’image.

Enfin, nous avons dû organiser notre script rigoureusement pour que la tortue trace les éléments dans le bon ordre pour un rendu propre et travaillé.

Le code expliqué étape par étape :

Pour concevoir cette image, nous avons agi étape par étape. Nous avons donc relevé les différentes parties du code qui ont permis de tracer l’image. (Nous ne montrerons pas la mise en place des modules et comment nous avons généré des images automatiquement. Pour cela, vous pouvez vous rendre sur cet article.)

Le fond :

Tout d’abord, nous avons divisé l’écran en quatre parties égales et rectangulaires. Nous avons défini une fonction rectangle(x,y,color). Pour obtenir nos quatre parties distinctes, il suffit de mettre les coordonnées ainsi qu’une couleur en argument pour tracer les rectangles au bon endroit.

# trace les rectangles
def rectangle(x, y, color):
  up()
  goto(x, y)
  down()
  pencolor(color)
  fillcolor(color)
  begin_fill()
  for i in range(2):
    forward(640)
    right(90)
    forward(360)
    right(90)
  end_fill()

Nous appelons donc la fonction avec des coordonnées et des couleurs différentes pour tracer nos quatre rectangles.

rectangle(-640, 360, "#A8608E")
rectangle(-640, 0, "#25AE80")
rectangle(0, 360, "#C9BB32")
rectangle(0, 0, "#E1770C")

Résultat :

L’écriture « HAPPY HALLOWEEN » :

Ensuite, nous avons créé des fonctions pour chaque lettre différente composant l’expression « HAPPY HALLOWEEN » soit une fonction pour les lettres h, a, p, y, l, o, w, e et n. La lettre « o » est spéciale car nous avons voulu la représenter par une citrouille pour rester dans le thème d’Halloween. Ici, nous vous montrerons les fonctions lettre_h(x,y), lettre_o(x,y) et lettre_e(x,y).

# trace la lettre h en majuscule
def lettre_h(x,y):
  pensize(3)
  color("black")
  up()
  goto(x,y)
  setheading(90)
  down()
  forward(50)
  backward(25)
  right(90)
  forward(25)
  right(90)
  forward(25)
  backward(50)


# la lettre o est représentée par une citrouille
def lettre_o(x,y,f):
  pensize(3)
  color("black")
  fillcolor(f)
  up()
  goto(x,y+25)

  a = x
  b = y
  for i in range(2):
    up()
    goto(x, y)
    down()
    begin_fill()
    circle(25)
    end_fill()
    x += 25 / (35 / 15)
    y -= 25 / 14

  a = x + 25 / 1.4
  for i in range(2):
    up()
    goto(a, b)
    down()
    begin_fill()
    circle(25)
    end_fill()
    a -= 25 / (35 / 15)
    b -= 25 / 14

  goto(a + 25 / 14, b)
  begin_fill()
  circle(25)
  end_fill()

  setheading(0)
  up()
  goto(a, b + 25 * 2 + 2)
  down()
  pencolor("black")
  left(350)
  for i in range(4):
    left(40)
    forward(25 / (35 / 15))
    goto(a, b + 25 * 2 + 2)


# trace la lettre e en majuscule
def lettre_e(x,y):
  pensize(3)
  color("black")
  up()
  goto(x,y)
  setheading(90)
  down()
  forward(50)
  right(90)
  forward(25)
  backward(25)
  left(90)
  backward(25)
  right(90)
  forward(15)
  backward(15)
  left(90)
  backward(25)
  right(90)
  forward(25)

Après avoir créé toutes ces fonctions, nous les appelons dans un ordre précis pour écrire « HAPPY HALLOWEEN » et nous utilisons des boucles for pour que l’expression soit répétée et forme un motif. Nous rajoutons également la fonction stamp() qui permet de laisser l’empreinte de la tortue à la fin de la lettre « N ».

h = 20
for i in range(4):
  lettre_h(50,h)
  lettre_a(80,h)
  lettre_p(110,h)
  lettre_p(140,h)
  lettre_y(170,h)
  lettre_h(230,h)
  lettre_a(260,h)
  lettre_l(290,h)
  lettre_l(320,h)
  lettre_o(370,h,"#C9BB32")
  lettre_w(460,h)
  lettre_e(510,h)
  lettre_e(540,h)
  lettre_n(570,h)
  stamp()
  h += 90


h = -340
for i in range(4):
  lettre_h(50,h)
  lettre_a(80,h)
  lettre_p(110,h)
  lettre_p(140,h)
  lettre_y(170,h)
  lettre_h(230,h)
  lettre_a(260,h)
  lettre_l(290,h)
  lettre_l(320,h)
  lettre_o(370,h,"#E1770C")
  lettre_w(460,h)
  lettre_e(510,h)
  lettre_e(540,h)
  lettre_n(570,h)
  stamp()
  h += 90


h = 20
for i in range(4):
  lettre_h(-600,h)
  lettre_a(-570,h)
  lettre_p(-540,h)
  lettre_p(-510,h)
  lettre_y(-480,h)
  lettre_h(-420,h)
  lettre_a(-390,h)
  lettre_l(-360,h)
  lettre_l(-330,h)
  lettre_o(-280,h,"#A8608E")
  lettre_w(-190,h)
  lettre_e(-140,h)
  lettre_e(-110,h)
  lettre_n(-80,h)
  stamp()
  h += 90


h = -340
for i in range(4):
  lettre_h(-600,h)
  lettre_a(-570,h)
  lettre_p(-540,h)
  lettre_p(-510,h)
  lettre_y(-480,h)
  lettre_h(-420,h)
  lettre_a(-390,h)
  lettre_l(-360,h)
  lettre_l(-330,h)
  lettre_o(-280,h,"#25AE80")
  lettre_w(-190,h)
  lettre_e(-140,h)
  lettre_e(-110,h)
  lettre_n(-80,h)
  stamp()
  h += 90
shape("turtle")
stamp()

Résultat :

Le corps de la citrouille :

Puis, nous avons défini la fonction corps_citrouille(x,y,pen,fi) pour dessiner le corps de la citrouille. Celle-ci prend en paramètre la couleur et les coordonnées du corps. Le corps est constitué de plusieurs cercles assemblés dans un ordre précis pour que le remplissage s’effectue correctement.

# trace le corps de la citrouille
def corps_citrouille(x,y,pen,fi):
  pencolor(pen)
  pensize(5)
  fillcolor(fi)
  a = x
  b = y
  for i in range(2):
    up()
    goto(x,y)
    down()
    begin_fill()
    circle(70)
    end_fill()
    x += 30
    y -= 5

  a = x + 50
  for i in range(2):
    up()
    goto(a,b)
    down()
    begin_fill()
    circle(70)
    end_fill()
    a -= 30
    b -= 5

  goto(a + 5,b)
  begin_fill()
  circle(70)
  end_fill()

Nous appelons cette fonction avec des coordonnées et des couleurs différentes pour créer nos quatre corps de citrouille.

corps_citrouille(-380,110,"#E1C40C","#E3E013")
corps_citrouille(280,110,"#FF4017","#FF5733")
corps_citrouille(280,-260,"#502D9B","#6445A6")
corps_citrouille(-380,-260,"#26b510","#7EEb1E")

Résultat:

La tige de la citrouille :

De plus, nous avons conçu la tige à l’aide d’une autre fonction qui prend en compte les coordonnées et les couleurs de la tige. Pour la concevoir, nous avons d’abord tracé deux traits partant d’un même point puis nous les avons reliés pour effectuer le remplissage.

#  trace la tige de la citrouille
def tige_citrouille(x,y,pn,fl):
  setheading(0)
  up()
  goto(x,y)
  down()
  pencolor(pn)
  fillcolor(fl)
  begin_fill()
  right(160)
  for i in range(2):
    left(110)
    forward(30)
  goto(x,y)
  end_fill()
  begin_fill()
  right(20)
  for i in range(35):
    forward(1)
    right(2)
  end_fill()

Nous appelons ensuite cette fonction tige_citrouille(x,y,pn,fl) avec différentes coordonnées et couleurs pour bien positionner nos quatre tiges de citrouille.

tige_citrouille(-350,260,"#515146","#7A7A65")
tige_citrouille(310,260,"#0E6F12","#1B801F")
tige_citrouille(310,-110,"#8C0F37","#AD2953")
tige_citrouille(-350,-110,"#909207","#C2BD34")

Résultat :

Le visage :

Enfin, nous avons paramétré une fonction afin de lui créer un visage qui a pour arguments ses coordonnées. Le visage est composé de deux yeux qui sont des triangles, d’un nez qui est un triangle plus petit et d’une bouche également composée de formes géométriques.

# trace le visage de la citrouille
def visage(x,y):
  setheading(0)
  pensize(1)
  up()
  goto(x,y)
  down()
  pencolor("#000000")
  fillcolor("#000000")
  begin_fill()

# trace les deux yeux  
  for i in range(2):
    up()
    goto(x,y)
    down()
    for i in range(3):
      forward(30)
      left(120)
    x += 70
  end_fill()

# trace le nez 
  up()
  goto(x - 100,y - 22)
  down()
  begin_fill()
  for i in range(3):
    forward(22)
    left(120)
  end_fill()

# trace la bouche
  up()
  goto(x - 120,y - 35)
  down()
  begin_fill()
  l = 10
  for i in range(2):
    forward(l)
    right(45)
    forward(12)
    left(90)
    forward(12)
    right(45)
    l = 12
  forward(15)
  for i in range(90):
    forward(0.5)
    right(2)
  for i in range(2):
    right(45)
    forward(12)
    left(90)
    forward(12)
    right(45)
    forward(12)
  right(45)
  forward(12)
  left(90)
  forward(12)
  right(45)
  for i in range(90):
    forward(0.5)
    right(2)
  end_fill()

Nous devons donc appeler cette fonction visage(x,y) avec des coordonnées différentes pour aligner le visage sur le corps de chaque citrouille.

visage(-378,193)
visage(282,193)
visage(282,-177)
visage(-378,-177)

Résultat :

Les difficultés rencontrées :

La première difficulté a été de trouver la distance entre les lettres pour former l’expression « HAPPY HALLOWEEN ». Au début, nous les avions espacées de 30 pixels puis nous nous sommes aperçues que certaines lettres se chevauchaient. Après de nombreuses tentatives, nous sommes arrivées au rendu recherché.

Une autre difficulté a été de tracer les cercles qui composent le corps de la citrouille dans le bon ordre pour que le remplissage s’effectue correctement. En ayant compris la logique du remplissage nous sommes finalement parvenues à trouver cet enchaînement.

Enfin, nous avons dû trouver les emplacements de tous les éléments qui composent la citrouille (le corps, la tige et le visage). Ce processus a été très long et a nécessité de nombreux essais mais nous y sommes arrivées !

Sources :

Pour écrire ce script, nous avons utilisé nos connaissances ainsi que le site python.org pour trouver de nouvelles commandes en python. Nous avons également regardé des projets de l’année dernière comme ceux qui sont dans la catégorie art.

Image finale :

Voici le rendu final de notre projet après avoir fait des tests, corrigé nos erreurs et pris du plaisir à coder !

Télécharger le script en .py :

Ne vous inquiétez pas, nous avons pensé à vous ! Vous pouvez télécharger le script ci-dessous pour vous amuser à le modifier ou tout simplement le montrer à vos amis !

Art

Sous les Rayons d’Or ; l’Arabie saoudite

L’art génératif est une fusion fascinante entre la créativité humaine et la puissance des algorithmes informatiques, nous vous invitons à plonger dans un univers où la machine devient artiste, créant des œuvres d’une beauté unique et imprévisible.

Notre Projet

Pour ce premier projet de NSI, nous avons décidé de représenter la ville de Riyad en python. Par conséquent, notre image rentre dans le thème de l’Architecture. Nous avons réalisé une ville assez moderne, avec des bâtiments de toutes formes et un soleil hors du commun, notre but étant de faire ressortir la ville luxueuse de Riyad, tout en apportant notre petite touche d’originalité. La vrais question étant comment nous sommes passé d’une simple idée à un résultat splendide ?

Les différentes étapes de la création de l’image

Pour être arrivé à notre résultat final, nous sommes passé par 4 étapes;

Tout d’abord voici le script python qui nous a permis d’obtenir un fond innovateur, les couleurs n’ont pas été choisi par hasard, en effet nous avons souhaité créer une ambiance qui évoque l’originalité sans oubliée le luxe notamment avec des arrondie et un dégradée de couleur reflétant l’étendue de la ville. Nous avons dans un premier temps définie la fonction disque pour dessiner un disque, rayon pour définir la taille des disques, x et y pour les coordonnées du centre et pour le dégradé de couleur nous avons fait appel a Background-color, enfin nous avons utilisé les fonctions arrondi_gauche et arrondi_droit pour dessiner des parties d’arcs.

def disque(rayon, x, y, couleur=(1, 1, 1)):
    penup()
    goto(x, y-rayon)
    pendown()
    pencolor(couleur)
    fillcolor(couleur)
    begin_fill()
    circle(rayon)
    end_fill()
    

x, y = (0,-250)
radius = (700)
color = ("#FA1D65")
disque(radius, x, y, color) 
t    
x, y = (0,-250)
radius = (600)
color = ("#F72367")
disque(radius, x, y, color)     

   
x, y = (0,-250)
radius = (500)
color = ("#F02E6B")
disque(radius, x, y, color)

x, y = (0,-250)
radius = (400)
color = ("#EA3970")
disque(radius, x, y, color)     

x, y = (0,-250)
radius = (300)
color = ("#E73F72")
disque(radius, x, y, color)

def arrondi_gauche():
    for i in range(120):
        left(1)
        forward(5/40)
        
def arrondi_droit():
    for i in range(100):
        right(1)
        forward(5/80)

Le fond est certes beau, mais nous n’avions toujours pas trouvée cette touche de beauté supplémentaire, c’est ce pourquoi nous avons rajouté des étoiles, nous avons utilisé un code python assez simple. Nous avons commencée par définir une nouvelle fonction étoile, puis nous avons placés 125 points grâce à la boucle for i in range ces points sont placés aléatoirement grâce à randint.

def etoile():
    pensize(1)
    pencolor("white")
    for i in range(125):
        penup()
        x,y = randint(-700,700), randint(-0,700)
        goto(x,y)
        pendown()
        circle(1)

Il est désormais temps de passer, au bâtiment, pour ce qui est des bâtiments nous avons voulus représenter des grattes ciel luxueux de différentes formes, pour ce faire nous avons créer des fonctions bat 1, bat 2 etc … nous avons ensuite définis leur largeur, longueur et hauteur jusqu’à que les bâtiments ressemble à la forme qui nous convenais et enfin nous les avons placés à des endroits différents.

def bat1(longueur,largeur, couleur=(1,1,1)):
    pendown()
    pencolor(couleur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur/1.5)
    left(90)
    forward(longueur/2)
 
def bat5(longueur, largeur, couleur=(1,1,1)):
    etage(longueur, largeur/5)
    etage(longueur/2 , largeur/5)
    etage(longueur/3 , largeur/5)
    left(80)
    forward(longueur/2)

def etage(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)

def etage_inverse(longueur, largeur, couleur=(1,1,1)):
    forward(largeur)
    left(270)
    forward(longueur)
    left(90)
def bat5_inverse(longueur, largeur, couleur=(1,1,1)):
    right(160)
    forward(longueur/2)
    left(80)
    etage_inverse(longueur/3, largeur/5)
    etage_inverse(longueur/2 , largeur/5)
    etage_inverse(longueur, largeur/5)

def bat3(longueur, largeur, couleur=(1,1,1)):
   forward(longueur/3)
   left(90)
   forward(longueur)
   right(90)
   forward(largeur)
   right(90)
   forward(longueur/4)
   left(90)
   forward(largeur)
   right(90)
   forward(longueur/2)
   
def bat4(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur/3)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    left(90)
    forward(longueur-30)
    right(90)
    forward(largeur+25)
    right(90)
    forward(longueur+20)
    
def bat2(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur/2)
    left(45)
    forward(longueur/5)
    right(225)
    forward(longueur/8)
    right(90)
    forward(largeur+8)
    right(90)
    forward(longueur+8)

def bat6(longueur, largeur, couleur=(1,1,1)):
    left(90)
    forward(largeur)
    left(90)
    forward(longueur)
    right(90)
    forward(largeur)
    left(90)
    forward(longueur/3)
    right(90)
    forward(largeur)
    right(90)
    forward(longueur-130)
    left(90)
    forward(largeur)
    right(90)
    forward(longueur-50)
    left(35)
    forward(largeur*2)
    right(35)
    forward(longueur-75)

penup()
fillcolor("#313131")
begin_fill()
goto(-630,-450)
goto(-630,-450)
bat1(60,30, couleur=("#313131"))
bat5(150,80 , couleur=("#313131"))
bat5_inverse(150,80 , couleur=("#313131"))
bat3(100,50, couleur=("#313131"))
bat4(100,40, couleur=("#313131"))
bat2(180,65, couleur=("#313131"))
bat6(165,35, couleur=("#313131"))
left(90)

right(90)
bat4(150,50, couleur=("#313131"))
left(90)
bat3(150,50, couleur=("#313131"))
pendown()
goto(630,-460)
goto(-630,-450)
end_fill()

Enfin, il manquait la structure la plus importe, le soleil pour, le soleil on a imaginé un soleil assez original, nous l’avons d’abord dessinée, puis nous l’avons ensuite codée en python, pour ce faire nous nous sommes aidés du concours NumWorks et nous avons utilisé une boucle avec un pas de 1 qui dessine le soleil avec les instructions de forme et de taille donnés.

from math import *
penup()
goto(0, 0)
pendown()

for r in range(20, 80, 1):
    penup()
    pensize(4 if r % 2 else 1)
    for a in range(361):
        d = r + 5 * cos(radians(12 * a))
        x = d * cos(radians(a))
        y = d * sin(radians(a))
        goto(x, y)
        pendown() 
        

Image final

Les problèmes rencontrés

Il faut savoir que cette image n’est pas aussi facilement réalisable qu’elle ne le paraît, en effet nous avons rencontrés énormément d’obstacle à la création de cette image, notamment lorsque les bâtiments on été créer les tailles on été difficilement ajustable, nous avons dus rajouter plusieurs paramètres pour ajuster la taille des bâtiments ce qui nous a pris plusieurs heure. Nous avons également rencontrés de nombreux code d’erreur heureusement que toute les ressources étais à notre disposition, au final il suffisait de lire.

Notre ressentis sur ce premier projet

Nous avons beaucoup aimé ce premier projet, nous avons pris du plaisir à réaliser le projet, c’est une belle expérience et un coup de coeur, j’ai énormément appris en python pendant ses vacances et je trouve que ce qui est magique c’est d’apprendre en prenant du plaisir.

Télécharger le .py

Art

L’engrenage du temps

Dans notre projet de NSI de Novembre 2023, nos enseignants nous ont demandé de créer un programme informatique qui génère une image , en se concentrant sur le concept d’art génératif.

Présentation du sujet:

Partant du tableau des 42 thèmes abordés en classe, notre attention s’est focalisée sur la pendule, symbole puissant du temps. À partir de là, l’idée centrale du projet a émergé : “L’engrenage du temps” visant à représenter à l’aide de turtle notre image du temps .

Sur la représentation que nous avons, on peut observer plusieurs composants tels qu’une pendule, un engrenage, un dégradé et un disque. Nous allons les examiner en détail au fil de la présentation.

Analyse du script:

Le fond : 

def degradé():
    turtle.colormode(255)
    turtle.speed(0)
    global compt
    global fr
    global fg
    global fb
    while compt != 350 :
        turtle.pendown()
        turtle.pencolor(fr, fg, fb)
        turtle.pensize(3)
        turtle.forward(510)
        turtle.penup()
        turtle.right(180)
        turtle.forward(510)
        turtle.right(90)
        turtle.forward(1)
        turtle.right(90)
        fr += 1
        fg += 1
        fb += 1
        compt += 1
        if compt > 200:
            fr -= 1
            fg -= 1
            fb -= 1           

Pour commencer, nous avons programmer le fond avec un dégradé allant du noir au gris.

Dans la fonction dégradé il y a une boucle qui se répète 350 fois dans laquelle la tortue dessine ligne après ligne le dégradé en indentant les variables r,g,b de 1 a chaque ligne sans jamais dépasser la valeur 200.

Engrenages:

def n_engrenage(trait):
    turtle.left(90)
    turtle.forward(trait * 2)
    turtle.right(45)
    turtle.pencolor(couleur)
    turtle.pensize(8)
    turtle.fillcolor(couleur)
    turtle.begin_fill() 
    for i in range(12):
        turtle.forward(trait)
        turtle.right(120)
        turtle.forward(trait)
        turtle.left(90)
    turtle.end_fill()

La fonction “n_engrenage” dessine l’ engrenage à l’aide du module turtle.

La boucle “for” fait répéter 12 fois une suite d’instructions qui dessinent l’engrenage puis la fonction “turtle.fillcolor” viens définir la couleur de remplissage de l’engrenage qui débute et se finit grâce aux fonctions  “turtle.begin_fill” et “turtle.end_fill”.

Pendule: 

def disque(rayon, x, y, couleur=(1, 1, 1)):
    penup()
    goto(x, y - rayon)
    pendown()
    pencolor(couleur)
    fillcolor(couleur)
    begin_fill()
    circle(rayon)
    end_fill()

x = 25  
y = 175
radius = 30
color = (255, 255, 0)  

disque(radius, x, y, color)

import turtle

pen = turtle
pen.penup()
pen.goto(65, 190)
pen.pendown()
pen.pencolor("black")
pen.goto(175, 350)

import turtle #fonction courbe

t = turtle

t.penup()
t.goto(90,173)
t.pendown()
t.right(50)
for i in range(55):
    t.forward(1)
    t.right(1)


import turtle #fonction courbe 2

t2 = turtle

t2.penup()
t2.goto(100,180)
t2.pendown()

t2.right(290)
for i in range(75):
    t2.forward(1)
    t2.right(1)


turtle.hideturtle()

Pour fabriquer la pendule, nous avons commencé avec un plan donné par nos professeurs de NSI. Il comportait plusieurs disques placés de façon aléatoire. Ensuite, nous l’avons simplifié en utilisant les instructions « begin_fill() » et « end_fill() » pour remplir les disques. Ensuite, nous avons ajouté une simple ligne en spécifiant un point de départ et un point d’arrivée. Enfin, nous avons inclus deux courbes pour donner l’impression que la pendule bougeait.

Les problèmes rencontrés:

Parmis les nombreux problèmes rencontrés il y avait que l’exécution de la fonction dégradé prenait très longtemps a finir de s’exécuter (env 1min), pour ne pas perdre temps à relancer tout le code a chaque modification on a trouvé la solution de mettre un “#” devant la ligne qui exécutait la fonction dégradé ce qui permettait de faire passer cette ligne pour un commentaire et de simplement enlever le  # quand on voulait exécuter le script complet.

L’image final:

Art

Le système solaire

Pour le projet que nous avons dû réalisé sur l’art génératif nous avons choisi le thème du système solaire de façon plus revisité.

La création du fond :

Le fond ici est un ensemble de cercle qui forme plusieurs dégrader de violés comme ci-dessous :

from turtle import *
import secrets

def disque(rayon, x, y, couleur=(1, 1, 1)):
  penup()
  goto(x, y-rayon)
  pendown()
  pencolor(color)
  circle(rayon)


#fond

list_color2=["#AC00D7", "#9B00C1", "#9A00C2", "#9800BF", "#8D00B0", "#8300A4", "#770095", "#690083", "#500064", "#400050", "#23002C", "#400050", "#500064",  "#690083", "#770095", "#8300A4", "#8D00B0", "#9800BF", "#9A00C2",  "#9B00C1", "#AC00D7",]

x = 0
y = -45
radius = 1100

color_index = 0

while radius >= 0:
    speed(400)
    color = list_color2[color_index] 
    fillcolor(color)
    begin_fill()
    disque(radius, x, y, color)
    end_fill()
    radius-=5
    color_index = (color_index + 1) % len(list_color2)</code>

Les axes de rotations des planètes :

Les axes ici en blanc représentantes le positionnement des astres dans le système solaire on les a codé en plusieurs étapes.

from turtle import *
import secrets

def disque(rayon, x, y, couleur=(1, 1, 1)):
  penup()
  goto(x, y-rayon)
  pendown()
  pencolor(color)
  circle(rayon)


#fond

list_color2=["#AC00D7", "#9B00C1", "#9A00C2", "#9800BF", "#8D00B0", "#8300A4", "#770095", "#690083", "#500064", "#400050", "#23002C", "#400050", "#500064",  "#690083", "#770095", "#8300A4", "#8D00B0", "#9800BF", "#9A00C2",  "#9B00C1", "#AC00D7",]

x = 0
y = -45
radius = 1100

color_index = 0

while radius >= 0:
    speed(400)
    color = list_color2[color_index] 
    fillcolor(color)
    begin_fill()
    disque(radius, x, y, color)
    end_fill()
    radius-=5
    color_index = (color_index + 1) % len(list_color2)


#cercle blanc

x, y = (0,-45)
radius = (410)
color = ("white")
disque(radius, x, y, color)   

x, y = (0,-45)
radius = (370)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (330)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (290)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (230)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (200)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (170)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (140)
color = ("white")
disque(radius, x, y, color) 

La créations du soleil :

le soleil est l’astre qui nous permet de nous réchauffer donc les couleurs chaudes et vive est ce qui allait le mieux avec le soleil.

from turtle import *
import secrets

def disque(rayon, x, y, couleur=(1, 1, 1)):
  penup()
  goto(x, y-rayon)
  pendown()
  pencolor(color)
  circle(rayon)


#fond

list_color2=["#AC00D7", "#9B00C1", "#9A00C2", "#9800BF", "#8D00B0", "#8300A4", "#770095", "#690083", "#500064", "#400050", "#23002C", "#400050", "#500064",  "#690083", "#770095", "#8300A4", "#8D00B0", "#9800BF", "#9A00C2",  "#9B00C1", "#AC00D7",]

x = 0
y = -45
radius = 1100

color_index = 0

while radius >= 0:
    speed(400)
    color = list_color2[color_index] 
    fillcolor(color)
    begin_fill()
    disque(radius, x, y, color)
    end_fill()
    radius-=5
    color_index = (color_index + 1) % len(list_color2)


#cercle blanc

x, y = (0,-45)
radius = (410)
color = ("white")
disque(radius, x, y, color)   

x, y = (0,-45)
radius = (370)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (330)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (290)
color = ("white")
disque(radius, x, y, color) 

x, y = (0,-45)
radius = (230)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (200)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (170)
color = ("white")
disque(radius, x, y, color)

x, y = (0,-45)
radius = (140)
color = ("white")
disque(radius, x, y, color) 

#soleil

list_color=["yellow", "orange", "red", "orange", "yellow", "orange", "red"]

x = 0
y = -45
radius = 100

color_index = 0

while radius > 0:

    color = list_color[color_index]
    fillcolor(color)
    begin_fill()
    disque(radius, x, y, color)
    end_fill()
    radius-=1
    color_index = (color_index + 1) % len(list_color)


def arrondi_gauche():
  for i in range(180):
      left(1)
      forward(7/45)

def arrondi_droit():
  for i in range(180):
      right(1)
      forward(7/100)

Les planètes :

Un système solaire sans nos planètes n’est pas un vrai système solaire nous avons reproduit différent astres sur nos axes.

Art

Musique : The neighbourood wiped out !

En tant qu’admiratrices de l’album « wiped out ! » du groupe The Neighbourood, notre premier projet en NSI prend une dimension passionnante puisqu’on a choisi de représenter la pochette de cet album qui nous tient particulièrement à coeur.

Le commencement

Pour commencer, nous avons réalisé le fond noir et le cercle blanc qui se situe au centre. Nous avons ensuite placé le texte avec la bonne police d’écriture et la bonne taille au-dessus du cercle blanc. Nous devions aussi reproduire une petite maison à l’envers tout en bas de l’image en commençant par la base puis la cheminée et enfin le toit.

Les vagues et le sol

Pour créer les vagues, nous avons utilisé deux boucles for. Une première boucle sert à dessiner les arcs de cercle qui forment une ligne de vagues, puis une deuxième boucle permet de déplacer la tortue vers le bas pour dessiner la ligne de vagues suivantes. Cette approche répétitive nous permet de créer un motif de vagues continus en descendant d’une ligne à l’autre.

pensize(10)
goto(-300,0)
color("black")
pendown()
setheading(-35)

for i in range(9):
    for j in range(11):
         circle(35, 70)
         circle(-35, 70)
    penup()
    goto(-300, -20 * (i+1))
    pendown()

Il nous fallait aussi un sol qu’on a obtenu grâce à de nombreux cercles pour pouvoir ensuite déplacer la maison.

Le palmier avec les roches

Pour le palmier, on a d’abord dessiné des arcs de cercle pour créer le tronc incliné du palmier puis on a dessiné chaque feuille en utilisant la commande circle() avec des angles spécifiques pour créer la forme des feuilles. Les pierres ont été créées en combinant des formes géométriques superposées les unes aux autres.

L’oiseau

Pour dessiner un l’oiseau, on a dû crée les ailes, le corps, la queue, le bec et la tête de l’oiseau en utilisant des boucles, des lignes et des cercles.

Notre petite touche personnelle

Pour finir, on a rajouté notre petite touche personnelle, un ciel étoilé. Nous avons défini une fonction étoile pour générer 30 étoiles à des emplacements aléatoires.

def etoile():
    
    for i in range(5):
        forward(0.5)



pensize(2)
pencolor("white")

for i in range(30):
    x = randint(-400, 400)
    y = randint(100, 300)
    penup()
    goto(x, y)
    pendown()
    etoile()

CONCLUSION

Ce projet nous a permis de réaliser qu’on peut faire de très belle chose juste en ayant les bases de la programmation. On a pris beaucoup de plaisir à voir notre image se construire au fur et à mesure du temps. Cela nous a ouverts de nouvelles perspectives pour des projets futurs et nous avons hâte d’en apprendre davantage pour réaliser des créations encore plus techniques et impressionnantes.

RENDU FINAL

télécharger le .py

Art

Paysage japonais

Un paysage où un monument de la culture japonaise se mélange avec un fond naturel est magnifique. Et bien que le Japon soit le pays du soleil, levant nous allons le mettre en valeur avec, cette fois-ci, la lune, à travers des montagnes et des torii. Ces derniers symbolisent un portail entre l’enceinte sacrée et l’environnement profane. C’est pour cette raison qu’il y en a à l’entrée de certains sanctuaires.

Organisation du script

Notre script sera expliqué par étape, de l’arrière plan au premier. La fonction goto sera beaucoup utilisée afin de faire des tracés contrôlés ainsi que pensize() pour la largeur du tracé du stylo, color() pour choisir la couleur du crayon, circle() pour faire un cercle et for i in range pour faire des boucles.

L’arrière-plan

from turtle import*    
pensize (42)    
color("#FFFFFF")

a = -40   
col = ["#FFFFFF","#9BF7F7","#41F9FF","#00CDFF","#008FFF","#0059FF","#003AFF", "#4D00FF","#33079A", "#000000"]    
nb_col = len(col)    
color("#FFFFFF")   
goto(0, 50)    
circle(40)

a = 0  

for i in range (0,10,1):
    goto(0, 40-a)
    color(col[i%nb_col])
    circle(40+a)
    a = a +30
    goto(0, 40-a)
    circle(40+a)
    a = a +30
    goto(0, 40-a)
    circle(40+a)
    a = a +40

Ici, nous montrons que notre script est importé de Turtle, ce module nous permettant de contrôler un crayon pour tracer diverses formes géométriques.

Le fond de notre code n’est pas centré mais c’est fait exprès. Nous avons donc mis la taille du crayon à 42 avec la fonction : pensize (42), ensuite a = -40 nous a servis à déplacer le centre du cercle de base, soit, dans notre cas de le décaler vers la haut. Puis nous avons listé les différentes couleurs utilisées dans tous ces cercles avec col = [ ]. Le goto(0, 50) nous emmènera ensuite aux coordonnées données (donc (0, 50)) puis tracera des cercles de différentes tailles et de différentes couleurs grâce à la fonction cercle circle(40) et à la boucle for i in range (0,10,1):.

Les premières montagnes

color("#42392C")
goto(0, -80)
goto(100, 90)
goto(150,80)
goto(230,150)
goto(270,250)
goto(300,150)
goto(500,20)
goto(580,30)
goto(630,10)
goto(640,-40)
goto(0,-80) 

goto(0, -40)
goto(100,50)
goto(120,40)
goto(200,100)
goto(320,250)
goto(500,30)
goto(580,-10)
goto(630,20)
goto(640,-80)
goto(0,-70) 

goto(0, -40)
goto(120,40)
goto(200,80)
goto(320,230)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-60)
goto(0,-50) 

goto(0, -40)
goto(120,33)
goto(200,60)
goto(320,210)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-40)
goto(0,-20) 

goto(0, -40)
goto(120,20)
goto(200,50)
goto(320,190)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-30)
goto(0,-10) 

goto(0, -40)
goto(120,00)
goto(200,20)
goto(320,170)
goto(500,00)
goto(580,00)
goto(630,000)
goto(640,-10)
goto(0,-00) 

goto(0, -40)
goto(120,00)
goto(200,10)
goto(320,160)
goto(580,00)
goto(630,000)
goto(640,-10)
goto(0,-00)  

goto(320,70)
goto(500,50)
goto(320,60)
goto(320,40)
goto(320,50)
goto(320,30) 

goto(0,-10)
goto(-200,50)
goto(-300,10)
goto(-430,160)
goto(-500,15)
goto(-600,250)
goto(-600,-10)

Nous comprenons ici que les goto sont et seront à l’honneur de ce script ! Ils sont simples à utiliser et donc à comprendre. La couleur des premières montagnes, elle, est encore une fois définie par color(« #42392C »).

Voici le résultat de tous ces goto ! Nous avons un début de montagne avec quelques imperfections mais pas d’inquiétudes ! Ce script fonctionne par plan donc comme un pochoir. Ici, les goto ont donc servis à diriger le stylo d’un point à un autre jusqu’à ce que nous ayons ce résultat

Encore des montagnes

color("#6F6556")
goto(0, 0)
goto(80,40)
goto(120,00)
goto(200,10)
goto(430,200)
goto(630,0)
goto(0,-00)

goto(0, 0)
goto(200,0)
goto(430,180)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(430,160)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(430,150)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,150)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,140)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,130)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,120)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,110)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,100)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,90)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,80)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,70)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,60)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,60)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,50)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,40)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,40)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,30)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,20)
goto(630,0)

goto(0, 0)
goto(200,0)
goto(400,10)
goto(630,0)

goto(0,0)
goto(0,-10)
goto(-200,30)
goto(-300,00)
goto(-400,150)
goto(-500,5)
goto(-600,200)
goto(-600,-10)
goto(0,0)

Ces montagnes sont faites de la même manière que les premières : le changement de couleur avec color(« #6F6556 ») et les goto ! Voyons maintenant le résultat en image…

Et voilà nos montagnes finies ! Mais il reste encore quelques étapes pour donner un sens à notre titre.

Le sol bleu

up()
goto(0,-400)
down()
col = ["#000000","#33079A","#4D00FF", "#003AFF", "#0059FF","#008FFF", "#00CDFF", "#41F9FF","#9BF7F7", "#FFFFFF","#9BF7F7","#41F9FF","#00CDFF","#008FFF","#0059FF","#003AFF","#4D00FF","#33079A","#000000"]
nb_col = len(col) 
recup = 0
k = -50
for i in range (0,50):
    color(col[i%nb_col])
    for i in range (0,3):
        k += 40
        goto(1000-k,-35)
        goto(1300-k,-500)

Comme pour l’arrière-plan, les couleurs sont définies grâce à col = [ ].

Avec l’image, nous pouvons plus facilement comprendre la présence de la boucle for i in range (0,50) qui nous a aidé à répéter tous les traits positionnés en diagonale pour nous éviter de les faire un à un avec des goto par exemple !

Les torii

pensize(42)
up()
goto(160,-220)
down()

color("#FF7000")
goto(160,100)
goto(-160,100)
goto(-160,-220)
goto(-160,100)
goto(-220,100)
goto(220,100)
goto(160,100)
goto(160,160)
goto(160,100)
goto(-160,100)
goto(-160,160)
goto(-220,160)
goto(220,160)

pensize(25)
up()
goto(80,-150)
down()

color("#E76E00")
goto(80,20)
goto(-80,20)
goto(-80,-150)
goto(-80,20)
goto(-120,20)
goto(120,20)
goto(80,20)
goto(80,60)
goto(80,20)
goto(-80,20)
goto(-80,60)
goto(-120,60)
goto(120,60)

pensize(12)
up()
goto(40,-120)
down()

color("#CB6100")
goto(40,-30)
goto(-40,-30)
goto(-40,-120)
goto(-40,-30)
goto(-60,-30)
goto(60,-30)
goto(40,-30)
goto(40,-10)
goto(40,-30)
goto(-40,-30)
goto(-40,-10)
goto(-60,-10)
goto(60,-10)

pensize(6)
up()
goto(20,-100)
down()

color("#A95100")
goto(20,-60)
goto(-20,-60)
goto(-20,-100)
goto(-20,-60)
goto(-30,-60)
goto(30,-60)
goto(20,-60)
goto(20,-50)
goto(20,-60)
goto(-20,-60)
goto(-20,-50)
goto(-30,-50)
goto(30,-50)

Voici le code de nos torii. A chaque nouveau pensize( ), il y en a un nouveau ! Nous avons d’abord le placement du crayon avec up( ), goto( ) et down( ) dans cet ordre là. Cela permet de se déplacer en décidant quand nous voulons écrire.

Cette fois-ci, l’image est sans le fond pour mieux observer le choix de couleur ainsi que les tailles décroissantes.

Le résultat final

Et enfin, notre résultat ! Nous avons également rajouté deux ligne, une verte et une marron pour montrer le début des montagnes mais ces lignes servent aussi à cacher la délimitation qu’il y avait pour les traits droits en diagonale.

Télécharger le .py

Art

Miata: une route de nuit

Il s’agit d’un projet d’art génératif réalisé en utilisant principalement le module turtle de python . Nous avons décider de générer une Mazda mx-5 aussi appelée Miata sur une route de nuit avec des étoiles générées aléatoirement.

Le script

On commence par importer les modules dont on a besoin pour la suite tout en définissant la taille de l’image grâce au module pillow

from turtle import *
from random import randint
try:
    from PIL import *
    pillow_installed = True
except:
    print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
    print("https://nsi.xyz/py2png")
    pillow_installed = False
# Uniquement des lettres, des chiffres, un tiret. Rien d'autre.
titre = "MIATA"
# Définir le titre de la fenêtre de turtle + propagande ^^
title(titre+" | Au lycée, la meilleure spécialité, c'est la spé NSI")
# definir la taille de la fenêtre en 720p (Largeur, Hauteur)
# La tortue part du centre, au point de coordonnées (0,0)
setup(800, 700)
# La tortue va à la vitesse du lièvre et active sa cape d'invisibilité
speed(0)
hideturtle()

Image de fond

On génère ensuite l’image en commençant par le fond

On commence par le ciel de nuit et les étoiles

def star():

     pensize(3)
     seth(randint(0,360))
     e = randint(2,6)
     color("#F2F3CF")
     penup()
     goto(randint(-400,400),randint(85,350))
     pendown()
     for i in range(5):
        forward(e)
        right(142)

speed(0)
pensize(10000)
hideturtle()
color("#07073C")
forward(10)

for i in range(18):
    star()
penup()
goto(-250,300)
pendown()
pensize(2)
begin_fill()
seth(210)
color("#BFC298")
for i in range(

On commence par définir la fonction star() qui nous sert a générer une étoile d’une taille aléatoire a une position elle aussi aléatoire dans la zone qui sera le ciel pour éviter qu’elle finisse cachée par les autres éléments qui seront générés par la suite. Ensuite on fait un fond bleu nuit qui prend l’entièreté de l’écran en mettant une taille de crayon très grande et on génère 18 étoiles en utilisant une boucle qui répète la fonction star() puis on fait un croissant de lune en faisant des boucles donnant des arrondis . Ainsi on obtient cela:

on continue en ajoutant une forêt qui sera derrière la voiture

goto(-400,75)
pendown()
pensize(2)
color("#2C4D20")
begin_fill()
for i in range(3):
    seth(45)
    forward(77)
    right(90)
    forward(70)
    seth(45)
    forward(60)
    right(90)
    forward(80)
    seth(45)
    forward(50)
    right(90)
    forward(43)
right(45)
forward(460)
right(90)
forward(810)
right(90)
forward(455)
end_fill()

Ce code nous permet de générer des triangles de 3 tailles différentes que l’on va remplir fin de donner l’illusion d’une forêt dense en utilisant un vert foncé

On continue en réalisant la route

seth(0)
goto(-450,-125)
pensize(30)
color("#373639")
forward(900)
penup()

goto(-400,-175)
pendown()
pensize(2)
begin_fill()
color("#262527")
forward(800)
right(90)
forward(200)
right(90)
forward(800)
right(90)
forward(200)
end_fill()

goto(-400,-180)
pensize(7)
seth(0)
for i in range(4):
    color("white")
    forward(100)
    penup()
    forward(100)
    pendown()

Ce code nous permet de faire un grand trait de couleur grise pour représenter la barrière puis il génère un grand rectangle qui représente la route en y ajoutant des bandes blanches, créant ainsi une route.

La voiture

On passe ensuite à la partie la plus importante du script: la voiture

def phares():
    left(30)  
    fillcolor('gray')
    begin_fill()
    left(80)
    color('yellow')
    pensize(4)
    forward(25)
    pensize(1)
    color('gray')
    right(120)
    forward(30)
    right(130)
    forward(30)
    end_fill()
    forward(-31)
    color('red')
    pensize(4)
    right(50)
    forward(32)
    forward(-32)
    color('red')
    right(125)
    pensize(1)
    pendown()
def jantes():
    color('gray')
    begin_fill()
    fillcolor('black')
    circle(30)
    end_fill()
    forward(5)
    left(90)
    forward(10)
    pendown()
    begin_fill()
    fillcolor('silver')
jantes()

Cette partie nous permet de faire l’avant de la voiture en définissant la fonction pour faire une roue composée d’un pneu et d’une jante, inspiré des jantes BBS et ainsi que la fonction qui servira à faire le phare avant

pensize(1)
color('black')
fillcolor('red')
for i in range (35):
    forward(1)
    right(0.75)
right(75)

forward(50)
right(90)
for i in range(169):
    forward(0.5)
    left(1)
right(94)
forward(20)
end_fill()
right(85)
forward(52)
right(163)
penup()
forward(63)
pendown()
jantes()

Résultat final

Il s’agit de la fin du code pour l’image, terminant la Miata en faisant l’habitacle composé du toit de la voiture et d’une fenêtre puis l’arrière de la voiture en rappelant la fonction définie plus tôt afin de faire la seconde roue

Pour conclure on met la dernière partie de code pour exporter l’image en fichier.png

# ============== GENERER DES IMAGES AUTOMATIQUEMENT ==============

if flash:
    wn.update() 

image = getcanvas()
nom_du_fichier_sans_extension=titre+"_"+hex(randint(2**30+2**25,2**30+2**25+2**24-1))[2:]

# Génère un fichier .ps
image.postscript(file=nom_du_fichier_sans_extension+".ps", colormode='color')

# Ouvre le fichier .ps et génère le fichier .png


try:
    psimage = Image.open(nom_du_fichier_sans_extension+".ps")
    psimage.load(scale=2)
    psimage_resized = psimage.resize((1280, 720))
    psimage.save(nom_du_fichier_sans_extension+".png")
    print(nom_du_fichier_sans_extension+".png", psimage.size, "sauvegardé dans le dossier")    

except:
    if not pillow_installed:
        print("Oops! - ModuleNotFoundError: No module named 'PIL' - RTFM :")
        print("https://nsi.xyz/py2png")
    else:
        print("Oops! - 'ghostscript' not installed- RTFM :")
        print("https://nsi.xyz/py2png")

exitonclick()

Télécharger le projet

Projets

Cinéma: Matrix et le binaire

« Are you telling me I can dodge bullets ? » Neo, The matrix. Cette citation représente la base de notre projet dans lequel est présenté le personnage Neo au visage hélicoïdal stoppant les balles sur un fond de chiffres binaires aléatoirement positionnés.

I – Le fond

Premièrement, le fond nous semblait être la partie la plus importante du projet. Nous avons donc commencé par poser un fond noir avec les lignes de code suivantes

color('black')
pensize(2000) #peu conventionnel 😅
goto(-635, 350)
forward(700)

Après cela, nous y avons superposé les caractères 1 et 0 que nous avons définis avec le code suivant.

def un():
    pensize(2)
    color('green')
    setheading(60)
    forward(12)
    setheading(270)
    forward(20)

def zero():
    setheading(90)
    circle(8)

Nous avons ensuite créé une suite de boucle pour placer aléatoirement des 1 et des 0 en colonnes. Pour cela, nous avons utilisé le module « random » avec la fonction « random.choice » pour sélectionner aléatoirement un nombre dans une liste prédéfinie, ensuite, une condition nous a permis de placer les chiffres. Pour ordonner ces derniers, une incrémentation aux coordonnées déjà inscrites (définissant la position du premier caractère posé) à la fin de chaque boucle a été nécessaire. Voici le code

y = 330
x = -620
    
for i in range(50):
    penup()
    goto(x, y)
    pendown()
    
    for i in range(20):
        list1 = [1,2]

        if random.choice(list1) == 1: 
            un()
        else:
            zero()
            
        penup()
        goto(x, y - 40 * (i + 1))
        pendown()
        
    x += 25 #incrémentation de la distance entre chaque colonnes (horizontalement)
    

Voici le résultat du fond finalisé :

II – Le personnage, Neo

1 – La main

La main était aussi une partie importante de l’image : elle constitue le point de fuite centrale de l’image, où se dirige toutes les balles. Voici la main, constituée de lignes plus ou moins courtes (doigts) et d’un cercle (paume).

2 – Le corps

Nous avons donc créé le corps d’un homme bâton, avec de simples lignes et un cercle pour la tête. Voici le code :

def corps():
    pensize(5)
    color('white')
    penup()
    goto(0,-70)
    pendown()
    setheading(90)
    left(110)
    forward(180)
    left(25)
    forward(80)
    left(180)
    forward(80)


    setheading(90)
    forward(40)
    right(180)
    forward(150)
    setheading(90)
    right(150)
    forward(90)
    left(180)
    forward(90)
    setheading(90)
    left(150)
    forward(90)
    right(180)
    forward(90)
    setheading(90)
    forward(150)

    right(90)
    circle(50)
    penup()
    setheading(90)
    forward(50)
    pendown()
corp()

Voici le rendu :

3 – La spirale

Pour créer cette spirale, il n’a suffit que de 2 lignes, avec une boucle for :

for i in range(48):
    circle(i,20) # i est donc augmenté a chaque répétition 

Le rendu fut le suivant :

III – Les balles

Pour créer les balles, nous avons créé une fonction, en utilisant les méthodes « begin_fill » et « end_fill » permettant de remplir tout ce que l’on dessine en trait. Voici le code :

def balle():
    pensize(3)
    color('#A9A9A9')
    begin_fill()
    forward(30)
    left(143)
    forward(27)
    left(110)
    forward(15)
    end_fill()
    left(180)
    forward(7)
    color("grey")
    begin_fill()
    circle(10)
    end_fill()

Voici le résultat

Pour créer plus de dynamisme, nous avons opté pour des tirets, encore avec une fonction, appelées (comme les balles) plusieurs fois. Nous avons donc créé une boucle for, se répétant 18 fois :

def tiret():
    for i in range(18):
        pensize(7)
        color("white")
        forward(5)
        penup()
        forward(15)
        pendown()

Pour une balle, nous avons combiné les deux fonctions en les appelant de la sorte :

penup()
left(50)
goto(300,-150) 
pendown()
balle()
penup()
left(90)
forward(30)
pendown()
tiret() 
right(90)

Nous avons répété ce pattern sept fois, en changeant leurs positions (goto).

IV – L’image finale

V – Les problèmes rencontrés

Le seul ‘problème’ qu’on a rencontré fut pour le fond, pour utiliser le module random dans une liste, mais nous avons relu nos exercices sur ce thème et avons facilement trouvé la solution.

VII – Télécharger le .py

Nous vous mettons au défi d’optimiser ce code au maximum, sans changer le rendu.