#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri May 22 08:33:22 2026

@author: etienne.mann and daniel.naie
"""

import numpy as np
import random as rd
import matplotlib.pyplot as plt


# ------ EXERCICE 1 ------
print("------ EXERCICE 1 ------")


def multiplication_sur_les_indices(p, n):
    N = 200
    x_circle = [np.cos(2 * k * np.pi / N) for k in range(N)]
    y_circle = [np.sin(2 * k * np.pi / N) for k in range(N)]

    x = [np.cos(2 * k * np.pi / n) for k in range(n)]
    y = [np.sin(2 * k * np.pi / n) for k in range(n)]

    plt.plot(x_circle, y_circle, c='k', lw=.5)
    plt.plot(x, y, ls=' ', marker='o', ms=5)

    for k in range(0, n):
        x_pts = [x[k], x[(p * k) % n]]
        y_pts = [y[k], y[(p * k) % n]]
        plt.plot(x_pts, y_pts, c='r')
        
    plt.title(f"p = {p} et n = {n}")
    plt.axis('equal')
    plt.show()
    
# Questions 1, 2 et 3
multiplication_sur_les_indices(2, 10)
multiplication_sur_les_indices(3, 10)
multiplication_sur_les_indices(3, 21)
multiplication_sur_les_indices(3, 201)


# Question 4
print("L'inverse de 3 modulo n (=10) est 7 car c'est lui qui est relie "
      + "avec le point M1")
print("3 x 7 = 21 = 1 mod 10")


# Question 5
print("k a un inverse modulo n si sur notre graphique un point est relie "
      + "avec le point M1"
      + "(sans prendre en compte celui sur lequel M1 s'envoie)")
print("La condition (sans prendre en compte celui sur lequel M1 s'envoie) "
      + "n'est pas visible sur le dessin dans l'etat !")

print("Du point de vue mathematique, k et n sont premiers entre eux.")




# ------ EXERCICE 2 ------
print("\n\n------ EXERCICE 2 ------")
print("solution de Lucas Leriche\n")

# Question 1
def chiffres(N):
    c = list()
    n = N
    while n != 0:
        c.append(n%10)
        n = n // 10
    return c

def laSomme(N):
    c = chiffres(N)
    s = 0
    for n in c:
        s = s + n*n*n
    return s

# Question 3
nombres = list()
n = 2
while len(nombres) < 2:
    if(laSomme(n) == n):
        nombres.append(n)
    n = n+1
    
print("Les deux nombres pour lesquelles laSomme(n)=n sont", nombres)

# Question 4
def laSomme_puiss4(N):
    c = chiffres(N)
    s = 0
    for n in c:
        s = s + n*n*n*n
    return s

nombres = list()
n = 2
while len(nombres) < 2:
    if(laSomme_puiss4(n) == n):
        nombres.append(n)
    n = n+1

print("Les deux nombres pour lesquelles laSomme_puiss4(n)=n sont", nombres)

# Question 5
def laSommeCarre(N):
    c = chiffres(N)
    s = 0
    for n in c:
        s = s + n*n
    return s

print("A partir de 999, on ne peut pas atteindre le nombre voulu avec des carrés.")
print("999 donne 9²+9²+9² = 243 ce qui est trop petit. Tous les nombres plus grands donneront la même remarque.")
print("Et si on teste tous les nombres entre 2 et 999")
for n in range(2, 1000):
    if(laSommeCarre(n) == n):
        print(f"Cela marche pour {n}")
print("On voit que aucun nombre ne vérifie la condition.")





# ------ EXERCICE 3 ------
print("\n\n------ EXERCICE 3 ------")

print(f"voir comment rd fonctione :", rd.choice([-1,1]))

def marche(n):
    L = [0]
    for i in range(n):
        t = rd.choice([-1, 1])
        temp = L[i]+t
        L.append(temp)
    return(L)


def afficher_marche(n):
    fig = plt.figure(figsize=(9, 8))
    axe = fig.add_subplot(111)
    axe.grid()
    axe.set_title(f"Cinq marches aleatoires avec n = {n}")
    X = range(n+1)
    for i in range(5):
        Y = marche(n)
        axe.plot(X, Y)
                

def revient_origine(positions):
    p = len(positions)
    for i in range(1, p):
        if positions[i] == 0:
            return i
    return p + 1    


def premier_retours(n, nb_tests):
    L = []
    for _ in range(nb_tests):
        M = marche(n)
        L.append(revient_origine(M))
    return L


afficher_marche(100)


n_list = [10, 50, 100, 500]  #, 1000]
N = len(n_list)
etude = plt.figure(figsize=(18, 6))
etude.suptitle("Etudes avec 10000 repetitions")
axes_list = []
for k in range(N):
    axe = etude.add_subplot(1, N, k + 1)
    axes_list.append(axe)

N = len(n_list)
for k in range(N):
    n = n_list[k]
    R = premier_retours(n, 10000)
    axes_list[k].hist(R, bins = n + 1)

plt.show()

