################################################################################
#               TP 2 d'informatique - MPSI - Listes - 29/09/2026               #
#                                  Correction                                  #
################################################################################

###########################################
# Exercice 1. Moyenne arithmético-géométrique
###########################################

def approx_moy_ag(a,b,n):
    """approx_moy_ag(a: float, b: float, n: int) -> float"""
    u = a
    v = b
    for _ in range(n):
        tmp = u
        u = (u*v)**0.5
        v = (tmp+v)/2
    return (u, v)

### Tests:

# print(approx_moy_ag(5,20,0))
# print(approx_moy_ag(5,20,1))
# print(approx_moy_ag(5,20,2))

# print(approx_moy_ag(1,1,100))
# print(approx_moy_ag(2,8,10))
# print(approx_moy_ag(3,10,10))

###########################################
# Exercice 2. Parcours de listes
###########################################

################
### Question 1
################

def maximum(L):
    """maximum(L: list[int]) -> int"""
    assert L != []
    maxi = L[0]
    for i in range(1, len(L)):
        if maxi < L[i]:
            maxi = L[i]
    return maxi

### Tests:

# # print(maximum([]))
# print(maximum([1,2,3]))
# print(maximum([-8,6,0,4]))
# print(maximum([8,6,4,0]))

################
### Question 2
################

def est_croissante(L):
    """est_croissante(L: list[int]) -> bool"""
    for i in range(len(L)-1):
        if L[i] > L[i+1]:
            return False
    return True

### Tests:

# print(est_croissante([]))
# print(est_croissante([0]))
# print(est_croissante([1,2,3]))
# print(est_croissante([-10,-3,0,0,4,8,8]))
# print(est_croissante([0,-1]))
# print(est_croissante([-3, 4, 5, 4, 5, 6]))
# print(est_croissante([1,0,1,2,3,4]))
# print(est_croissante([-2,-1,0,1,2,3,2]))

################
### Question 3
################

def inverser(L):
    """inverser(L: list[int]) -> list[int]"""
    M = []
    for i in range(len(L)-1, -1, -1):
        M.append(L[i])
    return M

### Tests:

# print(inverser([]))
# print(inverser([0]))
# print(inverser([3,2,1]))
# print(inverser([5,8,4,1,0,2,1]))

###########################################
# Exercice 3. Compréhensions de listes
###########################################

################
### Question 1
################

def mult_elem_liste(a,L):
    """mult_elem_liste(a: int, L: list[int]) -> list[int]"""
    return [a*e for e in L]

### Tests:

# print(mult_elem_liste(2, [1,2,3]))
# print(mult_elem_liste(0.5, []))
# print(mult_elem_liste(0.5, [10,8,6,-8,2,7]))
# print(mult_elem_liste(-4, [7,4,1,0,-7,-4,-1]))

################
### Question 2
################

def val_abs(L):
    """val_abs(L: list[float]) -> list[float]"""
    return [e if e >= 0 else -e for e in L]

### Tests:

# print(val_abs([]))
# print(val_abs([1,2,3]))
# print(val_abs([-5,3,0,5]))
# print(val_abs([-4]))

################
### Question 3
################

def prod_couples(L):
    """prod_couples(L: list[(int, int)]) -> list[int]"""
    return [a*b for (a,b) in L]

### Tests:

# print(prod_couples([]))
# print(prod_couples([(8,8)]))
# print(prod_couples([(1,2),(-5,2),(0,0),(9,3)]))

###########################################
# Exercice 4. Crible d'Ératosthène
###########################################

# On écrit une fonction qui met tous les multiples de i a False dans L
def mise_a_jour(L,i):
    for j in range(i,len(L),i):
        L[j] = False

def crible_eratosthene(n):
    if n < 2:
        return []
    R = []
    L = [True]*(n+1)
    L[0] = False
    L[1] = False
    for i in range(len(L)):
        if L[i]:
            R.append(i)
            mise_a_jour(L,i)
    return R

### Tests:

# print(crible_eratosthene(0))
# print(crible_eratosthene(1))
# print(crible_eratosthene(2))
# print(crible_eratosthene(12))
# print(crible_eratosthene(13))
# print(crible_eratosthene(100))

###########################################
# Exercice 5. Représentation graphique des tables de multiplications
###########################################

import tkinter as tk
from tkinter import messagebox
import math

# Cette fonction est issue du TP 1.
def open_window(width, height, title):
    """open_window(width: int, height: int, title: str) -> canevas"""
    win = tk.Tk()
    win.protocol("WM_DELETE_WINDOW", win.destroy)
    win.title(title)
    can = tk.Canvas(win, width=width, height=height,
                    highlightthickness=0, bd = 0)
    can.pack()
    can.config(bg = "white")
    return can

# Renvoie les coordonnées (i,j) du point A_k
def coord_point(L,d,k):
    x = math.sin(2*math.pi*k/d)
    y = math.cos(2*math.pi*k/d)
    i = (L-1)/2 * (1+x)
    j = (L-1)/2*(1-y)
    return (i,j)

def afficher_tablesMult(m, d):
    L = 500
    can = open_window(L, L, "m = " + str(m) + " et d = " + str(d))
    can.create_oval((0,0), (L-1,L-1))
    for k in range(d):
        i1, j1 = coord_point(L, d, k)
        i2, j2 = coord_point(L, d, (m*k) % d)
        can.create_line((i1, j1), (i2, j2))
    can.mainloop()

### Tests:

# afficher_tablesMult(3, 12)
# afficher_tablesMult(5, 21)
# afficher_tablesMult(2, 200)
# afficher_tablesMult(6, 300)