Mini-projets algorithmique, corrigé TP KNN, news, notebooks IA
This commit is contained in:
BIN
algorithmes/mini-projets/01_devine_nombre.zip
Normal file
BIN
algorithmes/mini-projets/01_devine_nombre.zip
Normal file
Binary file not shown.
41
algorithmes/mini-projets/01_devine_nombre/starter.py
Normal file
41
algorithmes/mini-projets/01_devine_nombre/starter.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# Projet 01 — Le Nombre Mystère
|
||||
# Algorithme : Recherche dichotomique
|
||||
|
||||
def devine():
|
||||
"""
|
||||
L'ordinateur devine le nombre auquel pense l'utilisateur
|
||||
en utilisant la recherche dichotomique.
|
||||
"""
|
||||
print("=== Le Nombre Mystère ===")
|
||||
print("Pense à un nombre entre 1 et 100 (sans le dire !)")
|
||||
print("Réponds avec : < (trop grand), > (trop petit), = (trouvé !)")
|
||||
print()
|
||||
|
||||
gauche = 1
|
||||
droite = 100
|
||||
nb_essais = 0
|
||||
|
||||
while gauche <= droite:
|
||||
milieu = (gauche + droite) // 2
|
||||
nb_essais += 1
|
||||
|
||||
reponse = input(f"Essai {nb_essais} — Est-ce que ton nombre est {milieu} ? ")
|
||||
|
||||
if reponse == "=":
|
||||
print(f"Trouvé ! C'était bien {milieu}, en {nb_essais} essai(s) !")
|
||||
return
|
||||
elif reponse == "<":
|
||||
# TODO : le nombre cherché est plus petit que milieu
|
||||
# Que faut-il modifier ? gauche ou droite ?
|
||||
pass
|
||||
elif reponse == ">":
|
||||
# TODO : le nombre cherché est plus grand que milieu
|
||||
pass
|
||||
else:
|
||||
print("Réponse invalide, utilise <, > ou =")
|
||||
|
||||
print("Je n'ai pas trouvé... tu as peut-être changé de nombre !")
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
devine()
|
||||
44
algorithmes/mini-projets/01_devine_nombre/sujet.md
Normal file
44
algorithmes/mini-projets/01_devine_nombre/sujet.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 01 — Le Nombre Mystère
|
||||
|
||||
**Algorithme :** Recherche dichotomique
|
||||
**Difficulté :** Facile
|
||||
**Durée estimée :** 45 min — 1h
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous pensez à un nombre entre 1 et 100. L'ordinateur doit le deviner le plus vite possible en posant des questions.
|
||||
|
||||
À chaque essai, vous répondez :
|
||||
- `<` si votre nombre est **plus petit** que la proposition
|
||||
- `>` si votre nombre est **plus grand**
|
||||
- `=` si c'est **le bon nombre**
|
||||
|
||||
L'ordinateur utilise la **recherche dichotomique** : à chaque question, il coupe l'intervalle possible en deux.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Comprendre la stratégie
|
||||
Sans coder, répondez sur papier : si le nombre est entre 1 et 100, quelle est la première proposition optimale ? Pourquoi ?
|
||||
|
||||
### Étape 2 — Implémenter `devine()`
|
||||
Complétez la fonction `devine()` dans `starter.py` :
|
||||
- L'ordinateur part de `gauche = 1` et `droite = 100`
|
||||
- Il propose `milieu = (gauche + droite) // 2`
|
||||
- Selon la réponse, il réduit l'intervalle
|
||||
- Il compte le nombre d'essais
|
||||
|
||||
### Étape 3 — Tester
|
||||
Lancez le programme et jouez plusieurs parties. Vérifiez que l'ordinateur trouve toujours en **7 essais maximum**.
|
||||
|
||||
### Étape 4 — Extension (si vous avez le temps)
|
||||
Ajoutez une deuxième version où **c'est vous** qui devez deviner le nombre de l'ordinateur. L'ordinateur choisit un nombre aléatoire (`random.randint(1, 100)`), et le programme vous dit si vous êtes trop grand ou trop petit. Comptez vos essais et comparez avec le maximum optimal.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme qui fonctionne
|
||||
- La réponse à la question : pourquoi 7 essais suffisent toujours pour 100 nombres ?
|
||||
BIN
algorithmes/mini-projets/02_cartes.zip
Normal file
BIN
algorithmes/mini-projets/02_cartes.zip
Normal file
Binary file not shown.
81
algorithmes/mini-projets/02_cartes/starter.py
Normal file
81
algorithmes/mini-projets/02_cartes/starter.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# Projet 02 — Le Tri de Cartes
|
||||
# Algorithme : Tri par insertion
|
||||
|
||||
NOMS_VALEURS = {11: "Valet", 12: "Dame", 13: "Roi", 14: "As"}
|
||||
|
||||
def nom_carte(carte):
|
||||
"""Retourne une représentation lisible d'une carte."""
|
||||
valeur, couleur = carte
|
||||
nom = NOMS_VALEURS.get(valeur, str(valeur))
|
||||
return f"{nom} de {couleur}"
|
||||
|
||||
def afficher_main(main):
|
||||
"""Affiche toutes les cartes d'une main."""
|
||||
print("Main :", " | ".join(nom_carte(c) for c in main))
|
||||
|
||||
def tri_insertion_cartes(main):
|
||||
"""
|
||||
Trie la main de cartes par valeur croissante (tri par insertion).
|
||||
Chaque carte est un tuple (valeur, couleur).
|
||||
On trie selon le premier élément du tuple : la valeur.
|
||||
"""
|
||||
for i in range(1, len(main)):
|
||||
x = main[i]
|
||||
j = i
|
||||
# TODO : compléter la condition du while
|
||||
# Indice : on compare les valeurs (main[j-1][0] et x[0])
|
||||
while j > 0 and ...:
|
||||
main[j] = main[j - 1]
|
||||
j -= 1
|
||||
main[j] = x
|
||||
return main
|
||||
|
||||
def chercher_carte(main_triee, valeur):
|
||||
"""
|
||||
Recherche dichotomique : retourne True si une carte de cette valeur
|
||||
est dans la main triée, False sinon.
|
||||
"""
|
||||
a = 0
|
||||
b = len(main_triee) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
valeur_m = main_triee[m][0] # on compare les valeurs
|
||||
if valeur_m == valeur:
|
||||
return True
|
||||
elif valeur_m < valeur:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
main = [
|
||||
(7, "Coeur"),
|
||||
(2, "Pique"),
|
||||
(11, "Trèfle"),
|
||||
(5, "Carreau"),
|
||||
(14, "Coeur"),
|
||||
(9, "Pique"),
|
||||
(3, "Carreau"),
|
||||
]
|
||||
|
||||
print("=== Le Tri de Cartes ===")
|
||||
print()
|
||||
print("Avant le tri :")
|
||||
afficher_main(main)
|
||||
|
||||
tri_insertion_cartes(main)
|
||||
|
||||
print()
|
||||
print("Après le tri par insertion :")
|
||||
afficher_main(main)
|
||||
|
||||
print()
|
||||
# Test de recherche
|
||||
for valeur_cherchee in [7, 12, 14, 6]:
|
||||
resultat = chercher_carte(main, valeur_cherchee)
|
||||
nom = NOMS_VALEURS.get(valeur_cherchee, str(valeur_cherchee))
|
||||
print(f"Cherche {nom} : {'trouvé !' if resultat else 'absent'}")
|
||||
39
algorithmes/mini-projets/02_cartes/sujet.md
Normal file
39
algorithmes/mini-projets/02_cartes/sujet.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# 02 — Le Tri de Cartes
|
||||
|
||||
**Algorithme :** Tri par insertion
|
||||
**Difficulté :** Facile
|
||||
**Durée estimée :** 45 min — 1h
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Lorsqu'on reçoit des cartes à jouer, on les trie naturellement dans sa main : on prend chaque nouvelle carte et on la glisse à la bonne place parmi celles déjà en ordre. C'est exactement le **tri par insertion**.
|
||||
|
||||
Dans ce projet, vous allez trier une main de cartes par valeur croissante, puis chercher une carte avec la dichotomie.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Afficher la main
|
||||
Lancez le starter et observez comment les cartes sont représentées. Chaque carte est un **tuple** `(valeur, couleur)`. La valeur va de 2 à 14 (11 = Valet, 12 = Dame, 13 = Roi, 14 = As).
|
||||
|
||||
### Étape 2 — Implémenter `tri_insertion_cartes(main)`
|
||||
Le tri doit classer les cartes par **valeur croissante** (le premier élément du tuple).
|
||||
|
||||
> **Indication** : dans le tri par insertion vu en cours, on comparait `tab[j-1] > x`. Ici, vous comparerez `main[j-1][0] > x[0]` (on ne regarde que la valeur, pas la couleur).
|
||||
|
||||
### Étape 3 — Chercher une carte
|
||||
Implémentez `chercher_carte(main_triee, valeur)` qui utilise la **dichotomie** pour savoir si une carte d'une certaine valeur est dans la main.
|
||||
|
||||
> **Attention** : la dichotomie ne fonctionne que sur une liste **déjà triée** !
|
||||
|
||||
### Étape 4 — Extension (si vous avez le temps)
|
||||
Ajoutez un mode "nouvelle donne" : générez une main aléatoire de 7 cartes avec `random`, triez-la et affichez-la.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme qui trie et cherche correctement
|
||||
- Une explication : pourquoi le tri par insertion ressemble à ce qu'on fait naturellement avec des cartes ?
|
||||
BIN
algorithmes/mini-projets/03_podium.zip
Normal file
BIN
algorithmes/mini-projets/03_podium.zip
Normal file
Binary file not shown.
93
algorithmes/mini-projets/03_podium/starter.py
Normal file
93
algorithmes/mini-projets/03_podium/starter.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# Projet 03 — Le Podium
|
||||
# Algorithme : Tri par sélection
|
||||
|
||||
athletes = [
|
||||
{"nom": "Marcus", "pays": "JAM", "temps": 9.97},
|
||||
{"nom": "Alice", "pays": "FRA", "temps": 9.85},
|
||||
{"nom": "Yusuf", "pays": "TUR", "temps": 10.03},
|
||||
{"nom": "Carla", "pays": "BRA", "temps": 9.97},
|
||||
{"nom": "Bob", "pays": "USA", "temps": 9.91},
|
||||
{"nom": "Lena", "pays": "GER", "temps": 10.11},
|
||||
{"nom": "Kwame", "pays": "GHA", "temps": 9.99},
|
||||
{"nom": "Sofia", "pays": "ITA", "temps": 10.07},
|
||||
]
|
||||
|
||||
def tri_selection_athletes(athletes):
|
||||
"""
|
||||
Trie la liste d'athlètes par temps croissant (tri par sélection).
|
||||
Le meilleur (temps le plus bas) sera en premier.
|
||||
"""
|
||||
n = len(athletes)
|
||||
for i in range(n):
|
||||
mini = i
|
||||
for j in range(i + 1, n):
|
||||
# TODO : comparer les temps pour trouver le minimum
|
||||
if ...:
|
||||
mini = j
|
||||
athletes[i], athletes[mini] = athletes[mini], athletes[i]
|
||||
return athletes
|
||||
|
||||
def afficher_podium(athletes):
|
||||
"""Affiche un podium ASCII avec les 3 premiers athlètes."""
|
||||
if len(athletes) < 3:
|
||||
print("Pas assez d'athlètes pour un podium !")
|
||||
return
|
||||
|
||||
or_ = athletes[0]
|
||||
ar_ = athletes[1]
|
||||
br_ = athletes[2]
|
||||
|
||||
print()
|
||||
print(" 🥇")
|
||||
print(" ┌───┐ 🥈 🥉")
|
||||
print(" │ │ ┌───┐ ┌───┐")
|
||||
print(" │ 1 │ │ 2 │ │ 3 │")
|
||||
print(" │ │ │ │ │ │")
|
||||
print(" └───┘ └───┘ └───┘")
|
||||
print(f" {or_['nom']:^10} ({or_['pays']}) {ar_['nom']:^10} ({ar_['pays']}) {br_['nom']:^10} ({br_['pays']})")
|
||||
print(f" {or_['temps']} s {ar_['temps']} s {br_['temps']} s")
|
||||
print()
|
||||
|
||||
def temps_atteint(temps_liste, t):
|
||||
"""
|
||||
Recherche dichotomique : retourne True si le temps t
|
||||
a été réalisé par un athlète, False sinon.
|
||||
La liste temps_liste doit être triée.
|
||||
"""
|
||||
a = 0
|
||||
b = len(temps_liste) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
if temps_liste[m] == t:
|
||||
return True
|
||||
elif temps_liste[m] < t:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Compétition de Sprint ===")
|
||||
print()
|
||||
print("Résultats bruts :")
|
||||
for a in athletes:
|
||||
print(f" {a['nom']} ({a['pays']}) : {a['temps']} s")
|
||||
|
||||
tri_selection_athletes(athletes)
|
||||
|
||||
afficher_podium(athletes)
|
||||
|
||||
# Classement complet
|
||||
print("Classement final :")
|
||||
for i, a in enumerate(athletes, 1):
|
||||
print(f" {i}. {a['nom']} ({a['pays']}) — {a['temps']} s")
|
||||
|
||||
# Recherche dichotomique
|
||||
temps_liste = [a["temps"] for a in athletes]
|
||||
print()
|
||||
for t in [9.85, 10.00, 9.97]:
|
||||
trouve = temps_atteint(temps_liste, t)
|
||||
print(f"Temps {t}s réalisé ? {'Oui' if trouve else 'Non'}")
|
||||
49
algorithmes/mini-projets/03_podium/sujet.md
Normal file
49
algorithmes/mini-projets/03_podium/sujet.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 03 — Le Podium
|
||||
|
||||
**Algorithme :** Tri par sélection
|
||||
**Difficulté :** Facile
|
||||
**Durée estimée :** 45 min — 1h
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous gérez le classement d'une compétition de sprint. Vous devez trier les athlètes par **temps croissant** (le plus rapide en premier) et afficher le podium.
|
||||
|
||||
Le tri par sélection fonctionne comme un vrai classement : à chaque étape, on cherche le meilleur parmi tous les restants et on le place en tête.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Implémenter `tri_selection_athletes(athletes)`
|
||||
La liste `athletes` contient des dictionnaires `{"nom": ..., "pays": ..., "temps": ...}`.
|
||||
Il faut trier par `temps` croissant (le plus petit temps = le plus rapide).
|
||||
|
||||
> **Indication** : dans le tri par sélection, au lieu de comparer `tab[j] < tab[mini]`, vous comparerez `athletes[j]["temps"] < athletes[mini]["temps"]`.
|
||||
|
||||
### Étape 2 — Afficher le podium
|
||||
Implémentez `afficher_podium(athletes_tries)` qui affiche les 3 premiers avec un podium en ASCII.
|
||||
|
||||
```
|
||||
1er
|
||||
+---+ 2e 3e
|
||||
| | +---+ +---+
|
||||
| 1 | | 2 | | 3 |
|
||||
| | | | | |
|
||||
+---+ +---+ +---+
|
||||
Alice (FR) Bob (USA) Carla (BR)
|
||||
9.85 s 9.91 s 9.97 s
|
||||
```
|
||||
|
||||
### Étape 3 — Recherche dichotomique
|
||||
Après le tri, créez une liste des temps uniquement. Implémentez `temps_atteint(temps_liste, t)` qui utilise la dichotomie pour dire si un temps exact a été réalisé lors de la compétition.
|
||||
|
||||
### Étape 4 — Extension (si vous avez le temps)
|
||||
Affichez aussi le classement complet sous forme de tableau numéroté.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme qui trie et affiche le podium
|
||||
- Réponse : pourquoi le tri par sélection fait-il **moins de déplacements** que le tri par insertion ?
|
||||
BIN
algorithmes/mini-projets/04_annuaire.zip
Normal file
BIN
algorithmes/mini-projets/04_annuaire.zip
Normal file
Binary file not shown.
88
algorithmes/mini-projets/04_annuaire/starter.py
Normal file
88
algorithmes/mini-projets/04_annuaire/starter.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Projet 04 — L'Annuaire
|
||||
# Algorithmes : Tri par insertion + Recherche dichotomique
|
||||
|
||||
# L'annuaire est une liste de dictionnaires, toujours triée par "nom"
|
||||
annuaire = [
|
||||
{"nom": "Dupont", "prenom": "Alice", "tel": "06 11 22 33 44"},
|
||||
{"nom": "Garcia", "prenom": "Carlos", "tel": "07 55 66 77 88"},
|
||||
{"nom": "Martin", "prenom": "Sophie", "tel": "06 99 88 77 66"},
|
||||
{"nom": "Petit", "prenom": "Luc", "tel": "07 12 34 56 78"},
|
||||
{"nom": "Rousseau", "prenom": "Emma", "tel": "06 44 55 66 77"},
|
||||
]
|
||||
|
||||
def afficher_annuaire(annuaire):
|
||||
"""Affiche tous les contacts sous forme de tableau."""
|
||||
print(f"\n{'Nom':<15} {'Prénom':<12} {'Téléphone'}")
|
||||
print("-" * 40)
|
||||
for contact in annuaire:
|
||||
print(f"{contact['nom']:<15} {contact['prenom']:<12} {contact['tel']}")
|
||||
print()
|
||||
|
||||
def ajouter_contact(annuaire, contact):
|
||||
"""
|
||||
Insère le contact à la bonne place pour maintenir l'ordre alphabétique.
|
||||
Principe : tri par insertion (un seul élément à insérer).
|
||||
"""
|
||||
annuaire.append(contact) # on l'ajoute à la fin temporairement
|
||||
j = len(annuaire) - 1
|
||||
# TODO : décaler vers la droite tant que le nom précédent est > au nom du contact
|
||||
# Indice : comparer annuaire[j-1]["nom"] et contact["nom"]
|
||||
while j > 0 and ...:
|
||||
annuaire[j] = annuaire[j - 1]
|
||||
j -= 1
|
||||
annuaire[j] = contact
|
||||
|
||||
def rechercher(annuaire, nom):
|
||||
"""
|
||||
Recherche dichotomique par nom.
|
||||
Retourne le contact (dict) si trouvé, None sinon.
|
||||
"""
|
||||
a = 0
|
||||
b = len(annuaire) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
nom_m = annuaire[m]["nom"]
|
||||
if nom_m == nom:
|
||||
return annuaire[m]
|
||||
elif nom_m < nom:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return None
|
||||
|
||||
def menu():
|
||||
"""Boucle de menu interactif."""
|
||||
while True:
|
||||
print("=== Annuaire ===")
|
||||
print("1 — Afficher tous les contacts")
|
||||
print("2 — Ajouter un contact")
|
||||
print("3 — Rechercher un contact")
|
||||
print("4 — Quitter")
|
||||
choix = input("Votre choix : ")
|
||||
|
||||
if choix == "1":
|
||||
afficher_annuaire(annuaire)
|
||||
|
||||
elif choix == "2":
|
||||
nom = input("Nom : ").strip().capitalize()
|
||||
prenom = input("Prénom : ").strip().capitalize()
|
||||
tel = input("Téléphone : ").strip()
|
||||
ajouter_contact(annuaire, {"nom": nom, "prenom": prenom, "tel": tel})
|
||||
print(f"{nom} ajouté !")
|
||||
|
||||
elif choix == "3":
|
||||
nom = input("Nom à rechercher : ").strip().capitalize()
|
||||
# TODO : appeler rechercher() et afficher le résultat
|
||||
pass
|
||||
|
||||
elif choix == "4":
|
||||
print("Au revoir !")
|
||||
break
|
||||
else:
|
||||
print("Choix invalide.")
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
menu()
|
||||
46
algorithmes/mini-projets/04_annuaire/sujet.md
Normal file
46
algorithmes/mini-projets/04_annuaire/sujet.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 04 — L'Annuaire
|
||||
|
||||
**Algorithmes :** Tri par insertion + Recherche dichotomique
|
||||
**Difficulté :** Moyen
|
||||
**Durée estimée :** 1h — 1h15
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous créez un mini-annuaire de contacts. Il doit toujours rester **trié par nom** pour que la recherche dichotomique fonctionne.
|
||||
|
||||
Chaque fois qu'on ajoute un contact, on l'insère directement à la bonne place (comme dans le tri par insertion). Chaque fois qu'on cherche, on utilise la dichotomie.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Afficher l'annuaire
|
||||
Lancez le starter, vérifiez que `afficher_annuaire()` fonctionne.
|
||||
|
||||
### Étape 2 — Implémenter `ajouter_contact(annuaire, contact)`
|
||||
Cette fonction insère le nouveau contact **à la bonne position** pour maintenir l'ordre alphabétique.
|
||||
|
||||
> **Indication** : c'est le principe du tri par insertion, mais appliqué à un seul élément. On parcourt depuis la fin et on décale les contacts dont le nom est alphabétiquement après le nouveau.
|
||||
>
|
||||
> Pour comparer des chaînes alphabétiquement en Python : `"Dupont" < "Martin"` → `True`
|
||||
|
||||
### Étape 3 — Implémenter `rechercher(annuaire, nom)`
|
||||
Recherche dichotomique : retourne le contact (dictionnaire complet) si trouvé, `None` sinon.
|
||||
|
||||
### Étape 4 — Menu interactif
|
||||
Complétez la boucle `menu()` pour que l'utilisateur puisse :
|
||||
- `1` — Afficher tous les contacts
|
||||
- `2` — Ajouter un contact
|
||||
- `3` — Rechercher un contact par nom
|
||||
- `4` — Quitter
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez une option `5` pour supprimer un contact par nom (cherchez-le d'abord avec la dichotomie, puis supprimez-le de la liste).
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme avec le menu fonctionnel
|
||||
- Réponse : dans quel cas la dichotomie est-elle inutilisable directement ?
|
||||
BIN
algorithmes/mini-projets/05_correcteur.zip
Normal file
BIN
algorithmes/mini-projets/05_correcteur.zip
Normal file
Binary file not shown.
111
algorithmes/mini-projets/05_correcteur/starter.py
Normal file
111
algorithmes/mini-projets/05_correcteur/starter.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# Projet 05 — Le Correcteur Orthographique
|
||||
# Algorithmes : Tri par insertion + Recherche dichotomique
|
||||
|
||||
# Dictionnaire de base, déjà trié alphabétiquement
|
||||
dictionnaire = [
|
||||
"algorithme", "annuaire", "arbre", "binaire", "boucle",
|
||||
"cellule", "chaine", "chat", "chien", "circuit",
|
||||
"clavier", "code", "complexite", "condition", "donnee",
|
||||
"ecran", "entier", "fichier", "flottant", "fonction",
|
||||
"graphe", "indice", "instruction", "langage", "liste",
|
||||
"logiciel", "memoire", "module", "nombre", "octet",
|
||||
"ordinateur", "pixel", "programme", "python", "recursion",
|
||||
"reseau", "serveur", "tableau", "terminal", "variable",
|
||||
]
|
||||
|
||||
def verifier(dictionnaire, mot):
|
||||
"""
|
||||
Recherche dichotomique : retourne True si le mot est dans le dictionnaire,
|
||||
False sinon.
|
||||
"""
|
||||
a = 0
|
||||
b = len(dictionnaire) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
if dictionnaire[m] == mot:
|
||||
return True
|
||||
elif dictionnaire[m] < mot:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return False
|
||||
|
||||
def verifier_avec_voisins(dictionnaire, mot):
|
||||
"""
|
||||
Recherche dichotomique améliorée.
|
||||
Retourne un tuple (trouve, voisin_avant, voisin_apres) :
|
||||
- trouve : True si le mot existe, False sinon
|
||||
- voisin_avant : le mot juste avant dans le dictionnaire (ou None)
|
||||
- voisin_apres : le mot juste après dans le dictionnaire (ou None)
|
||||
|
||||
Indication : à la fin de la boucle, si le mot n'est pas trouvé,
|
||||
b pointe vers le mot juste avant et a vers le mot juste après.
|
||||
"""
|
||||
a = 0
|
||||
b = len(dictionnaire) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
if dictionnaire[m] == mot:
|
||||
return (True, None, None)
|
||||
elif dictionnaire[m] < mot:
|
||||
a = m + 1
|
||||
else:
|
||||
b = m - 1
|
||||
# TODO : récupérer les voisins avec les indices a et b
|
||||
# Attention aux cas limites : b peut valoir -1, a peut dépasser la taille
|
||||
voisin_avant = None # TODO : dictionnaire[b] si b >= 0, sinon None
|
||||
voisin_apres = None # TODO : dictionnaire[a] si a < len(dictionnaire), sinon None
|
||||
return (False, voisin_avant, voisin_apres)
|
||||
|
||||
def ajouter_mot(dictionnaire, mot):
|
||||
"""
|
||||
Insère le mot à la bonne place pour maintenir l'ordre alphabétique.
|
||||
Principe : tri par insertion sur un seul élément.
|
||||
"""
|
||||
dictionnaire.append(mot)
|
||||
j = len(dictionnaire) - 1
|
||||
# TODO : décaler vers la gauche tant que le mot précédent est après le mot inséré
|
||||
while j > 0 and False: # TODO : remplacer False par la bonne condition
|
||||
dictionnaire[j] = dictionnaire[j - 1]
|
||||
j -= 1
|
||||
dictionnaire[j] = mot
|
||||
|
||||
def corriger(dictionnaire, mot):
|
||||
"""Affiche le résultat de la correction pour un mot donné."""
|
||||
trouve, avant, apres = verifier_avec_voisins(dictionnaire, mot)
|
||||
if trouve:
|
||||
print(f' "{mot}" : correct')
|
||||
else:
|
||||
suggestions = [v for v in [avant, apres] if v is not None]
|
||||
if suggestions:
|
||||
proposition = '" ou "'.join(suggestions)
|
||||
print(f' "{mot}" : mot inconnu. Vouliez-vous dire "{proposition}" ?')
|
||||
else:
|
||||
print(f' "{mot}" : mot inconnu, aucune suggestion.')
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Correcteur Orthographique ===")
|
||||
print(f"Dictionnaire : {len(dictionnaire)} mots\n")
|
||||
|
||||
# Tests de correction
|
||||
print("Tests automatiques :")
|
||||
for mot in ["python", "pithon", "algorithme", "algorythme", "variable", "varible", "zzz"]:
|
||||
corriger(dictionnaire, mot)
|
||||
|
||||
# Ajout d'un mot
|
||||
print()
|
||||
print("Ajout du mot 'reseau' (déjà présent) et 'robot' (nouveau) :")
|
||||
ajouter_mot(dictionnaire, "robot")
|
||||
print(f' "robot" ajouté. Vérification : {verifier(dictionnaire, "robot")}')
|
||||
|
||||
# Interface interactive
|
||||
print()
|
||||
print("--- Mode interactif (tapez 'fin' pour quitter) ---")
|
||||
while True:
|
||||
mot = input("Mot à vérifier : ").strip().lower()
|
||||
if mot == "fin":
|
||||
break
|
||||
corriger(dictionnaire, mot)
|
||||
50
algorithmes/mini-projets/05_correcteur/sujet.md
Normal file
50
algorithmes/mini-projets/05_correcteur/sujet.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 05 — Le Correcteur Orthographique
|
||||
|
||||
**Algorithmes :** Tri par insertion + Recherche dichotomique
|
||||
**Difficulté :** Moyen
|
||||
**Durée estimée :** 1h — 1h15
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous construisez un mini correcteur orthographique. Il dispose d'un dictionnaire de mots déjà triés par ordre alphabétique. Il peut vérifier si un mot existe, proposer des mots voisins en cas d'erreur, et permettre d'ajouter de nouveaux mots en maintenant l'ordre.
|
||||
|
||||
Ce projet utilise la dichotomie différemment des autres : au lieu de renvoyer seulement `True` ou `False`, elle doit aussi indiquer **où** le mot aurait dû se trouver, pour proposer des suggestions.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Vérifier un mot
|
||||
Implémentez `verifier(dictionnaire, mot)` qui retourne `True` si le mot est dans le dictionnaire, `False` sinon.
|
||||
|
||||
C'est une recherche dichotomique classique sur des chaînes de caractères.
|
||||
|
||||
> Rappel : en Python, les chaînes se comparent alphabétiquement : `"chat" < "chien"` → `True`.
|
||||
|
||||
### Étape 2 — Proposer des voisins
|
||||
Modifiez votre fonction pour qu'elle retourne aussi les **mots voisins** quand le mot est absent : le mot qui se trouverait juste avant et juste après dans le dictionnaire.
|
||||
|
||||
> **Indication** : à la fin de la dichotomie, si le mot n'est pas trouvé, les bornes `a` et `b` indiquent l'endroit où il aurait dû être inséré. Les mots en `dictionnaire[b]` et `dictionnaire[a]` sont ses voisins alphabétiques.
|
||||
|
||||
Retournez un tuple `(trouve, voisin_avant, voisin_apres)`.
|
||||
|
||||
### Étape 3 — Ajouter un mot
|
||||
Implémentez `ajouter_mot(dictionnaire, mot)` qui insère le mot à la bonne place pour maintenir l'ordre alphabétique.
|
||||
|
||||
> **Indication** : c'est le même principe que le tri par insertion, appliqué à un seul élément. Ajoutez le mot à la fin avec `append()`, puis décalez vers la gauche tant que le mot précédent est alphabétiquement après lui.
|
||||
|
||||
### Étape 4 — Interface de correction
|
||||
Complétez la boucle principale : l'utilisateur saisit un mot, le programme répond :
|
||||
- `"chat" : correct`
|
||||
- `"chzt" : mot inconnu. Vouliez-vous dire "chute" ou "chat" ?`
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez une fonction `charger_mots(fichier)` qui lit un fichier texte (un mot par ligne) et retourne la liste triée. Testez avec un vrai fichier de mots français.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme fonctionnel avec la suggestion de voisins
|
||||
- Réponse : pourquoi les bornes `a` et `b` à la fin de la dichotomie indiquent-elles le point d'insertion ?
|
||||
BIN
algorithmes/mini-projets/06_bibliotheque.zip
Normal file
BIN
algorithmes/mini-projets/06_bibliotheque.zip
Normal file
Binary file not shown.
93
algorithmes/mini-projets/06_bibliotheque/starter.py
Normal file
93
algorithmes/mini-projets/06_bibliotheque/starter.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# Projet 06 — La Bibliothèque
|
||||
# Algorithmes : Tri par sélection + Recherche dichotomique
|
||||
|
||||
livres = [
|
||||
{"titre": "le seigneur des anneaux", "auteur": "tolkien", "annee": 1954, "genre": "Fantasy", "pages": 1200},
|
||||
{"titre": "1984", "auteur": "orwell", "annee": 1949, "genre": "Dystopie", "pages": 328},
|
||||
{"titre": "dune", "auteur": "herbert", "annee": 1965, "genre": "SF", "pages": 688},
|
||||
{"titre": "le petit prince", "auteur": "exupery", "annee": 1943, "genre": "Conte", "pages": 96},
|
||||
{"titre": "fondation", "auteur": "asimov", "annee": 1951, "genre": "SF", "pages": 255},
|
||||
{"titre": "harry potter t1", "auteur": "rowling", "annee": 1997, "genre": "Fantasy", "pages": 309},
|
||||
{"titre": "fahrenheit 451", "auteur": "bradbury", "annee": 1953, "genre": "Dystopie", "pages": 158},
|
||||
{"titre": "l'etranger", "auteur": "camus", "annee": 1942, "genre": "Littérature","pages": 123},
|
||||
{"titre": "neuromancien", "auteur": "gibson", "annee": 1984, "genre": "SF", "pages": 271},
|
||||
{"titre": "brave new world", "auteur": "huxley", "annee": 1932, "genre": "Dystopie", "pages": 311},
|
||||
]
|
||||
|
||||
def afficher_catalogue(livres):
|
||||
"""Affiche le catalogue sous forme de liste numérotée."""
|
||||
print(f"\n {'Titre':<30} {'Auteur':<12} {'Année':>5} {'Pages':>6}")
|
||||
print(" " + "-" * 58)
|
||||
for i, l in enumerate(livres, 1):
|
||||
print(f" {i:>2}. {l['titre']:<30} {l['auteur']:<12} {l['annee']:>5} {l['pages']:>6} p.")
|
||||
print()
|
||||
|
||||
def afficher_fiche(livre):
|
||||
"""Affiche la fiche complète d'un livre."""
|
||||
# TODO : afficher toutes les informations du livre de façon lisible
|
||||
pass
|
||||
|
||||
def tri_selection_livres(livres):
|
||||
"""Trie les livres par titre alphabétique (tri par sélection)."""
|
||||
n = len(livres)
|
||||
for i in range(n):
|
||||
mini = i
|
||||
for j in range(i + 1, n):
|
||||
# TODO : comparer les titres
|
||||
if ...:
|
||||
mini = j
|
||||
livres[i], livres[mini] = livres[mini], livres[i]
|
||||
return livres
|
||||
|
||||
def rechercher_titre(livres_tries, titre):
|
||||
"""
|
||||
Recherche dichotomique par titre exact (en minuscules).
|
||||
Retourne le livre si trouvé, None sinon.
|
||||
"""
|
||||
a = 0
|
||||
b = len(livres_tries) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
titre_m = livres_tries[m]["titre"]
|
||||
if titre_m == titre:
|
||||
return livres_tries[m]
|
||||
elif titre_m < titre:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return None
|
||||
|
||||
def statistiques(livres):
|
||||
"""Affiche des statistiques sur le catalogue."""
|
||||
n = len(livres)
|
||||
total_pages = sum(l["pages"] for l in livres)
|
||||
# TODO : trouver le livre avec le moins de pages et le plus de pages
|
||||
# Indice : utilise ton tri par sélection sur une copie triée par pages !
|
||||
print(f"\nStatistiques du catalogue ({n} livres) :")
|
||||
print(f" Moyenne de pages : {total_pages // n} pages")
|
||||
# TODO : afficher le plus court et le plus long
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Catalogue de la Bibliothèque ===")
|
||||
print("\nAvant tri :")
|
||||
afficher_catalogue(livres)
|
||||
|
||||
tri_selection_livres(livres)
|
||||
|
||||
print("Après tri alphabétique :")
|
||||
afficher_catalogue(livres)
|
||||
|
||||
# Tests de recherche
|
||||
print("Recherches :")
|
||||
for titre in ["1984", "dune", "le comte de monte cristo"]:
|
||||
resultat = rechercher_titre(livres, titre)
|
||||
if resultat:
|
||||
print(f" '{titre}' → trouvé !")
|
||||
afficher_fiche(resultat)
|
||||
else:
|
||||
print(f" '{titre}' → absent du catalogue")
|
||||
|
||||
statistiques(livres)
|
||||
45
algorithmes/mini-projets/06_bibliotheque/sujet.md
Normal file
45
algorithmes/mini-projets/06_bibliotheque/sujet.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# 06 — La Bibliothèque
|
||||
|
||||
**Algorithmes :** Tri par sélection + Recherche dichotomique
|
||||
**Difficulté :** Moyen
|
||||
**Durée estimée :** 1h — 1h15
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous gérez le catalogue d'une bibliothèque. Les livres doivent être triés par **titre alphabétique** pour qu'on puisse les retrouver rapidement. Vous utiliserez le tri par sélection pour trier, et la dichotomie pour chercher.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Trier par titre
|
||||
Implémentez `tri_selection_livres(livres)` qui trie par `"titre"` (ordre alphabétique).
|
||||
|
||||
> **Rappel** : en Python, `"Alice" < "Zorro"` → `True`. Vous pouvez comparer des chaînes directement.
|
||||
|
||||
### Étape 2 — Recherche dichotomique
|
||||
Implémentez `rechercher_titre(livres_tries, titre)` qui retourne le livre si trouvé, `None` sinon.
|
||||
|
||||
> **Attention** : la comparaison doit être exacte (majuscules comprises). Pour simplifier, tout est déjà en minuscules dans les données.
|
||||
|
||||
### Étape 3 — Affichage enrichi
|
||||
Implémentez `afficher_fiche(livre)` qui affiche toutes les informations d'un livre de façon lisible (titre, auteur, année, genre, pages).
|
||||
|
||||
### Étape 4 — Statistiques
|
||||
Ajoutez une fonction `statistiques(livres)` qui affiche :
|
||||
- Le nombre de livres
|
||||
- Le livre le plus court et le plus long (en pages)
|
||||
- La moyenne de pages
|
||||
|
||||
> **Indication** : une fois la liste triée par titre, vous pouvez utiliser une boucle simple pour les stats. Ou bien trier une copie par pages avec votre tri !
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez la possibilité de trier aussi par **année** ou par **nombre de pages**, et de rechercher tous les livres d'un **même auteur** (recherche linéaire cette fois — pourquoi ne peut-on pas utiliser la dichotomie ici ?).
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme fonctionnel
|
||||
- Réponse : pour chercher tous les livres d'un auteur, pourquoi la dichotomie est-elle inadaptée ?
|
||||
109
algorithmes/mini-projets/07_meteo 2/starter.py
Normal file
109
algorithmes/mini-projets/07_meteo 2/starter.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# Projet 07 — La Météo
|
||||
# Algorithmes : Tri par insertion + Recherche dichotomique
|
||||
|
||||
# Relevés du mois de mars : (numéro du jour, température en °C)
|
||||
releves = [
|
||||
(1, 12.3), (2, 8.7), (3, 14.1), (4, 11.5), (5, 9.2),
|
||||
(6, 7.8), (7, 13.4), (8, 15.6), (9, 10.1), (10, 6.5),
|
||||
(11, 5.2), (12, 9.8), (13, 12.7),(14, 16.3),(15, 18.1),
|
||||
(16, 14.5),(17, 11.2),(18, 8.9), (19, 7.3), (20, 10.5),
|
||||
(21, 13.8),(22, 17.2),(23, 19.4),(24, 15.1),(25, 12.0),
|
||||
(26, 9.5), (27, 11.8),(28, 14.2),(29, 16.7),(30, 18.9),
|
||||
(31, 13.3),
|
||||
]
|
||||
|
||||
def afficher_releves(releves, nb=10):
|
||||
"""Affiche les nb premiers relevés."""
|
||||
print(f"\n {'Jour':>5} {'Température':>12}")
|
||||
print(" " + "-" * 20)
|
||||
for jour, temp in releves[:nb]:
|
||||
print(f" Jour {jour:>2} {temp:>8.1f} °C")
|
||||
if len(releves) > nb:
|
||||
print(f" ... ({len(releves) - nb} relevés supplémentaires)")
|
||||
print()
|
||||
|
||||
def tri_insertion_temperatures(tab):
|
||||
"""
|
||||
Trie les relevés par température croissante (tri par insertion).
|
||||
Chaque élément est un tuple (jour, temperature).
|
||||
On trie selon le deuxième élément du tuple.
|
||||
"""
|
||||
for i in range(1, len(tab)):
|
||||
x = tab[i]
|
||||
j = i
|
||||
# TODO : comparer tab[j-1][1] et x[1]
|
||||
while j > 0 and ...:
|
||||
tab[j] = tab[j - 1]
|
||||
j -= 1
|
||||
tab[j] = x
|
||||
return tab
|
||||
|
||||
def statistiques(tab_trie):
|
||||
"""Affiche les statistiques à partir des relevés triés."""
|
||||
n = len(tab_trie)
|
||||
min_releve = tab_trie[0]
|
||||
max_releve = tab_trie[n - 1]
|
||||
mediane = tab_trie[n // 2]
|
||||
|
||||
print("Statistiques du mois :")
|
||||
print(f" Minimum : {min_releve[1]:.1f} °C (jour {min_releve[0]})")
|
||||
print(f" Maximum : {max_releve[1]:.1f} °C (jour {max_releve[0]})")
|
||||
print(f" Médiane : {mediane[1]:.1f} °C (jour {mediane[0]})")
|
||||
# TODO : ajouter la moyenne
|
||||
print()
|
||||
|
||||
def temperature_atteinte(tab_trie, t):
|
||||
"""
|
||||
Recherche dichotomique : retourne True si la température t
|
||||
a été relevée au cours du mois (comparaison exacte).
|
||||
"""
|
||||
a = 0
|
||||
b = len(tab_trie) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
temp_m = tab_trie[m][1]
|
||||
if temp_m == t:
|
||||
return True
|
||||
elif temp_m < t:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return False
|
||||
|
||||
def histogramme(tab_trie):
|
||||
"""Affiche un histogramme horizontal des températures (arrondi à l'entier)."""
|
||||
# Compter les occurrences par degré entier
|
||||
compteur = {}
|
||||
for _, temp in tab_trie:
|
||||
degre = int(temp)
|
||||
compteur[degre] = compteur.get(degre, 0) + 1
|
||||
|
||||
print("Histogramme des températures :")
|
||||
for degre in sorted(compteur):
|
||||
barre = "█" * compteur[degre]
|
||||
print(f" {degre:>3}°C | {barre} ({compteur[degre]})")
|
||||
print()
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Analyse Météo — Mars ===")
|
||||
print("\nRelevés originaux (10 premiers) :")
|
||||
afficher_releves(releves, nb=5)
|
||||
|
||||
# Trier une copie pour ne pas perdre l'ordre chronologique
|
||||
releves_tries = releves[:]
|
||||
tri_insertion_temperatures(releves_tries)
|
||||
|
||||
print("Relevés triés par température :")
|
||||
afficher_releves(releves_tries, nb=5)
|
||||
|
||||
statistiques(releves_tries)
|
||||
histogramme(releves_tries)
|
||||
|
||||
# Tests de recherche
|
||||
print("Recherches :")
|
||||
for t in [5.2, 15.0, 19.4, 20.0]:
|
||||
present = temperature_atteinte(releves_tries, t)
|
||||
print(f" {t}°C relevé ce mois-ci ? {'Oui' if present else 'Non'}")
|
||||
54
algorithmes/mini-projets/07_meteo 2/sujet.md
Normal file
54
algorithmes/mini-projets/07_meteo 2/sujet.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# 07 — La Météo
|
||||
|
||||
**Algorithmes :** Tri par insertion + Recherche dichotomique
|
||||
**Difficulté :** Moyen
|
||||
**Durée estimée :** 1h — 1h15
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous analysez les relevés de température d'un mois complet. Vous voulez les trier, calculer des statistiques, et savoir rapidement si une température précise a été atteinte ce mois-ci.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Trier les températures
|
||||
Implémentez `tri_insertion_temperatures(tab)` qui trie la liste de relevés par **température croissante**.
|
||||
|
||||
Chaque relevé est un tuple `(jour, temperature)`. On trie selon la température (le deuxième élément).
|
||||
|
||||
> **Indication** : comparez `tab[j-1][1]` et `x[1]` (le deuxième élément du tuple).
|
||||
|
||||
### Étape 2 — Statistiques de base
|
||||
Implémentez `statistiques(tab_trie)` qui affiche :
|
||||
- La température **minimale** et le jour où elle a été relevée
|
||||
- La température **maximale** et le jour où elle a été relevée
|
||||
- La **médiane** (la valeur au milieu une fois triée)
|
||||
|
||||
> Rappel : la médiane d'une liste triée de taille n est à l'indice `n // 2`.
|
||||
|
||||
### Étape 3 — Recherche dichotomique
|
||||
Implémentez `temperature_atteinte(tab_trie, t)` : retourne `True` si la température `t` a été relevée, `False` sinon.
|
||||
|
||||
> **Attention** : les relevés sont triés par température. La dichotomie doit comparer `tab[m][1]` (la valeur) avec `t`.
|
||||
|
||||
### Étape 4 — Visualisation ASCII
|
||||
Implémentez `histogramme(tab_trie)` qui affiche un histogramme horizontal des températures.
|
||||
|
||||
```
|
||||
5°C | ##
|
||||
10°C | #####
|
||||
15°C | ########
|
||||
...
|
||||
```
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez une fonction qui regroupe les relevés par **tranche de 5°C** et compte combien de jours tombent dans chaque tranche.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme complet avec statistiques et recherche
|
||||
- Réponse : pourquoi le tri par insertion est-il particulièrement efficace si les données sont **déjà presque triées** ?
|
||||
BIN
algorithmes/mini-projets/07_meteo.zip
Normal file
BIN
algorithmes/mini-projets/07_meteo.zip
Normal file
Binary file not shown.
109
algorithmes/mini-projets/07_meteo/starter.py
Normal file
109
algorithmes/mini-projets/07_meteo/starter.py
Normal file
@@ -0,0 +1,109 @@
|
||||
# Projet 07 — La Météo
|
||||
# Algorithmes : Tri par insertion + Recherche dichotomique
|
||||
|
||||
# Relevés du mois de mars : (numéro du jour, température en °C)
|
||||
releves = [
|
||||
(1, 12.3), (2, 8.7), (3, 14.1), (4, 11.5), (5, 9.2),
|
||||
(6, 7.8), (7, 13.4), (8, 15.6), (9, 10.1), (10, 6.5),
|
||||
(11, 5.2), (12, 9.8), (13, 12.7),(14, 16.3),(15, 18.1),
|
||||
(16, 14.5),(17, 11.2),(18, 8.9), (19, 7.3), (20, 10.5),
|
||||
(21, 13.8),(22, 17.2),(23, 19.4),(24, 15.1),(25, 12.0),
|
||||
(26, 9.5), (27, 11.8),(28, 14.2),(29, 16.7),(30, 18.9),
|
||||
(31, 13.3),
|
||||
]
|
||||
|
||||
def afficher_releves(releves, nb=10):
|
||||
"""Affiche les nb premiers relevés."""
|
||||
print(f"\n {'Jour':>5} {'Température':>12}")
|
||||
print(" " + "-" * 20)
|
||||
for jour, temp in releves[:nb]:
|
||||
print(f" Jour {jour:>2} {temp:>8.1f} °C")
|
||||
if len(releves) > nb:
|
||||
print(f" ... ({len(releves) - nb} relevés supplémentaires)")
|
||||
print()
|
||||
|
||||
def tri_insertion_temperatures(tab):
|
||||
"""
|
||||
Trie les relevés par température croissante (tri par insertion).
|
||||
Chaque élément est un tuple (jour, temperature).
|
||||
On trie selon le deuxième élément du tuple.
|
||||
"""
|
||||
for i in range(1, len(tab)):
|
||||
x = tab[i]
|
||||
j = i
|
||||
# TODO : comparer tab[j-1][1] et x[1]
|
||||
while j > 0 and ...:
|
||||
tab[j] = tab[j - 1]
|
||||
j -= 1
|
||||
tab[j] = x
|
||||
return tab
|
||||
|
||||
def statistiques(tab_trie):
|
||||
"""Affiche les statistiques à partir des relevés triés."""
|
||||
n = len(tab_trie)
|
||||
min_releve = tab_trie[0]
|
||||
max_releve = tab_trie[n - 1]
|
||||
mediane = tab_trie[n // 2]
|
||||
|
||||
print("Statistiques du mois :")
|
||||
print(f" Minimum : {min_releve[1]:.1f} °C (jour {min_releve[0]})")
|
||||
print(f" Maximum : {max_releve[1]:.1f} °C (jour {max_releve[0]})")
|
||||
print(f" Médiane : {mediane[1]:.1f} °C (jour {mediane[0]})")
|
||||
# TODO : ajouter la moyenne
|
||||
print()
|
||||
|
||||
def temperature_atteinte(tab_trie, t):
|
||||
"""
|
||||
Recherche dichotomique : retourne True si la température t
|
||||
a été relevée au cours du mois (comparaison exacte).
|
||||
"""
|
||||
a = 0
|
||||
b = len(tab_trie) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
temp_m = tab_trie[m][1]
|
||||
if temp_m == t:
|
||||
return True
|
||||
elif temp_m < t:
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# TODO
|
||||
pass
|
||||
return False
|
||||
|
||||
def histogramme(tab_trie):
|
||||
"""Affiche un histogramme horizontal des températures (arrondi à l'entier)."""
|
||||
# Compter les occurrences par degré entier
|
||||
compteur = {}
|
||||
for _, temp in tab_trie:
|
||||
degre = int(temp)
|
||||
compteur[degre] = compteur.get(degre, 0) + 1
|
||||
|
||||
print("Histogramme des températures :")
|
||||
for degre in sorted(compteur):
|
||||
barre = "█" * compteur[degre]
|
||||
print(f" {degre:>3}°C | {barre} ({compteur[degre]})")
|
||||
print()
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Analyse Météo — Mars ===")
|
||||
print("\nRelevés originaux (10 premiers) :")
|
||||
afficher_releves(releves, nb=5)
|
||||
|
||||
# Trier une copie pour ne pas perdre l'ordre chronologique
|
||||
releves_tries = releves[:]
|
||||
tri_insertion_temperatures(releves_tries)
|
||||
|
||||
print("Relevés triés par température :")
|
||||
afficher_releves(releves_tries, nb=5)
|
||||
|
||||
statistiques(releves_tries)
|
||||
histogramme(releves_tries)
|
||||
|
||||
# Tests de recherche
|
||||
print("Recherches :")
|
||||
for t in [5.2, 15.0, 19.4, 20.0]:
|
||||
present = temperature_atteinte(releves_tries, t)
|
||||
print(f" {t}°C relevé ce mois-ci ? {'Oui' if present else 'Non'}")
|
||||
54
algorithmes/mini-projets/07_meteo/sujet.md
Normal file
54
algorithmes/mini-projets/07_meteo/sujet.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# 07 — La Météo
|
||||
|
||||
**Algorithmes :** Tri par insertion + Recherche dichotomique
|
||||
**Difficulté :** Moyen
|
||||
**Durée estimée :** 1h — 1h15
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Vous analysez les relevés de température d'un mois complet. Vous voulez les trier, calculer des statistiques, et savoir rapidement si une température précise a été atteinte ce mois-ci.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Trier les températures
|
||||
Implémentez `tri_insertion_temperatures(tab)` qui trie la liste de relevés par **température croissante**.
|
||||
|
||||
Chaque relevé est un tuple `(jour, temperature)`. On trie selon la température (le deuxième élément).
|
||||
|
||||
> **Indication** : comparez `tab[j-1][1]` et `x[1]` (le deuxième élément du tuple).
|
||||
|
||||
### Étape 2 — Statistiques de base
|
||||
Implémentez `statistiques(tab_trie)` qui affiche :
|
||||
- La température **minimale** et le jour où elle a été relevée
|
||||
- La température **maximale** et le jour où elle a été relevée
|
||||
- La **médiane** (la valeur au milieu une fois triée)
|
||||
|
||||
> Rappel : la médiane d'une liste triée de taille n est à l'indice `n // 2`.
|
||||
|
||||
### Étape 3 — Recherche dichotomique
|
||||
Implémentez `temperature_atteinte(tab_trie, t)` : retourne `True` si la température `t` a été relevée, `False` sinon.
|
||||
|
||||
> **Attention** : les relevés sont triés par température. La dichotomie doit comparer `tab[m][1]` (la valeur) avec `t`.
|
||||
|
||||
### Étape 4 — Visualisation ASCII
|
||||
Implémentez `histogramme(tab_trie)` qui affiche un histogramme horizontal des températures.
|
||||
|
||||
```
|
||||
5°C | ##
|
||||
10°C | #####
|
||||
15°C | ########
|
||||
...
|
||||
```
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez une fonction qui regroupe les relevés par **tranche de 5°C** et compte combien de jours tombent dans chaque tranche.
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme complet avec statistiques et recherche
|
||||
- Réponse : pourquoi le tri par insertion est-il particulièrement efficace si les données sont **déjà presque triées** ?
|
||||
BIN
algorithmes/mini-projets/08_course_algos.zip
Normal file
BIN
algorithmes/mini-projets/08_course_algos.zip
Normal file
Binary file not shown.
92
algorithmes/mini-projets/08_course_algos/starter.py
Normal file
92
algorithmes/mini-projets/08_course_algos/starter.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# Projet 08 — La Course des Algorithmes
|
||||
# Comparer les performances du tri par insertion et du tri par sélection
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Étape 1 : recopie ici tes deux fonctions de tri
|
||||
# -------------------------------------------------------
|
||||
|
||||
def tri_insertion(tab):
|
||||
# TODO : recopier depuis le cours
|
||||
pass
|
||||
|
||||
def tri_selection(tab):
|
||||
# TODO : recopier depuis le cours
|
||||
pass
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Outils de mesure (déjà fournis)
|
||||
# -------------------------------------------------------
|
||||
|
||||
def mesurer_temps(fonction, tab):
|
||||
"""
|
||||
Mesure le temps d'exécution de fonction(tab) en millisecondes.
|
||||
Travaille sur une copie pour ne pas modifier l'original.
|
||||
"""
|
||||
copie = tab[:]
|
||||
debut = time.time()
|
||||
fonction(copie)
|
||||
fin = time.time()
|
||||
return round((fin - debut) * 1000, 3) # résultat en ms
|
||||
|
||||
def generer_liste(n, mode="aleatoire"):
|
||||
"""
|
||||
Génère une liste de n entiers selon le mode :
|
||||
- "aleatoire" : ordre aléatoire
|
||||
- "trie" : déjà triée (croissant)
|
||||
- "inverse" : triée à l'envers (décroissant)
|
||||
"""
|
||||
if mode == "aleatoire":
|
||||
return random.sample(range(n * 10), n)
|
||||
elif mode == "trie":
|
||||
return list(range(n))
|
||||
elif mode == "inverse":
|
||||
return list(range(n, 0, -1))
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Étape 3 : tableau comparatif selon la taille
|
||||
# -------------------------------------------------------
|
||||
|
||||
def comparer_tailles():
|
||||
tailles = [100, 500, 1000, 2000, 5000]
|
||||
print("=== Comparaison par taille (liste aléatoire) ===\n")
|
||||
print(f" {'n':>6} {'Insertion (ms)':>16} {'Sélection (ms)':>16} {'Vainqueur':>10}")
|
||||
print(" " + "-" * 55)
|
||||
|
||||
for n in tailles:
|
||||
liste = generer_liste(n, "aleatoire")
|
||||
t_insertion = mesurer_temps(tri_insertion, liste)
|
||||
t_selection = mesurer_temps(tri_selection, liste)
|
||||
vainqueur = "Insertion" if t_insertion < t_selection else "Sélection"
|
||||
print(f" {n:>6} {t_insertion:>16.3f} {t_selection:>16.3f} {vainqueur:>10}")
|
||||
print()
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Étape 4 : tableau comparatif selon le mode (n fixé)
|
||||
# -------------------------------------------------------
|
||||
|
||||
def comparer_modes(n=1000):
|
||||
modes = ["aleatoire", "trie", "inverse"]
|
||||
print(f"=== Comparaison par configuration (n = {n}) ===\n")
|
||||
print(f" {'Mode':<12} {'Insertion (ms)':>16} {'Sélection (ms)':>16} {'Vainqueur':>10}")
|
||||
print(" " + "-" * 60)
|
||||
|
||||
for mode in modes:
|
||||
liste = generer_liste(n, mode)
|
||||
t_insertion = mesurer_temps(tri_insertion, liste)
|
||||
t_selection = mesurer_temps(tri_selection, liste)
|
||||
vainqueur = "Insertion" if t_insertion < t_selection else "Sélection"
|
||||
print(f" {mode:<12} {t_insertion:>16.3f} {t_selection:>16.3f} {vainqueur:>10}")
|
||||
print()
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Programme principal
|
||||
# -------------------------------------------------------
|
||||
|
||||
comparer_tailles()
|
||||
comparer_modes(n=1000)
|
||||
|
||||
print("Conclusion :")
|
||||
print(" TODO : écris tes observations ici")
|
||||
49
algorithmes/mini-projets/08_course_algos/sujet.md
Normal file
49
algorithmes/mini-projets/08_course_algos/sujet.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# 08 — La Course des Algorithmes
|
||||
|
||||
**Algorithmes :** Tri par insertion vs Tri par sélection (comparaison)
|
||||
**Difficulté :** Difficile
|
||||
**Durée estimée :** 1h15 — 1h30
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
On sait que les deux tris ont une complexité **quadratique** (O(n²)) dans le pire des cas. Mais en pratique, se comportent-ils vraiment pareil ? C'est ce que vous allez mesurer.
|
||||
|
||||
Vous allez tester les deux algorithmes sur différentes tailles de listes et dans différentes configurations, afficher les résultats et tirer des conclusions.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Copier les deux tris
|
||||
Recopiez dans le starter vos fonctions `tri_insertion(tab)` et `tri_selection(tab)` qui fonctionnent sur des listes d'entiers.
|
||||
|
||||
### Étape 2 — Mesurer le temps
|
||||
La fonction `mesurer_temps(fonction, tab)` est déjà fournie. Elle prend une **copie** de la liste pour ne pas la modifier et mesure le temps en millisecondes.
|
||||
|
||||
> **Important** : toujours travailler sur une **copie** (`tab[:]`) pour que les deux algos partent du même état.
|
||||
|
||||
### Étape 3 — Tester sur différentes tailles
|
||||
Testez pour `n ∈ [100, 500, 1000, 2000, 5000]` avec une liste **aléatoire**. Affichez un tableau comparatif.
|
||||
|
||||
### Étape 4 — Tester les cas particuliers
|
||||
Pour `n = 1000`, testez :
|
||||
- Liste aléatoire
|
||||
- Liste **déjà triée** (croissant)
|
||||
- Liste **triée à l'envers** (décroissant)
|
||||
|
||||
Affichez les résultats. Quel algorithme est avantagé selon le cas ?
|
||||
|
||||
### Étape 5 — Tracer un graphique (extension)
|
||||
Si vous connaissez `matplotlib`, tracez les courbes de temps en fonction de n pour les deux algorithmes.
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le programme avec le tableau comparatif
|
||||
- Une conclusion écrite : dans quels cas préférez-vous le tri par insertion ? Le tri par sélection ? Justifiez avec vos mesures.
|
||||
BIN
algorithmes/mini-projets/09_generateur_web.zip
Normal file
BIN
algorithmes/mini-projets/09_generateur_web.zip
Normal file
Binary file not shown.
163
algorithmes/mini-projets/09_generateur_web/starter.py
Normal file
163
algorithmes/mini-projets/09_generateur_web/starter.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# Projet 09 — Le Générateur Web
|
||||
# Algorithmes : Tri par insertion + Dichotomie → page HTML/CSS
|
||||
|
||||
import webbrowser
|
||||
|
||||
jeux = [
|
||||
{"titre": "The Legend of Zelda: BotW", "studio": "Nintendo", "annee": 2017, "score": 97},
|
||||
{"titre": "Red Dead Redemption 2", "studio": "Rockstar", "annee": 2018, "score": 97},
|
||||
{"titre": "Grand Theft Auto V", "studio": "Rockstar", "annee": 2013, "score": 97},
|
||||
{"titre": "The Witcher 3", "studio": "CD Projekt", "annee": 2015, "score": 93},
|
||||
{"titre": "Elden Ring", "studio": "FromSoftware", "annee": 2022, "score": 96},
|
||||
{"titre": "Minecraft", "studio": "Mojang", "annee": 2011, "score": 93},
|
||||
{"titre": "Portal 2", "studio": "Valve", "annee": 2011, "score": 95},
|
||||
{"titre": "Hollow Knight", "studio": "Team Cherry", "annee": 2017, "score": 90},
|
||||
{"titre": "Hades", "studio": "Supergiant", "annee": 2020, "score": 93},
|
||||
{"titre": "Celeste", "studio": "Maddy Makes", "annee": 2018, "score": 94},
|
||||
{"titre": "Disco Elysium", "studio": "ZA/UM", "annee": 2019, "score": 97},
|
||||
{"titre": "Death Stranding", "studio": "Kojima Prod.", "annee": 2019, "score": 82},
|
||||
]
|
||||
|
||||
def tri_insertion_jeux(jeux):
|
||||
"""
|
||||
Trie les jeux par score DÉCROISSANT (tri par insertion).
|
||||
Le meilleur score doit être en premier.
|
||||
"""
|
||||
for i in range(1, len(jeux)):
|
||||
x = jeux[i]
|
||||
j = i
|
||||
# TODO : condition pour trier par ordre décroissant
|
||||
# Indice : pour l'ordre décroissant, on décale quand le score précédent est INFÉRIEUR
|
||||
while j > 0 and ...:
|
||||
jeux[j] = jeux[j - 1]
|
||||
j -= 1
|
||||
jeux[j] = x
|
||||
return jeux
|
||||
|
||||
def rechercher_score(jeux_tries, score):
|
||||
"""
|
||||
Recherche dichotomique d'un jeu par score exact.
|
||||
ATTENTION : la liste est triée par score DÉCROISSANT.
|
||||
Les comparaisons < et > sont inversées par rapport au cours !
|
||||
"""
|
||||
a = 0
|
||||
b = len(jeux_tries) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
score_m = jeux_tries[m]["score"]
|
||||
if score_m == score:
|
||||
return jeux_tries[m]
|
||||
elif score_m > score:
|
||||
# Le score du milieu est trop grand → chercher à droite
|
||||
# TODO
|
||||
pass
|
||||
else:
|
||||
# Le score du milieu est trop petit → chercher à gauche
|
||||
# TODO
|
||||
pass
|
||||
return None
|
||||
|
||||
def generer_html(jeux_tries, fichier="classement.html"):
|
||||
"""Génère une page HTML affichant le classement."""
|
||||
COULEURS_PODIUM = ["#FFD700", "#C0C0C0", "#CD7F32"] # or, argent, bronze
|
||||
|
||||
lignes_html = ""
|
||||
for i, jeu in enumerate(jeux_tries, 1):
|
||||
if i <= 3:
|
||||
bg = f'style="background-color: {COULEURS_PODIUM[i-1]}; font-weight: bold;"'
|
||||
else:
|
||||
bg = 'style="background-color: #f9f9f9;"' if i % 2 == 0 else ""
|
||||
|
||||
lignes_html += f"""
|
||||
<tr {bg}>
|
||||
<td>{i}</td>
|
||||
<td>{jeu['titre']}</td>
|
||||
<td>{jeu['studio']}</td>
|
||||
<td>{jeu['annee']}</td>
|
||||
<td>{jeu['score']}/100</td>
|
||||
</tr>"""
|
||||
|
||||
html = f"""<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Top Jeux Vidéo</title>
|
||||
<style>
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 40px auto;
|
||||
background: #1a1a2e;
|
||||
color: #eee;
|
||||
}}
|
||||
h1 {{
|
||||
text-align: center;
|
||||
color: #FFD700;
|
||||
font-size: 2em;
|
||||
}}
|
||||
table {{
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: white;
|
||||
color: #333;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
|
||||
}}
|
||||
th {{
|
||||
background: #16213e;
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
text-align: left;
|
||||
}}
|
||||
td {{
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}}
|
||||
tr:last-child td {{ border-bottom: none; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>🎮 Classement des meilleurs jeux</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Titre</th>
|
||||
<th>Studio</th>
|
||||
<th>Année</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{lignes_html}
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="text-align:center; margin-top:20px; color:#aaa;">
|
||||
Généré par Python avec tri par insertion — NSI Première
|
||||
</p>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
with open(fichier, "w", encoding="utf-8") as f:
|
||||
f.write(html)
|
||||
print(f"Page générée : {fichier}")
|
||||
|
||||
|
||||
# --- Programme principal ---
|
||||
print("=== Générateur de classement HTML ===")
|
||||
|
||||
tri_insertion_jeux(jeux)
|
||||
|
||||
print("Classement (5 premiers) :")
|
||||
for i, jeu in enumerate(jeux[:5], 1):
|
||||
print(f" {i}. {jeu['titre']} — {jeu['score']}/100")
|
||||
|
||||
# Recherche
|
||||
jeu_trouve = rechercher_score(jeux, 95)
|
||||
if jeu_trouve:
|
||||
print(f"\nJeu avec score 95 : {jeu_trouve['titre']}")
|
||||
|
||||
# Génération HTML
|
||||
generer_html(jeux)
|
||||
webbrowser.open("classement.html")
|
||||
51
algorithmes/mini-projets/09_generateur_web/sujet.md
Normal file
51
algorithmes/mini-projets/09_generateur_web/sujet.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 09 — Le Générateur Web
|
||||
|
||||
**Algorithmes :** Tri par insertion + Recherche dichotomique → génération HTML/CSS
|
||||
**Difficulté :** Difficile
|
||||
**Durée estimée :** 1h15 — 1h30
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Sans JavaScript, une page web ne peut pas exécuter d'algorithme. Mais Python peut **générer** une page HTML ! Vous allez trier des données en Python, puis produire un fichier `.html` affichant le résultat avec un style CSS.
|
||||
|
||||
---
|
||||
|
||||
## Étapes
|
||||
|
||||
### Étape 1 — Trier les données
|
||||
Implémentez `tri_insertion_jeux(jeux)` qui trie la liste de jeux vidéo par **score décroissant** (le meilleur en premier).
|
||||
|
||||
> **Indication** : pour trier par ordre **décroissant**, inversez la condition : `tab[j-1][1] < x[1]` au lieu de `>`.
|
||||
|
||||
### Étape 2 — Recherche dichotomique
|
||||
Implémentez `rechercher_score(jeux_tries, score)` qui retourne le jeu avec ce score exact, ou `None`.
|
||||
|
||||
> Attention : la liste est triée par score **décroissant**. La dichotomie doit être adaptée (les comparaisons `<` et `>` sont inversées).
|
||||
|
||||
### Étape 3 — Générer la page HTML
|
||||
Implémentez `generer_html(jeux_tries, fichier)` qui écrit un fichier `.html` contenant un tableau du classement, stylisé avec du CSS intégré.
|
||||
|
||||
La page doit afficher au minimum :
|
||||
- Le rang, le titre, le studio, l'année et le score de chaque jeu
|
||||
- Les 3 premiers avec une couleur distincte (or, argent, bronze)
|
||||
- Un titre et un style propre
|
||||
|
||||
### Étape 4 — Ouvrir la page automatiquement
|
||||
À la fin du programme, ouvrez la page générée dans le navigateur avec :
|
||||
|
||||
```python
|
||||
import webbrowser
|
||||
webbrowser.open("classement.html")
|
||||
```
|
||||
|
||||
### Étape 5 — Extension (si vous avez le temps)
|
||||
Ajoutez un deuxième tableau sur la même page : les jeux triés par **année de sortie** (vous pouvez faire un deuxième tri sur une copie).
|
||||
|
||||
---
|
||||
|
||||
## Ce que vous devez rendre
|
||||
- Le fichier `starter.py` qui tourne et génère `classement.html`
|
||||
- La page `classement.html` ouverte dans le navigateur
|
||||
- Réponse : pourquoi Python peut-il générer du HTML, alors qu'HTML ne peut pas exécuter Python ?
|
||||
238
algorithmes/mini-projets/AIDE.md
Normal file
238
algorithmes/mini-projets/AIDE.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# Guide enseignant — Questions fréquentes par projet
|
||||
|
||||
---
|
||||
|
||||
## Questions communes à tous les projets
|
||||
|
||||
**"On peut utiliser `sort()` ou `sorted()` ?"**
|
||||
Non. L'objectif est précisément d'implémenter les algorithmes vus en cours. Ces fonctions intégrées existent, mais leur utilisation ici invalide le travail demandé.
|
||||
|
||||
**"Comment copier une liste sans modifier l'original ?"**
|
||||
```python
|
||||
copie = ma_liste[:] # ou list(ma_liste)
|
||||
```
|
||||
Ne pas faire `copie = ma_liste` : les deux variables pointeraient sur le même objet en mémoire.
|
||||
|
||||
**"La dichotomie ne fonctionne pas, j'ai une erreur ou un résultat faux."**
|
||||
Vérifier que la liste est bien triée avant d'appeler la dichotomie. C'est la condition indispensable. Si la liste n'est pas triée, le résultat est imprévisible.
|
||||
|
||||
**"Mon tri modifie la liste originale, est-ce normal ?"**
|
||||
Oui. `tri_insertion` et `tri_selection` trient la liste **en place** (ils la modifient directement). Si l'on veut conserver l'original, il faut travailler sur une copie : `tri_insertion(ma_liste[:])`.
|
||||
|
||||
**"J'ai une `IndexError`."**
|
||||
La cause la plus fréquente est un indice qui dépasse la taille de la liste. Vérifiez les bornes de vos boucles (`range`) et les conditions d'arrêt (`while`).
|
||||
|
||||
---
|
||||
|
||||
## Projet 01 — Le Nombre Mystère
|
||||
|
||||
**"Pourquoi la condition est `while gauche <= droite` et pas `while gauche < droite` ?"**
|
||||
Quand il ne reste qu'un seul élément possible, `gauche` et `droite` sont égaux. Si on exclut ce cas avec `<`, on rate le dernier candidat. Le `<=` permet de traiter ce dernier cas.
|
||||
|
||||
**"Pourquoi 7 essais suffisent toujours pour 100 nombres ?"**
|
||||
Parce que la recherche dichotomique a une complexité logarithmique : log₂(100) ≈ 6,64, donc 7 essais au maximum. À chaque question, on élimine la moitié des candidats restants.
|
||||
|
||||
**"Et si l'utilisateur ment ou se trompe dans sa réponse ?"**
|
||||
Le programme finira par épuiser l'intervalle et afficher "tu as triché". Ce comportement est déjà géré dans le starter (fin de boucle sans `return`).
|
||||
|
||||
**"Comment modifier `gauche` et `droite` selon la réponse ?"**
|
||||
- Si le nombre cherché est `<` milieu : `droite = milieu - 1`
|
||||
- Si le nombre cherché est `>` milieu : `gauche = milieu + 1`
|
||||
|
||||
---
|
||||
|
||||
## Projet 02 — Le Tri de Cartes
|
||||
|
||||
**"Comment accéder à la valeur d'une carte ?"**
|
||||
Chaque carte est un tuple `(valeur, couleur)`. `carte[0]` donne la valeur, `carte[1]` donne la couleur.
|
||||
|
||||
**"Pourquoi l'As vaut 14 ?"**
|
||||
C'est une convention pour qu'il soit la carte la plus forte (valeur maximale). Cela permet de le trier après le Roi (13) avec une simple comparaison numérique.
|
||||
|
||||
**"La condition du `while` dans le tri insertion : que faut-il écrire ?"**
|
||||
```python
|
||||
while j > 0 and main[j - 1][0] > x[0]:
|
||||
```
|
||||
On compare uniquement les valeurs (`[0]`), pas les couleurs.
|
||||
|
||||
**"Ma dichotomie retourne toujours `False` même si la carte est là."**
|
||||
Vérifier que la main est bien triée avant la recherche. Et que la comparaison porte bien sur `main_triee[m][0]` (la valeur), pas sur la carte entière.
|
||||
|
||||
---
|
||||
|
||||
## Projet 03 — Le Podium
|
||||
|
||||
**"Comment trier des dictionnaires ?"**
|
||||
On ne trie pas le dictionnaire en tant que tel, on trie la **liste** de dictionnaires. Dans le tri, on compare `athletes[j]["temps"]` et `athletes[mini]["temps"]`.
|
||||
|
||||
**"Que se passe-t-il si deux athlètes ont le même temps ?"**
|
||||
Le tri par sélection n'est pas **stable** : il ne garantit pas que deux éléments égaux restent dans leur ordre d'origine. L'un des deux sera placé en premier de façon arbitraire. C'est une propriété à connaître pour le DS.
|
||||
|
||||
**"Comment aligner le texte dans le podium ASCII ?"**
|
||||
Avec les f-strings et le formatage d'alignement :
|
||||
```python
|
||||
f"{nom:^12}" # centré sur 12 caractères
|
||||
f"{nom:<12}" # aligné à gauche
|
||||
f"{nom:>12}" # aligné à droite
|
||||
```
|
||||
|
||||
**"La dichotomie sur les temps : pourquoi ça compare des flottants ?"**
|
||||
Comparer des flottants avec `==` peut poser des problèmes de précision en Python (ex. `0.1 + 0.2 != 0.3`). Ici les données sont saisies à la main donc c'est acceptable, mais c'est un point de vigilance à mentionner.
|
||||
|
||||
---
|
||||
|
||||
## Projet 04 — L'Annuaire
|
||||
|
||||
**"Comment ajouter un élément à la fin d'une liste ?"**
|
||||
```python
|
||||
ma_liste.append(element)
|
||||
```
|
||||
|
||||
**"Comment supprimer un élément d'une liste par sa valeur ?"**
|
||||
```python
|
||||
ma_liste.remove(element) # supprime la première occurrence
|
||||
```
|
||||
Ou par indice :
|
||||
```python
|
||||
del ma_liste[i]
|
||||
```
|
||||
|
||||
**"La condition du `while` dans `ajouter_contact` : que comparer ?"**
|
||||
```python
|
||||
while j > 0 and annuaire[j - 1]["nom"] > contact["nom"]:
|
||||
```
|
||||
On compare les noms alphabétiquement.
|
||||
|
||||
**"La dichotomie me retourne le bon contact mais je n'affiche rien."**
|
||||
Vérifier que l'appel dans le `menu()` est bien `resultat = rechercher(annuaire, nom)` et que le résultat est ensuite utilisé (`if resultat is not None:`).
|
||||
|
||||
**"Le menu ne s'arrête jamais."**
|
||||
C'est le comportement voulu (`while True`). Il faut saisir `4` pour déclencher le `break`.
|
||||
|
||||
---
|
||||
|
||||
## Projet 05 — Le Correcteur Orthographique
|
||||
|
||||
**"Pourquoi les bornes `a` et `b` donnent les voisins à la fin de la dichotomie ?"**
|
||||
À la fin de la boucle (quand `a > b`), `b` vaut l'indice du dernier élément plus petit que le mot cherché, et `a` vaut l'indice du premier élément plus grand. Ce sont donc les deux voisins alphabétiques du mot absent. C'est une propriété de la dichotomie que l'on exploite ici de façon non conventionnelle.
|
||||
|
||||
**"Il faut vérifier quoi pour les cas limites des voisins ?"**
|
||||
- Si `b < 0` : le mot serait avant tous les mots du dictionnaire → pas de voisin avant
|
||||
- Si `a >= len(dictionnaire)` : le mot serait après tous les mots → pas de voisin après
|
||||
|
||||
```python
|
||||
voisin_avant = dictionnaire[b] if b >= 0 else None
|
||||
voisin_apres = dictionnaire[a] if a < len(dictionnaire) else None
|
||||
```
|
||||
|
||||
**"La condition du `while` dans `ajouter_mot` : que comparer ?"**
|
||||
```python
|
||||
while j > 0 and dictionnaire[j - 1] > mot:
|
||||
```
|
||||
Les chaînes se comparent directement en Python (ordre alphabétique).
|
||||
|
||||
**"Les suggestions ne correspondent pas au mot saisi."**
|
||||
Vérifier que la comparaison se fait bien en minuscules. Utiliser `.lower()` sur le mot saisi par l'utilisateur pour uniformiser.
|
||||
|
||||
---
|
||||
|
||||
## Projet 06 — La Bibliothèque
|
||||
|
||||
**"Comment trier par titre (chaînes) avec le tri sélection ?"**
|
||||
```python
|
||||
if livres[j]["titre"] < livres[mini]["titre"]:
|
||||
```
|
||||
Python compare les chaînes alphabétiquement avec `<` et `>`.
|
||||
|
||||
**"La dichotomie ne trouve pas un livre qui est pourtant dans la liste."**
|
||||
Les titres dans le dictionnaire sont tous en **minuscules**. Si l'utilisateur saisit "1984" avec une majuscule ou des espaces en trop, la comparaison échouera. Appliquer `.strip().lower()` à la saisie.
|
||||
|
||||
**"Comment trier une copie sans modifier la liste originale ?"**
|
||||
```python
|
||||
livres_par_pages = livres[:] # copie
|
||||
tri_selection_livres_par_pages(livres_par_pages) # trier la copie
|
||||
```
|
||||
|
||||
**"Comment calculer la moyenne ?"**
|
||||
```python
|
||||
total = sum(l["pages"] for l in livres)
|
||||
moyenne = total / len(livres)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Projet 07 — La Météo
|
||||
|
||||
**"Comment accéder au jour et à la température dans un tuple ?"**
|
||||
Chaque relevé est `(jour, temperature)`. On accède avec `releve[0]` pour le jour et `releve[1]` pour la température. Ou avec le déballage : `jour, temp = releve`.
|
||||
|
||||
**"La condition du `while` dans le tri : que comparer ?"**
|
||||
```python
|
||||
while j > 0 and tab[j - 1][1] > x[1]:
|
||||
```
|
||||
On compare le deuxième élément du tuple (la température).
|
||||
|
||||
**"Qu'est-ce que `.get()` sur un dictionnaire ?"**
|
||||
`compteur.get(degre, 0)` retourne la valeur associée à la clé `degre` si elle existe, sinon retourne `0`. C'est équivalent à :
|
||||
```python
|
||||
if degre in compteur:
|
||||
return compteur[degre]
|
||||
else:
|
||||
return 0
|
||||
```
|
||||
|
||||
**"Pourquoi travailler sur une copie des relevés ?"**
|
||||
Pour conserver l'ordre chronologique original. Si on trie directement `releves`, on perd l'information "quel jour avait quelle température".
|
||||
|
||||
**"Comment calculer la médiane ?"**
|
||||
Sur une liste triée de taille `n`, la médiane est l'élément à l'indice `n // 2` :
|
||||
```python
|
||||
mediane = tab_trie[len(tab_trie) // 2]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Projet 08 — La Course des Algorithmes
|
||||
|
||||
**"Les temps mesurés varient à chaque exécution, c'est normal ?"**
|
||||
Oui. Le temps dépend de la charge du processeur au moment de l'exécution. Pour des résultats plus stables, on peut faire la moyenne sur plusieurs exécutions. Mais les tendances (quel algorithme est plus rapide) restent les mêmes.
|
||||
|
||||
**"Pourquoi travailler sur une copie dans `mesurer_temps` ?"**
|
||||
Si on trie directement la liste passée en argument, elle sera triée pour la deuxième mesure : les deux algorithmes ne partiraient pas dans les mêmes conditions.
|
||||
|
||||
**"Mon tri insertion est beaucoup plus rapide sur une liste déjà triée, pourquoi ?"**
|
||||
Parce que sur une liste déjà triée, la boucle `while` interne ne s'exécute jamais (la condition est fausse dès le premier tour). Sa complexité devient linéaire O(n) au lieu de O(n²). Ce n'est pas le cas du tri sélection, qui parcourt toujours toute la liste restante.
|
||||
|
||||
**"Qu'est-ce que `random.sample(range(n * 10), n)` ?"**
|
||||
Cela génère une liste de `n` entiers distincts choisis aléatoirement entre 0 et `n*10`. Le `* 10` évite les doublons dans la liste.
|
||||
|
||||
**"Comment interpréter les résultats pour la conclusion ?"**
|
||||
Le tri insertion est plus rapide sur des listes presque triées. Le tri sélection est plus constant (toujours O(n²) quel que soit le cas). Pour des listes aléatoires de grande taille, les deux sont comparables.
|
||||
|
||||
---
|
||||
|
||||
## Projet 09 — Le Générateur Web
|
||||
|
||||
**"Le fichier HTML se génère où ?"**
|
||||
Dans le même dossier que `starter.py`. Si le navigateur ne s'ouvre pas automatiquement, ouvrir manuellement `classement.html` depuis ce dossier.
|
||||
|
||||
**"La dichotomie inversée : comment ça marche ?"**
|
||||
Quand la liste est triée par ordre décroissant, un score plus grand se trouve à gauche. Les comparaisons sont donc inversées :
|
||||
- Si `score_m > score` (le milieu est trop grand) → chercher à droite (`a = m + 1`)
|
||||
- Si `score_m < score` (le milieu est trop petit) → chercher à gauche (`b = m - 1`)
|
||||
|
||||
**"La condition du `while` dans le tri décroissant : que mettre ?"**
|
||||
```python
|
||||
while j > 0 and jeux[j - 1]["score"] < x["score"]:
|
||||
```
|
||||
On décale quand le score précédent est **inférieur** (l'inverse du tri croissant).
|
||||
|
||||
**"Comment écrire dans un fichier en Python ?"**
|
||||
```python
|
||||
with open("fichier.html", "w", encoding="utf-8") as f:
|
||||
f.write(contenu)
|
||||
```
|
||||
Le `with` garantit que le fichier est bien fermé après l'écriture.
|
||||
|
||||
**"Pourquoi Python peut générer du HTML mais HTML ne peut pas exécuter Python ?"**
|
||||
HTML est un langage de **description** (il décrit une structure), pas un langage d'exécution. Python, lui, s'exécute côté serveur ou en local et peut produire n'importe quel texte en sortie, y compris du HTML. Un navigateur lit le HTML généré, mais ne sait pas d'où il vient.
|
||||
65
algorithmes/mini-projets/README.md
Normal file
65
algorithmes/mini-projets/README.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Mini-projets — Algorithmes de tri et recherche dichotomique
|
||||
|
||||
Séance de révision avant DS (mardi). Chaque groupe reçoit un projet différent.
|
||||
Durée : **1h à 1h30**. Langage : **Python** (sauf projet 09 : Python + HTML/CSS).
|
||||
|
||||
> **Règle commune** : vous devez implémenter vous-mêmes `tri_insertion`, `tri_selection` et `dichotomique`. **Interdiction d'utiliser `sort()` ou `sorted()`.**
|
||||
|
||||
---
|
||||
|
||||
## Répartition des groupes
|
||||
|
||||
| # | Projet | Algorithmes utilisés | Difficulté |
|
||||
|---|--------|----------------------|------------|
|
||||
| 01 | [Le Nombre Mystère](01_devine_nombre/) | Dichotomie | Facile |
|
||||
| 02 | [Le Tri de Cartes](02_cartes/) | Tri insertion | Facile |
|
||||
| 03 | [Le Podium](03_podium/) | Tri sélection + Dichotomie | Facile |
|
||||
| 04 | [L'Annuaire](04_annuaire/) | Tri insertion + Dichotomie | Moyen |
|
||||
| 05 | [Le Correcteur](05_correcteur/) | Tri insertion + Dichotomie (voisins) | Moyen |
|
||||
| 06 | [La Bibliothèque](06_bibliotheque/) | Tri sélection + Dichotomie | Moyen |
|
||||
| 07 | [La Météo](07_meteo/) | Tri insertion + Dichotomie | Moyen |
|
||||
| 08 | [La Course des Algos](08_course_algos/) | Tri insertion vs Tri sélection | Difficile |
|
||||
| 09 | [Le Générateur Web](09_generateur_web/) | Tri insertion + Dichotomie → HTML | Difficile |
|
||||
|
||||
---
|
||||
|
||||
## Rappels des algorithmes
|
||||
|
||||
```python
|
||||
def tri_insertion(tab):
|
||||
for i in range(1, len(tab)):
|
||||
x = tab[i]
|
||||
j = i
|
||||
while j > 0 and tab[j - 1] > x:
|
||||
tab[j] = tab[j - 1]
|
||||
j -= 1
|
||||
tab[j] = x
|
||||
return tab
|
||||
|
||||
def tri_selection(tab):
|
||||
n = len(tab)
|
||||
for i in range(n):
|
||||
mini = i
|
||||
for j in range(i + 1, n):
|
||||
if tab[j] < tab[mini]:
|
||||
mini = j
|
||||
tab[i], tab[mini] = tab[mini], tab[i]
|
||||
return tab
|
||||
|
||||
def dichotomique(tab, x):
|
||||
a = 0
|
||||
b = len(tab) - 1
|
||||
while a <= b:
|
||||
m = (a + b) // 2
|
||||
if tab[m] == x:
|
||||
return True
|
||||
elif tab[m] < x:
|
||||
a = m + 1
|
||||
else:
|
||||
b = m - 1
|
||||
return False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu — Licence CC BY NC
|
||||
Reference in New Issue
Block a user