def nb_voisins_vivants(grille, i, j):
    n, m = len(grille), len(grille[0])
    voisins = [(-1,-1), (-1,0), (-1,1),
               (0,-1),          (0,1),
               (1,-1),  (1,0),  (1,1)]
    c = 0
    for di, dj in voisins:
        ni, nj = i + di, j + dj
        if 0 <= ni < n and 0 <= nj < m:
            c += grille[ni][nj]
    return c

def prochaine_generation(grille):
    n, m = len(grille), len(grille[0])
    nouvelle = [[0]*m for _ in range(n)]
    for i in range(n):
        for j in range(m):
            v = nb_voisins_vivants(grille, i, j)
            if grille[i][j] == 1:
                if v in (2, 3):
                    nouvelle[i][j] = 1
            else:
                if v == 3:
                    nouvelle[i][j] = 1
    return nouvelle

import time

def afficher(grille):
    for ligne in grille:
        print(''.join('█' if x else ' ' for x in ligne))
    print()

def simulation(grille, n):
    for _ in range(n):
        afficher(grille)
        grille = prochaine_generation(grille)
        time.sleep(0.2)


clignotant = [
    [0,0,0,0,0],
    [0,0,0,0,0],
    [0,1,1,1,0],
    [0,0,0,0,0],
    [0,0,0,0,0]
]

glider = [
    [0,1,0],
    [0,0,1],
    [1,1,1]
]


import turtle

CELL_SIZE = 10

# Initialisation de la fenêtre turtle
def init_turtle(n, m):
    turtle.setup(width=m*CELL_SIZE + 50, height=n*CELL_SIZE + 50)
    turtle.speed(0)
    turtle.hideturtle()
    turtle.tracer(0, 0)

# Dessine une cellule à la position (i, j)
def dessine_cellule(i, j, vivante):
    x = j * CELL_SIZE - 250
    y = 250 - i * CELL_SIZE
    turtle.up()
    turtle.goto(x, y)
    turtle.down()
    turtle.begin_fill() if vivante else None
    for _ in range(4):
        turtle.forward(CELL_SIZE)
        turtle.right(90)
    if vivante:
        turtle.end_fill()

# Dessine la grille complète
def dessine_grille(grille):
    turtle.clear()
    n, m = len(grille), len(grille[0])
    for i in range(n):
        for j in range(m):
            dessine_cellule(i, j, grille[i][j] == 1)
    turtle.update()

# Simulation graphique
def simulation_turtle(grille, n):
    init_turtle(len(grille), len(grille[0]))
    for _ in range(n):
        dessine_grille(grille)
        grille = prochaine_generation(grille)

## amélioration Tkinter
import tkinter as tk
import random

CELL_SIZE = 12

# --- Motifs célèbres ---
MOTIFS = {
    "Glider": [
        [0,1,0],
        [0,0,1],
        [1,1,1]
    ],
    "Pulsar": [
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,0,0,0,1,1,1,0,0]
    ],
    "LWSS": [
        [0,1,1,1,1],
        [1,0,0,0,1],
        [0,0,0,0,1],
        [1,0,0,1,0]
    ]
}

class JeuDeLaVie:
    def __init__(self, n=50, m=50):
        self.n = n
        self.m = m
        self.grille = [[random.randint(0, 1) for _ in range(m)] for _ in range(n)]
        self.running = False
        self.delay = 120

        # --- Fenêtre ---
        self.root = tk.Tk()
        self.root.title("Jeu de la Vie — Interface avancée")

        # --- Canvas ---
        self.canvas = tk.Canvas(self.root, width=m * CELL_SIZE, height=n * CELL_SIZE, bg="white")
        self.canvas.grid(row=0, column=0, columnspan=4)
        self.canvas.bind("<Button-1>", self.toggle_cell)

        # --- Boutons ---
        tk.Button(self.root, text="Start", command=self.start).grid(row=1, column=0)
        tk.Button(self.root, text="Pause", command=self.pause).grid(row=1, column=1)
        tk.Button(self.root, text="Réinitialiser", command=self.reset).grid(row=1, column=2)

        # --- Slider vitesse ---
        self.speed_slider = tk.Scale(self.root, from_=20, to=500, orient=tk.HORIZONTAL,
                                     label="Vitesse (ms)", command=self.update_speed)
        self.speed_slider.set(self.delay)
        self.speed_slider.grid(row=2, column=0, columnspan=2)

        # --- Menu motifs ---
        self.motif_var = tk.StringVar(self.root)
        self.motif_var.set("Insérer un motif")

        motif_menu = tk.OptionMenu(self.root, self.motif_var, *MOTIFS.keys(), command=self.insert_motif)
        motif_menu.grid(row=2, column=2, columnspan=2)

        self.update_canvas()

    # --- Interaction souris ---
    def toggle_cell(self, event):
        i = event.y // CELL_SIZE
        j = event.x // CELL_SIZE
        self.grille[i][j] = 1 - self.grille[i][j]
        self.update_canvas()

    # --- Interaction vitesse ---
    def update_speed(self, value):
        self.delay = int(value)

    # --- Gestion motifs ---
    def insert_motif(self, motif_name):
        motif = MOTIFS[motif_name]
        mi, mj = len(motif), len(motif[0])
        offset_i = (self.n - mi) // 2
        offset_j = (self.m - mj) // 2
        for i in range(mi):
            for j in range(mj):
                self.grille[offset_i + i][offset_j + j] = motif[i][j]
        self.update_canvas()

    # --- Gestion simulation ---
    def start(self):
        if not self.running:
            self.running = True
            self.run()

    def pause(self):
        self.running = False

    def reset(self):
        self.grille = [[random.randint(0, 1) for _ in range(self.m)] for _ in range(self.n)]
        self.update_canvas()

    # --- Affichage ---
    def update_canvas(self):
        self.canvas.delete("all")
        for i in range(self.n):
            for j in range(self.m):
                x1, y1 = j * CELL_SIZE, i * CELL_SIZE
                x2, y2 = x1 + CELL_SIZE, y1 + CELL_SIZE
                color = "black" if self.grille[i][j] == 1 else "white"
                self.canvas.create_rectangle(x1, y1, x2, y2, fill=color, outline="grey")

    # --- Automate ---
    def nb_voisins(self, i, j):
        voisins = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
        return sum(self.grille[i+di][j+dj]
                   for di, dj in voisins
                   if 0 <= i+di < self.n and 0 <= j+dj < self.m)

    def next_gen(self):
        new = [[0]*self.m for _ in range(self.n)]
        for i in range(self.n):
            for j in range(self.m):
                v = self.nb_voisins(i, j)
                if self.grille[i][j] == 1:
                    new[i][j] = 1 if v in (2,3) else 0
                else:
                    new[i][j] = 1 if v == 3 else 0
        self.grille = new

    # --- Boucle principale ---
    def run(self):
        if self.running:
            self.next_gen()
            self.update_canvas()
            self.root.after(self.delay, self.run)

    def launch(self):
        self.root.mainloop()

# Exemple d'utilisation :
app = JeuDeLaVie(50, 50)
app.launch()
