Compare commits
16
Commits
2b58c2b573
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3d5eb0751 | ||
|
|
09391fcc8b | ||
|
|
830a3ac4d8 | ||
|
|
21df8c5109 | ||
|
|
691fb60400 | ||
|
|
10828ecae5 | ||
|
|
50f8dd0afa | ||
|
|
8ec1ee8ba8 | ||
|
|
977fa778e9 | ||
|
|
abd478961e | ||
|
|
78d9912fe2 | ||
|
|
0d44ac2fc2 | ||
|
|
2f072b1711 | ||
|
|
758d4bbf7d | ||
|
|
db9d80ffbe | ||
|
|
118834bc5f |
@@ -38,12 +38,12 @@ Nous disposons d'une base de données pour une sandwicherie. Voici les tables de
|
|||||||
## 2. Questions pour réflexion
|
## 2. Questions pour réflexion
|
||||||
|
|
||||||
1. **Analyse des clés** :
|
1. **Analyse des clés** :
|
||||||
- Quelle est la **clé primaire** de chaque table ?
|
- Quelle est la **clé primaire** de chaque table ?
|
||||||
- Les tables comportent-elles des **clés étrangères** ? Si oui, lesquelles ?
|
- Les tables comportent-elles des **clés étrangères** ? Si oui, lesquelles ?
|
||||||
|
|
||||||
2. **Problèmes de modélisation** :
|
2. **Problèmes de modélisation** :
|
||||||
- La base est-elle bien modélisée ?
|
- La base est-elle bien modélisée ?
|
||||||
- Proposez des améliorations pour éviter la redondance et mieux gérer les relations.
|
- Proposez des améliorations pour éviter la redondance et mieux gérer les relations.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -53,10 +53,10 @@ Que se passe-t-il quand le bot analyse le tweet « Ce tweet est faux » ?
|
|||||||
### Analyse
|
### Analyse
|
||||||
|
|
||||||
1. **Hypothèse 1** : Le barbier se rase lui-même.
|
1. **Hypothèse 1** : Le barbier se rase lui-même.
|
||||||
- Que peut-on en déduire d'après la règle ?
|
- Que peut-on en déduire d'après la règle ?
|
||||||
|
|
||||||
2. **Hypothèse 2** : Le barbier ne se rase pas lui-même.
|
2. **Hypothèse 2** : Le barbier ne se rase pas lui-même.
|
||||||
- Que peut-on en déduire d'après la règle ?
|
- Que peut-on en déduire d'après la règle ?
|
||||||
|
|
||||||
3. Conclusion : pourquoi ce paradoxe n'a-t-il pas de solution ?
|
3. Conclusion : pourquoi ce paradoxe n'a-t-il pas de solution ?
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -17,8 +17,8 @@ Le parcours en largeur d’un graphe consiste à explorer tous les voisins d’u
|
|||||||
1. Choisir un sommet de départ et l’ajouter à une file d’attente.
|
1. Choisir un sommet de départ et l’ajouter à une file d’attente.
|
||||||
2. Marquer ce sommet comme visité.
|
2. Marquer ce sommet comme visité.
|
||||||
3. Tant que la file n’est pas vide :
|
3. Tant que la file n’est pas vide :
|
||||||
- Retirer le sommet en tête de la file.
|
- Retirer le sommet en tête de la file.
|
||||||
- Ajouter tous ses voisins non encore visités dans la file et les marquer comme visités.
|
- Ajouter tous ses voisins non encore visités dans la file et les marquer comme visités.
|
||||||
|
|
||||||
#### Implémentation en Python :
|
#### Implémentation en Python :
|
||||||
```python
|
```python
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -1,213 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "75db6ded",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"# Évaluation sur la Programmation Orientée Objet, les Piles et les Files\n",
|
|
||||||
"\n",
|
|
||||||
"### Durée : 1h à 1h30\n",
|
|
||||||
"\n",
|
|
||||||
"---\n",
|
|
||||||
"\n",
|
|
||||||
"## Consignes :\n",
|
|
||||||
"1. Cette évaluation est individuelle.\n",
|
|
||||||
"2. Chaque réponse doit être correctement commentée.\n",
|
|
||||||
"3. Soignez la lisibilité et la clarté de votre code.\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "09af4f46",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"## Partie 1 : Programmation Orientée Objet (10 points)\n",
|
|
||||||
"\n",
|
|
||||||
"### Contexte :\n",
|
|
||||||
"Un développeur de RPG (jeu de rôle) souhaite modéliser les personnages jouables de son jeu ainsi que leurs inventaires.\n",
|
|
||||||
"\n",
|
|
||||||
"### Travail à faire :\n",
|
|
||||||
"Implémente les classes suivantes :\n",
|
|
||||||
"\n",
|
|
||||||
"1. **Classe `Personnage`** :\n",
|
|
||||||
" - Attributs : \n",
|
|
||||||
" - `nom` (chaîne)\n",
|
|
||||||
" - `niveau` (entier, par défaut 1)\n",
|
|
||||||
" - `vie` (entier, par défaut 100)\n",
|
|
||||||
" - `inventaire` (liste, vide par défaut)\n",
|
|
||||||
" - Méthodes :\n",
|
|
||||||
" - `__init__` : initialise un personnage.\n",
|
|
||||||
" - `ajouter_objet(objet)` : ajoute un objet dans l’inventaire.\n",
|
|
||||||
" - `afficher_inventaire()` : affiche les objets dans l’inventaire.\n",
|
|
||||||
" - `subir_degats(points)` : réduit les points de vie du personnage (minimum 0).\n",
|
|
||||||
" - `__str__` : affiche les informations du personnage.\n",
|
|
||||||
"\n",
|
|
||||||
"2. **Classe `Objet`** :\n",
|
|
||||||
" - Attributs :\n",
|
|
||||||
" - `nom` (chaîne)\n",
|
|
||||||
" - `rarete` (chaîne : \"commun\", \"rare\", \"légendaire\")\n",
|
|
||||||
" - Méthodes :\n",
|
|
||||||
" - `__init__` : initialise un objet.\n",
|
|
||||||
" - `__str__` : affiche les informations de l’objet.\n",
|
|
||||||
"\n",
|
|
||||||
"### Exemple d'utilisation attendu :\n",
|
|
||||||
"```python\n",
|
|
||||||
"# Création des objets\n",
|
|
||||||
"epee = Objet(\"Épée magique\", \"rare\")\n",
|
|
||||||
"potion = Objet(\"Potion de soin\", \"commun\")\n",
|
|
||||||
"\n",
|
|
||||||
"# Création du personnage\n",
|
|
||||||
"hero = Personnage(\"Link\")\n",
|
|
||||||
"hero.ajouter_objet(epee)\n",
|
|
||||||
"hero.ajouter_objet(potion)\n",
|
|
||||||
"\n",
|
|
||||||
"# Afficher l'inventaire et infliger des dégâts\n",
|
|
||||||
"hero.afficher_inventaire()\n",
|
|
||||||
"hero.subir_degats(30)\n",
|
|
||||||
"print(hero)\n",
|
|
||||||
"```\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "6769bdf1",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"## Partie 2 : Les piles (5 points)\n",
|
|
||||||
"\n",
|
|
||||||
"### Contexte :\n",
|
|
||||||
"Un joueur de Tetris souhaite programmer la mécanique d’empilement et de suppression des lignes complètes.\n",
|
|
||||||
"\n",
|
|
||||||
"### Travail à faire :\n",
|
|
||||||
"Implémente une classe `Pile` pour modéliser les lignes de Tetris.\n",
|
|
||||||
"\n",
|
|
||||||
"1. Attributs :\n",
|
|
||||||
" - `elements` (liste vide au départ)\n",
|
|
||||||
"2. Méthodes :\n",
|
|
||||||
" - `ajouter_ligne(valeur)` : ajoute une ligne de blocs à la pile.\n",
|
|
||||||
" - `supprimer_ligne()` : supprime la ligne en haut de la pile.\n",
|
|
||||||
" - `est_vide()` : renvoie `True` si la pile est vide, sinon `False`.\n",
|
|
||||||
"\n",
|
|
||||||
"### Exemple d'utilisation attendu :\n",
|
|
||||||
"```python\n",
|
|
||||||
"pile = Pile()\n",
|
|
||||||
"pile.ajouter_ligne(\"Ligne 1\")\n",
|
|
||||||
"pile.ajouter_ligne(\"Ligne 2\")\n",
|
|
||||||
"pile.supprimer_ligne()\n",
|
|
||||||
"print(pile.est_vide()) # Affiche : False\n",
|
|
||||||
"```\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "1544315c",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"## Partie 3 : Les files (5 points)\n",
|
|
||||||
"\n",
|
|
||||||
"### Contexte :\n",
|
|
||||||
"Un fast-food inspiré du **Café Pikachu** utilise une file pour gérer les commandes des clients.\n",
|
|
||||||
"\n",
|
|
||||||
"### Travail à faire :\n",
|
|
||||||
"Écris une classe `File` pour gérer les commandes.\n",
|
|
||||||
"\n",
|
|
||||||
"1. Attributs :\n",
|
|
||||||
" - `elements` (liste vide au départ)\n",
|
|
||||||
"2. Méthodes :\n",
|
|
||||||
" - `ajouter_commande(valeur)` : ajoute une commande en fin de file.\n",
|
|
||||||
" - `traiter_commande()` : retire et renvoie la commande en début de file.\n",
|
|
||||||
" - `est_vide()` : renvoie `True` si la file est vide, sinon `False`.\n",
|
|
||||||
"\n",
|
|
||||||
"### Exemple d'utilisation attendu :\n",
|
|
||||||
"```python\n",
|
|
||||||
"file = File()\n",
|
|
||||||
"file.ajouter_commande(\"Commande Pikachu Pancakes\")\n",
|
|
||||||
"file.ajouter_commande(\"Commande Evoli Latte\")\n",
|
|
||||||
"print(file.traiter_commande()) # Affiche : \"Commande Pikachu Pancakes\"\n",
|
|
||||||
"print(file.est_vide()) # Affiche : False\n",
|
|
||||||
"```\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "8e12e449",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"\n",
|
|
||||||
"## Partie 4 : POO – Gestion d'une arène de combat (10 points)\n",
|
|
||||||
"\n",
|
|
||||||
"### Contexte :\n",
|
|
||||||
"Tu es chargé(e) de coder un simulateur d’arène de combat. Deux créatures s’affrontent jusqu’à ce que l’une d’elles n’ait plus de points de vie. Chaque créature possède des attaques spécifiques et un nombre de points de vie limité.\n",
|
|
||||||
"\n",
|
|
||||||
"---\n",
|
|
||||||
"\n",
|
|
||||||
"### Travail à faire :\n",
|
|
||||||
"Implémente les classes suivantes :\n",
|
|
||||||
"\n",
|
|
||||||
"1. **Classe `Creature`** :\n",
|
|
||||||
" - Attributs :\n",
|
|
||||||
" - `nom` (chaîne)\n",
|
|
||||||
" - `vie` (entier, par défaut 50)\n",
|
|
||||||
" - `force` (entier, par défaut 10)\n",
|
|
||||||
" - Méthodes :\n",
|
|
||||||
" - `__init__` : initialise une créature.\n",
|
|
||||||
" - `attaquer(cible)` : réduit les points de vie de la créature cible en fonction de la force de l'attaquant.\n",
|
|
||||||
" - `est_vivant()` : renvoie `True` si les points de vie sont supérieurs à 0, sinon `False`.\n",
|
|
||||||
" - `__str__` : affiche les informations de la créature.\n",
|
|
||||||
"\n",
|
|
||||||
"2. **Classe `Combat`** :\n",
|
|
||||||
" - Attributs :\n",
|
|
||||||
" - `creature1` (objet de type `Creature`)\n",
|
|
||||||
" - `creature2` (objet de type `Creature`)\n",
|
|
||||||
" - Méthodes :\n",
|
|
||||||
" - `__init__` : initialise un combat entre deux créatures.\n",
|
|
||||||
" - `lancer_combat()` : lance une boucle où chaque créature attaque l'autre jusqu'à ce qu'une des deux ne soit plus vivante. Affiche le déroulement du combat.\n",
|
|
||||||
"\n",
|
|
||||||
"---\n",
|
|
||||||
"\n",
|
|
||||||
"### Exemple d'utilisation attendu :\n",
|
|
||||||
"```python\n",
|
|
||||||
"# Création des créatures\n",
|
|
||||||
"pikachu = Creature(\"Pikachu\", vie=35, force=12)\n",
|
|
||||||
"dracaufeu = Creature(\"Dracaufeu\", vie=50, force=15)\n",
|
|
||||||
"\n",
|
|
||||||
"# Lancement du combat\n",
|
|
||||||
"combat = Combat(pikachu, dracaufeu)\n",
|
|
||||||
"combat.lancer_combat()\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"---\n",
|
|
||||||
"\n",
|
|
||||||
"### Résultat attendu :\n",
|
|
||||||
"Le programme affiche un résumé des attaques et indique quelle créature a gagné :\n",
|
|
||||||
"```\n",
|
|
||||||
"Pikachu attaque Dracaufeu (-12 PV).\n",
|
|
||||||
"Dracaufeu attaque Pikachu (-15 PV).\n",
|
|
||||||
"Pikachu attaque Dracaufeu (-12 PV).\n",
|
|
||||||
"Dracaufeu attaque Pikachu (-15 PV).\n",
|
|
||||||
"Pikachu est KO ! Dracaufeu remporte le combat.\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"---\n",
|
|
||||||
"\n",
|
|
||||||
"### Barème :\n",
|
|
||||||
"- **Classe `Creature`** : 6 points\n",
|
|
||||||
" - Implémentation des attributs et méthodes.\n",
|
|
||||||
"- **Classe `Combat`** : 4 points\n",
|
|
||||||
" - Lancer une boucle et afficher le déroulement du combat.\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"language_info": {
|
|
||||||
"name": "python"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 5
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
# Fiche de révision : la programmation orientée objet
|
||||||
|
|
||||||
|
> Une fiche pour reprendre les bases, et surtout la différence entre une **classe** et un **objet**. Les exemples reprennent le TP Pokémon Arena.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Vous faites de la POO depuis la Première
|
||||||
|
|
||||||
|
Bonne nouvelle : la POO n'est pas un monde nouveau. Vous utilisez des objets depuis l'année dernière sans le savoir.
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> type(3)
|
||||||
|
<class 'int'>
|
||||||
|
>>> type("salut")
|
||||||
|
<class 'str'>
|
||||||
|
>>> type([1, 2])
|
||||||
|
<class 'list'>
|
||||||
|
```
|
||||||
|
|
||||||
|
Python vous le dit lui-même : `3` est un objet de la **classe** `int`, `"salut"` un objet de la classe `str`, `[1, 2]` un objet de la classe `list`.
|
||||||
|
|
||||||
|
Et quand vous écrivez `ma_liste.append(3)` ou `"salut".upper()`, vous appelez une **méthode** sur un **objet**. Le point entre les deux signifie : « applique cette méthode à cet objet-là ».
|
||||||
|
|
||||||
|
En Terminale, la seule nouveauté, c'est que vous allez **écrire vos propres classes**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Classe ou objet ? La différence en une image
|
||||||
|
|
||||||
|
Reprenons l'image du cours : **la classe, c'est le plan d'architecte ; l'objet, c'est la maison construite.** Avec un seul plan, on peut construire toute une rue de maisons. Elles ont la même forme, mais chacune a sa propre couleur de volets, ses propres habitants, et si on repeint l'une, les autres ne changent pas.
|
||||||
|
|
||||||
|
Avec les Pokémon :
|
||||||
|
|
||||||
|
- la **classe** `Pokemon`, c'est le **formulaire vierge** du Pokédex : il prévoit des cases « nom », « type », « PV », mais il ne contient aucun Pokémon ;
|
||||||
|
- un **objet**, c'est un **Pokémon précis**, avec ses cases remplies : *ce* Pikachu-là, avec *ses* 80 PV.
|
||||||
|
|
||||||
|
| | Classe | Objet (ou instance) |
|
||||||
|
|:--|:--|:--|
|
||||||
|
| C'est… | un modèle, un plan | un exemplaire construit à partir du modèle |
|
||||||
|
| Combien ? | écrite **une seule fois** | créé **autant de fois qu'on veut** |
|
||||||
|
| Dans le code | `class Pokemon:` | `pikachu = Pokemon("Pikachu", "Electrik", 80)` |
|
||||||
|
| Nom | commence par une **majuscule** | une variable, en minuscules |
|
||||||
|
| Contient des valeurs ? | non, elle décrit **quelles** données existeront | oui, **ses propres** valeurs |
|
||||||
|
|
||||||
|
Voici une classe très courte :
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Pokemon:
|
||||||
|
def __init__(self, nom, type_pokemon, pv):
|
||||||
|
self.nom = nom
|
||||||
|
self.type_pokemon = type_pokemon
|
||||||
|
self.pv = pv
|
||||||
|
|
||||||
|
def subir_degats(self, degats):
|
||||||
|
self.pv = self.pv - degats
|
||||||
|
```
|
||||||
|
|
||||||
|
Ce code **ne crée aucun Pokémon**. Il explique seulement comment en fabriquer un. Les objets naissent ici :
|
||||||
|
|
||||||
|
```python
|
||||||
|
pikachu = Pokemon("Pikachu", "Electrik", 80)
|
||||||
|
autre_pikachu = Pokemon("Pikachu", "Electrik", 80)
|
||||||
|
```
|
||||||
|
|
||||||
|
Deux objets, construits avec le même plan et les mêmes valeurs. Ce sont pourtant **deux Pokémon différents** :
|
||||||
|
|
||||||
|
```python
|
||||||
|
>>> autre_pikachu.subir_degats(30)
|
||||||
|
>>> pikachu.pv
|
||||||
|
80
|
||||||
|
>>> autre_pikachu.pv
|
||||||
|
50
|
||||||
|
```
|
||||||
|
|
||||||
|
Le premier Pikachu n'a rien senti. Chaque objet a **ses propres attributs**, rangés dans sa propre « boîte ».
|
||||||
|
|
||||||
|
!!! tip "À retenir"
|
||||||
|
|
||||||
|
**Un objet n'existe que lorsqu'on appelle la classe avec des parenthèses** : `Pokemon(...)`. Chaque appel fabrique un **nouvel** objet. Écrire `class Pokemon:` ne fabrique rien.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Le constructeur et `self`
|
||||||
|
|
||||||
|
Que se passe-t-il exactement quand on écrit `pikachu = Pokemon("Pikachu", "Electrik", 80)` ?
|
||||||
|
|
||||||
|
1. Python fabrique un **objet vide** de la classe `Pokemon`.
|
||||||
|
2. Il appelle automatiquement la méthode `__init__`, le **constructeur**, en lui donnant cet objet vide comme **premier paramètre**, `self`.
|
||||||
|
3. `__init__` remplit l'objet : `self.nom = nom` signifie « range la valeur `nom` dans la case `nom` de **cet objet-là** ».
|
||||||
|
4. L'objet rempli est rangé dans la variable `pikachu`.
|
||||||
|
|
||||||
|
`self` désigne donc toujours **l'objet sur lequel on est en train de travailler**. C'est la même chose pour les autres méthodes :
|
||||||
|
|
||||||
|
```python
|
||||||
|
pikachu.subir_degats(30)
|
||||||
|
```
|
||||||
|
|
||||||
|
est exactement équivalent à :
|
||||||
|
|
||||||
|
```python
|
||||||
|
Pokemon.subir_degats(pikachu, 30)
|
||||||
|
```
|
||||||
|
|
||||||
|
Python fait cette traduction tout seul : l'objet placé **avant le point** devient `self`. C'est pour cela que `self` apparaît dans la définition de la méthode, mais jamais entre les parenthèses à l'appel.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Le vocabulaire
|
||||||
|
|
||||||
|
| Mot | Sens | Dans le TP Pokémon |
|
||||||
|
|:--|:--|:--|
|
||||||
|
| **Classe** | le modèle | `Pokemon`, `Dresseur`, `Combat` |
|
||||||
|
| **Objet** ou **instance** | un exemplaire créé à partir de la classe | `pikachu`, `salameche`, `sacha` |
|
||||||
|
| **Instanciation** | le fait de créer un objet | `Pokemon("Pikachu", "Electrik", 80)` |
|
||||||
|
| **Attribut** | une donnée rangée dans l'objet | `pikachu.pv`, `pikachu.nom` |
|
||||||
|
| **Méthode** | une fonction définie dans la classe, qui agit sur un objet | `pikachu.attaquer(salameche)` |
|
||||||
|
| **Constructeur** | la méthode `__init__`, appelée à la création | remplit `nom`, `type_pokemon`, `pv` |
|
||||||
|
| **`self`** | l'objet sur lequel la méthode travaille | `pikachu` quand on écrit `pikachu.attaquer(...)` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Les erreurs classiques
|
||||||
|
|
||||||
|
**Oublier `self` dans la définition d'une méthode.**
|
||||||
|
|
||||||
|
```python
|
||||||
|
def __init__(nom): # faux
|
||||||
|
def __init__(self, nom): # juste
|
||||||
|
```
|
||||||
|
|
||||||
|
Python répond : `TypeError: Pokemon.__init__() takes 1 positional argument but 2 were given`. Il a bien transmis deux choses, l'objet et le nom, mais la méthode n'avait prévu de place que pour une.
|
||||||
|
|
||||||
|
**Écrire `nom = nom` au lieu de `self.nom = nom`.**
|
||||||
|
|
||||||
|
Sans `self.`, la valeur est rangée dans une variable qui disparaît à la fin de `__init__`, pas dans l'objet. Plus tard, `pikachu.nom` provoque : `AttributeError: 'Pokemon' object has no attribute 'nom'`.
|
||||||
|
|
||||||
|
**Appeler une méthode sur la classe au lieu de l'objet.**
|
||||||
|
|
||||||
|
```python
|
||||||
|
Pokemon.subir_degats(10) # faux : quel Pokémon subit les dégâts ?
|
||||||
|
pikachu.subir_degats(10) # juste
|
||||||
|
```
|
||||||
|
|
||||||
|
C'est exactement la confusion entre classe et objet : la classe est un plan, on ne blesse pas un plan.
|
||||||
|
|
||||||
|
**Utiliser `print` au lieu de `return` dans `__repr__`.**
|
||||||
|
|
||||||
|
`__repr__` doit **renvoyer** un texte, pas l'afficher. Avec un `print`, Python se plaint : `TypeError: __str__ returned non-string (type NoneType)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Un peu d'histoire
|
||||||
|
|
||||||
|
!!! info "1967 : des classes pour simuler des navires"
|
||||||
|
|
||||||
|
À Oslo, deux chercheurs norvégiens, **Ole-Johan Dahl** et **Kristen Nygaard**, veulent simuler des systèmes réels : des files d'attente, du trafic, des navires dans un port. Ils créent le langage **Simula 67**, qui invente les **classes** et les **objets** : chaque navire du port devient un objet construit sur le modèle « navire ». C'est exactement l'idée de cette fiche, un plan et des exemplaires. Ils ont reçu en 2001 le **prix Turing**, l'équivalent du prix Nobel de l'informatique.
|
||||||
|
|
||||||
|
!!! info "Alan Kay et l'expression « orienté objet »"
|
||||||
|
|
||||||
|
Dans les années 1970, au centre de recherche de Xerox à Palo Alto, **Alan Kay** et son équipe créent le langage **Smalltalk**, où absolument tout est un objet. Alan Kay raconte que c'est lui qui a inventé l'expression « programmation orientée objet ». Des années plus tard, devant une salle d'informaticiens, il ajoutera avec malice : « J'ai inventé l'expression orienté objet, et je peux vous dire que je ne pensais pas à C++. »
|
||||||
|
|
||||||
|
!!! info "Et Python dans tout ça ?"
|
||||||
|
|
||||||
|
Python pousse cette idée aussi loin que Smalltalk : en Python, **tout est objet**. Les nombres, les textes, les listes, et même les fonctions et les classes elles-mêmes. C'est pour cela que `type(3)` répond `<class 'int'>` : depuis la Première, vous manipulez des objets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Pour revoir en vidéo
|
||||||
|
|
||||||
|
[Programmation orientée objet - PYTHON - TLE - Spé NSI](https://www.youtube.com/watch?v=yncatRjlEa0&t=50s), par David Latouche (2020).
|
||||||
|
|
||||||
|
Regardez de **0:50 à 9:51** : les concepts clés, la déclaration d'une classe et le constructeur, l'instanciation d'un objet, les attributs et les méthodes. La suite (encapsulation, héritage, polymorphisme) dépasse le programme de Terminale.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. À vous
|
||||||
|
|
||||||
|
!!! question "Exercice 1 : Classe ou objet ?"
|
||||||
|
|
||||||
|
Dans le code ci-dessous, indiquez pour chaque nom s'il désigne une **classe**, un **objet**, un **attribut** ou une **méthode** : `Dresseur`, `sacha`, `equipe`, `ajouter`, `pikachu`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Dresseur:
|
||||||
|
def __init__(self, nom):
|
||||||
|
self.nom = nom
|
||||||
|
self.equipe = []
|
||||||
|
|
||||||
|
def ajouter(self, pokemon):
|
||||||
|
self.equipe.append(pokemon)
|
||||||
|
|
||||||
|
sacha = Dresseur("Sacha")
|
||||||
|
sacha.ajouter(pikachu)
|
||||||
|
```
|
||||||
|
|
||||||
|
??? success "Correction de l'exercice 1"
|
||||||
|
|
||||||
|
- `Dresseur` : une **classe** (mot-clé `class`, majuscule).
|
||||||
|
- `sacha` : un **objet**, créé par `Dresseur("Sacha")`.
|
||||||
|
- `equipe` : un **attribut** (`self.equipe`), la liste des Pokémon du dresseur.
|
||||||
|
- `ajouter` : une **méthode**, définie dans la classe et appelée sur l'objet `sacha`.
|
||||||
|
- `pikachu` : un **objet**, de la classe `Pokemon`. Ce n'est pas parce qu'il est rangé dans l'équipe de Sacha qu'il devient un `Dresseur`.
|
||||||
|
|
||||||
|
!!! question "Exercice 2 : Combien d'objets ?"
|
||||||
|
|
||||||
|
Avec la classe `Pokemon` de la partie 2 :
|
||||||
|
|
||||||
|
```python
|
||||||
|
a = Pokemon("Évoli", "Normal", 55)
|
||||||
|
b = Pokemon("Évoli", "Normal", 55)
|
||||||
|
c = a
|
||||||
|
b.subir_degats(10)
|
||||||
|
c.subir_degats(5)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Combien d'objets `Pokemon` ont été créés ?
|
||||||
|
2. Que valent `a.pv`, `b.pv` et `c.pv` ?
|
||||||
|
|
||||||
|
??? success "Correction de l'exercice 2"
|
||||||
|
|
||||||
|
1. **Deux objets** seulement. Seuls `Pokemon(...)` avec des parenthèses fabriquent un objet, et il y en a deux. `c = a` ne crée rien : c'est un **deuxième nom** pour le même objet que `a`.
|
||||||
|
2. `a.pv` vaut **50**, `b.pv` vaut **45** et `c.pv` vaut **50**. `b` a subi 10 dégâts. `c` et `a` étant le même Pokémon, les 5 dégâts infligés « à `c` » sont subis par `a`.
|
||||||
|
|
||||||
|
!!! question "Exercice 3 : Écrire une classe"
|
||||||
|
|
||||||
|
Écrivez une classe `Badge` dont le constructeur reçoit un `nom` et une `ville`, et range ces deux valeurs dans l'objet. Créez ensuite le badge « Roche » de la ville d'Argenta, puis affichez sa ville.
|
||||||
|
|
||||||
|
??? success "Correction de l'exercice 3"
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Badge:
|
||||||
|
def __init__(self, nom, ville):
|
||||||
|
self.nom = nom
|
||||||
|
self.ville = ville
|
||||||
|
|
||||||
|
badge_roche = Badge("Roche", "Argenta")
|
||||||
|
print(badge_roche.ville)
|
||||||
|
```
|
||||||
|
|
||||||
|
Points à vérifier : `self` en premier paramètre de `__init__`, `self.nom` et `self.ville` (et pas `nom = nom`), et l'objet créé avec des parenthèses avant d'accéder à son attribut.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Auteur : Florian Mathieu
|
||||||
|
|
||||||
|
Licence CC BY-SA
|
||||||
|
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||||
@@ -0,0 +1,649 @@
|
|||||||
|
# Corrigé du TP : Pokémon Arena
|
||||||
|
|
||||||
|
Ce corrigé donne le code de chaque exercice, mais surtout **la façon d'y arriver**. Sous chaque question, vous trouverez des blocs à déplier :
|
||||||
|
|
||||||
|
- **Par où commencer** : comment réfléchir avant d'écrire la moindre ligne ;
|
||||||
|
- **Ce qui se passe à l'exécution** : le code suivi pas à pas sur un exemple.
|
||||||
|
|
||||||
|
Si les mots *classe*, *objet* ou *méthode* ne sont pas clairs, relisez d'abord la [fiche de révision POO](../FICHE_REVISION.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Avant de commencer : la méthode
|
||||||
|
|
||||||
|
### Quatre mots de vocabulaire
|
||||||
|
|
||||||
|
| Mot | Ce que c'est | Dans le TP |
|
||||||
|
|:--|:--|:--|
|
||||||
|
| **Classe** | Le moule, le plan de fabrication | `Pokemon` |
|
||||||
|
| **Objet** (ou instance) | Une chose fabriquée avec le moule | `pikachu`, `salameche` |
|
||||||
|
| **Attribut** | Une information rangée dans l'objet | `self.pv`, `self.nom` |
|
||||||
|
| **Méthode** | Une fonction rangée dans la classe, qui agit sur l'objet | `attaquer`, `soigner` |
|
||||||
|
|
||||||
|
### Que veut dire `self` ?
|
||||||
|
|
||||||
|
`self` désigne **l'objet sur lequel on appelle la méthode**. Quand vous écrivez `pikachu.soigner(20)`, Python exécute la méthode `soigner` en remplaçant `self` par `pikachu`. Lire `self.pv`, c'est donc lire « les PV de **ce** Pokémon-là ».
|
||||||
|
|
||||||
|
Règle à retenir : **dans une méthode, chaque attribut s'écrit avec `self.` devant**, sans exception.
|
||||||
|
|
||||||
|
### Par où commencer une méthode ?
|
||||||
|
|
||||||
|
Devant une méthode vide, ne cherchez pas le code tout de suite. Répondez dans l'ordre à ces trois questions, en français, sur votre brouillon :
|
||||||
|
|
||||||
|
1. **De quoi ai-je besoin ?** Regardez les paramètres (entre parenthèses) et les attributs de l'objet (`self.quelque_chose`).
|
||||||
|
2. **Que dois-je produire ?** Trois cas possibles, la docstring vous le dit :
|
||||||
|
- **renvoyer** une valeur (`:return:` dans la docstring), donc il faut un `return` ;
|
||||||
|
- **modifier** un attribut, donc il faut une ligne `self.attribut = ...` ;
|
||||||
|
- **afficher** un message, donc il faut un `print`.
|
||||||
|
3. **Quelles sont les étapes ?** Écrivez-les en français, une par ligne. Ensuite seulement, traduisez chaque étape en Python.
|
||||||
|
|
||||||
|
C'est exactement ce que font les blocs « Par où commencer » de ce corrigé.
|
||||||
|
|
||||||
|
### Les trois erreurs les plus fréquentes
|
||||||
|
|
||||||
|
!!! warning "Oublier `self`"
|
||||||
|
Trois formes différentes, trois messages d'erreur différents :
|
||||||
|
|
||||||
|
| Ce que vous avez écrit | Ce qu'il faut écrire | Message de Python |
|
||||||
|
|:--|:--|:--|
|
||||||
|
| `nom = nom` dans `__init__` | `self.nom = nom` | `AttributeError: 'Pokemon' object has no attribute 'nom'` (l'attribut n'a jamais été créé) |
|
||||||
|
| `return pv <= 0` | `return self.pv <= 0` | `NameError: name 'pv' is not defined` |
|
||||||
|
| `def est_ko():` | `def est_ko(self):` | `TypeError: Pokemon.est_ko() takes 0 positional arguments but 1 was given` |
|
||||||
|
|
||||||
|
Le dernier message est déroutant : vous n'avez passé aucun argument, et Python dit en avoir reçu un. Cet argument, c'est l'objet lui-même, que Python place automatiquement dans `self`.
|
||||||
|
|
||||||
|
!!! warning "Les virgules dans les f-strings"
|
||||||
|
Dans une f-string, **chaque paire d'accolades contient une seule valeur**. Tout ce qui est entre les accolades (espaces, parenthèses, tirets, virgules) est recopié tel quel.
|
||||||
|
|
||||||
|
| Ce que vous avez écrit | Ce qui s'affiche |
|
||||||
|
|:--|:--|
|
||||||
|
| `f"{self.nom, self.type_pokemon}"` | `('Pikachu', 'Electrik')` : la virgule dans l'accolade crée un tuple |
|
||||||
|
| `return f"{self.nom}", f"({self.type_pokemon})"` | `TypeError: __str__ returned non-string (type tuple)` : la virgule après le `return` renvoie deux chaînes au lieu d'une |
|
||||||
|
| `"{self.nom} ({self.type_pokemon})"` | `{self.nom} ({self.type_pokemon})` : sans le `f` devant, les accolades ne sont pas remplacées |
|
||||||
|
| `f"{self.nom} ({self.type_pokemon})"` | `Pikachu (Electrik)` : correct |
|
||||||
|
|
||||||
|
Méthode sûre : **écrivez d'abord le texte attendu**, par exemple `Pikachu (Electrik) - Nv.25 - 80/80 PV`, puis remplacez chaque valeur variable par une accolade : `{self.nom} ({self.type_pokemon}) - Nv.{self.niveau} - {self.pv}/{self.pv_max} PV`. Ajoutez le `f` et les guillemets.
|
||||||
|
|
||||||
|
!!! warning "Afficher au lieu de renvoyer"
|
||||||
|
`print` montre une valeur à l'écran, mais le programme ne peut plus s'en servir. `return` donne la valeur au programme. Quand la docstring contient `:return:`, il faut un `return`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partie 1 : La classe Pokémon
|
||||||
|
|
||||||
|
### Exercice 1 : Créer la classe de base
|
||||||
|
|
||||||
|
??? tip "Par où commencer"
|
||||||
|
1. **De quoi ai-je besoin ?** Les paramètres de `__init__` : `nom`, `type_pokemon`, `niveau`, `pv_max`, `attaque`.
|
||||||
|
2. **Que dois-je produire ?** `__init__` ne renvoie rien : son rôle est de **ranger** chaque information dans l'objet, sous forme d'attribut.
|
||||||
|
3. **Les étapes :**
|
||||||
|
- pour chaque paramètre, créer l'attribut correspondant : `self.nom = nom`, etc. ;
|
||||||
|
- créer l'attribut `pv`, qui n'est pas un paramètre : un Pokémon neuf a tous ses PV, donc `self.pv = pv_max`.
|
||||||
|
|
||||||
|
Pour `__repr__` : la docstring demande une chaîne. Écrivez le texte attendu de l'énoncé, `Pikachu (Electrik) - Nv.25 - 80/80 PV`, puis remplacez chaque valeur par l'attribut correspondant entre accolades.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Pokemon:
|
||||||
|
def __init__(self, nom, type_pokemon, niveau=1, pv_max=100, attaque=10):
|
||||||
|
"""
|
||||||
|
Constructeur de la classe Pokemon.
|
||||||
|
|
||||||
|
:param nom: (str) Nom du Pokémon
|
||||||
|
:param type_pokemon: (str) Type élémentaire
|
||||||
|
:param niveau: (int) Niveau du Pokémon
|
||||||
|
:param pv_max: (int) Points de vie maximum
|
||||||
|
:param attaque: (int) Puissance d'attaque
|
||||||
|
"""
|
||||||
|
self.nom = nom # on range le paramètre nom dans l'objet
|
||||||
|
self.type_pokemon = type_pokemon
|
||||||
|
self.niveau = niveau
|
||||||
|
self.pv_max = pv_max
|
||||||
|
self.pv = pv_max # pas de paramètre pv : on démarre avec tous ses PV
|
||||||
|
self.attaque = attaque
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Représentation textuelle du Pokémon."""
|
||||||
|
return f"{self.nom} ({self.type_pokemon}) - Nv.{self.niveau} - {self.pv}/{self.pv_max} PV"
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
```python
|
||||||
|
pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Python fabrique un objet vide, et le place dans `self`.
|
||||||
|
2. Il exécute `__init__` avec `nom = "Pikachu"`, `type_pokemon = "Electrik"`, `niveau = 25`, `pv_max = 80`, `attaque = 15`.
|
||||||
|
3. Chaque ligne `self.... = ...` remplit l'objet. À la fin, l'objet contient : `nom` vaut `"Pikachu"`, `type_pokemon` vaut `"Electrik"`, `niveau` vaut 25, `pv_max` vaut 80, `pv` vaut 80, `attaque` vaut 15.
|
||||||
|
4. L'objet est rangé dans la variable `pikachu`.
|
||||||
|
|
||||||
|
Ensuite, `print(pikachu)` appelle automatiquement `__repr__` : `{self.nom}` est remplacé par `Pikachu`, `{self.pv}` par `80`, etc. On obtient `Pikachu (Electrik) - Nv.25 - 80/80 PV`.
|
||||||
|
|
||||||
|
Remarquez que `__init__` a 6 paramètres (`self` compris) mais qu'on ne lui en donne que 5 : `self`, c'est Python qui le fournit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Exercice 2 : Méthodes de combat
|
||||||
|
|
||||||
|
Ces méthodes s'ajoutent dans la classe `Pokemon`, avec la même indentation que `__repr__`.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `est_ko`"
|
||||||
|
1. **De quoi ai-je besoin ?** Aucun paramètre à part `self`. L'attribut utile est `self.pv`.
|
||||||
|
2. **Que dois-je produire ?** La docstring dit `:return: (bool)` : il faut **renvoyer** `True` ou `False`.
|
||||||
|
3. **Les étapes :** regarder si les PV sont inférieurs ou égaux à 0, et renvoyer la réponse.
|
||||||
|
|
||||||
|
`self.pv <= 0` est déjà une expression qui vaut `True` ou `False` : on peut la renvoyer directement.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `subir_degats`"
|
||||||
|
1. **De quoi ai-je besoin ?** Le paramètre `degats`, et l'attribut `self.pv`.
|
||||||
|
2. **Que dois-je produire ?** Pas de `:return:` dans la docstring. On **modifie** un attribut : `self.pv`.
|
||||||
|
3. **Les étapes :**
|
||||||
|
- enlever les dégâts aux PV ;
|
||||||
|
- si les PV sont passés sous 0, les remettre à 0.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `attaquer`"
|
||||||
|
1. **De quoi ai-je besoin ?** Le paramètre `cible`, qui est **un objet `Pokemon`** (la docstring le précise : `(Pokemon)`). On a donc accès à `cible.nom`, `cible.pv`, et à ses méthodes. On a aussi `self.attaque` et `self.nom`.
|
||||||
|
2. **Que dois-je produire ?** Un **affichage**, et une **modification** : les PV de la cible baissent.
|
||||||
|
3. **Les étapes :**
|
||||||
|
- afficher le message de l'énoncé : `Pikachu attaque Salamèche et inflige 15 dégâts !` ;
|
||||||
|
- faire subir les dégâts à la cible. Pas besoin de réécrire le calcul : la méthode `subir_degats` existe déjà, on l'appelle **sur la cible**.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `soigner`"
|
||||||
|
C'est le miroir de `subir_degats` :
|
||||||
|
|
||||||
|
- ajouter le soin aux PV ;
|
||||||
|
- si les PV dépassent `pv_max`, les ramener à `pv_max`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def est_ko(self):
|
||||||
|
"""
|
||||||
|
Vérifie si le Pokémon est KO.
|
||||||
|
|
||||||
|
:return: (bool) True si PV <= 0, False sinon
|
||||||
|
"""
|
||||||
|
return self.pv <= 0
|
||||||
|
|
||||||
|
def subir_degats(self, degats):
|
||||||
|
"""
|
||||||
|
Inflige des dégâts au Pokémon.
|
||||||
|
Les PV ne peuvent pas descendre en dessous de 0.
|
||||||
|
|
||||||
|
:param degats: (int) Nombre de dégâts subis
|
||||||
|
"""
|
||||||
|
self.pv = self.pv - degats
|
||||||
|
if self.pv < 0: # on ne descend pas sous 0
|
||||||
|
self.pv = 0
|
||||||
|
|
||||||
|
def attaquer(self, cible):
|
||||||
|
"""
|
||||||
|
Attaque un autre Pokémon.
|
||||||
|
Affiche un message et inflige des dégâts à la cible.
|
||||||
|
|
||||||
|
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
||||||
|
"""
|
||||||
|
print(f"{self.nom} attaque {cible.nom} et inflige {self.attaque} dégâts !")
|
||||||
|
cible.subir_degats(self.attaque) # c'est la cible qui perd des PV
|
||||||
|
|
||||||
|
def soigner(self, soin):
|
||||||
|
"""
|
||||||
|
Soigne le Pokémon.
|
||||||
|
Les PV ne peuvent pas dépasser pv_max.
|
||||||
|
|
||||||
|
:param soin: (int) Nombre de PV récupérés
|
||||||
|
"""
|
||||||
|
self.pv = self.pv + soin
|
||||||
|
if self.pv > self.pv_max: # on ne dépasse pas le maximum
|
||||||
|
self.pv = self.pv_max
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
```python
|
||||||
|
pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
||||||
|
salameche = Pokemon("Salamèche", "Feu", niveau=20, pv_max=70, attaque=12)
|
||||||
|
pikachu.attaquer(salameche)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. On appelle `attaquer` **sur `pikachu`** : dans la méthode, `self` vaut `pikachu`, et `cible` vaut `salameche`.
|
||||||
|
2. Le `print` affiche `Pikachu attaque Salamèche et inflige 15 dégâts !` : `self.nom` donne `Pikachu`, `cible.nom` donne `Salamèche`, `self.attaque` donne 15.
|
||||||
|
3. La ligne `cible.subir_degats(self.attaque)` appelle `subir_degats` **sur `salameche`** avec `degats = 15`. Dans cette nouvelle méthode, `self` vaut maintenant `salameche`.
|
||||||
|
4. `self.pv = self.pv - degats` : les PV de Salamèche passent de 70 à 55. 55 n'est pas négatif, le `if` ne fait rien.
|
||||||
|
5. `salameche.est_ko()` calcule `55 <= 0`, ce qui vaut `False`.
|
||||||
|
|
||||||
|
Le point clé : `self` ne désigne pas toujours le même Pokémon. Il désigne celui **devant le point** au moment de l'appel.
|
||||||
|
|
||||||
|
!!! note "Une version plus courte"
|
||||||
|
`self.pv = max(0, self.pv - degats)` fait la même chose que les trois lignes de `subir_degats` : on garde le plus grand entre 0 et le résultat. De même, `self.pv = min(self.pv_max, self.pv + soin)` pour `soigner`. Les deux versions sont correctes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Exercice 3 : Système de faiblesses (Bonus)
|
||||||
|
|
||||||
|
??? tip "Par où commencer"
|
||||||
|
1. **Comprendre le dictionnaire.** `FAIBLESSES["Eau"]` vaut `["Feu"]` : l'Eau est super efficace contre le Feu. La clé est le type de **l'attaquant**, la valeur est la liste des types **qu'il bat**.
|
||||||
|
2. **Que change cette version ?** Les dégâts ne valent plus toujours `self.attaque` : ils peuvent doubler. On a donc besoin d'une variable `degats`.
|
||||||
|
3. **Les étapes :**
|
||||||
|
- mettre `self.attaque` dans une variable `degats` ;
|
||||||
|
- si le type de l'attaquant est dans le dictionnaire, **et** si le type de la cible est dans sa liste, doubler `degats` et afficher `C'est super efficace !` ;
|
||||||
|
- afficher le message d'attaque avec `degats` ;
|
||||||
|
- faire subir `degats` à la cible.
|
||||||
|
|
||||||
|
Le dictionnaire est placé **en dehors** de la classe, en début de programme.
|
||||||
|
|
||||||
|
```python
|
||||||
|
FAIBLESSES = {
|
||||||
|
"Eau": ["Feu"],
|
||||||
|
"Feu": ["Plante"],
|
||||||
|
"Plante": ["Eau"],
|
||||||
|
"Electrik": ["Eau"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
La nouvelle méthode `attaquer` remplace celle de l'exercice 2 :
|
||||||
|
|
||||||
|
```python
|
||||||
|
def attaquer(self, cible):
|
||||||
|
"""
|
||||||
|
Attaque un autre Pokémon avec prise en compte des faiblesses.
|
||||||
|
|
||||||
|
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
||||||
|
"""
|
||||||
|
degats = self.attaque # variable locale : on ne touche pas à self.attaque
|
||||||
|
|
||||||
|
# Vérifier si le type de la cible est faible contre notre type
|
||||||
|
if self.type_pokemon in FAIBLESSES:
|
||||||
|
if cible.type_pokemon in FAIBLESSES[self.type_pokemon]:
|
||||||
|
degats = degats * 2
|
||||||
|
print("C'est super efficace !")
|
||||||
|
|
||||||
|
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
|
||||||
|
cible.subir_degats(degats)
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
```python
|
||||||
|
tortank = Pokemon("Tortank", "Eau", 45, 140, 22)
|
||||||
|
dracaufeu = Pokemon("Dracaufeu", "Feu", 50, 150, 25)
|
||||||
|
tortank.attaquer(dracaufeu)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. `self` vaut `tortank`, `cible` vaut `dracaufeu`. `degats` vaut 22.
|
||||||
|
2. `self.type_pokemon in FAIBLESSES` : `"Eau"` est bien une clé du dictionnaire.
|
||||||
|
3. `FAIBLESSES["Eau"]` vaut `["Feu"]`, et `cible.type_pokemon` vaut `"Feu"` : il est dans la liste. `degats` passe à 44, et Python affiche `C'est super efficace !`.
|
||||||
|
4. Puis `Tortank attaque Dracaufeu et inflige 44 dégâts !`, et Dracaufeu passe de 150 à 106 PV.
|
||||||
|
|
||||||
|
Si un Onix (type `"Roche"`) attaquait, le premier `if` serait faux, car `"Roche"` n'est pas une clé : les dégâts resteraient normaux. Sans ce premier test, `FAIBLESSES["Roche"]` provoquerait une erreur `KeyError`.
|
||||||
|
|
||||||
|
!!! warning "Erreur fréquente"
|
||||||
|
Écrire `self.attaque = self.attaque * 2` au lieu de passer par `degats`. L'attaque du Pokémon serait doublée **pour toujours**, et redoublée à chaque coup super efficace.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partie 2 : La classe Dresseur
|
||||||
|
|
||||||
|
### Exercice 4 : Créer la classe Dresseur
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `__init__`"
|
||||||
|
Deux attributs : `nom` est donné en paramètre, mais `equipe` ne l'est pas. Un dresseur commence sans Pokémon : `self.equipe = []`.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `ajouter_pokemon`"
|
||||||
|
1. **De quoi ai-je besoin ?** Le paramètre `pokemon`, et l'attribut `self.equipe`.
|
||||||
|
2. **Que dois-je produire ?** **Modifier** l'équipe si c'est possible, et **renvoyer** `True` ou `False` (`:return:`).
|
||||||
|
3. **Les étapes :**
|
||||||
|
- si l'équipe compte moins de 6 Pokémon, ajouter le Pokémon à la liste et renvoyer `True` ;
|
||||||
|
- sinon, renvoyer `False`.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `pokemon_disponibles`, `premier_pokemon_dispo`, `tous_ko`"
|
||||||
|
Ces trois méthodes parcourent l'équipe avec une boucle `for pokemon in self.equipe:`. À chaque tour, `pokemon` est un objet `Pokemon` : on peut donc lui demander `pokemon.est_ko()`.
|
||||||
|
|
||||||
|
- `pokemon_disponibles` : partir d'une liste vide, y ajouter chaque Pokémon qui n'est pas KO, renvoyer la liste.
|
||||||
|
- `premier_pokemon_dispo` : dès qu'on trouve un Pokémon qui n'est pas KO, le renvoyer. Si la boucle se termine sans rien trouver, renvoyer `None`.
|
||||||
|
- `tous_ko` : tous les Pokémon sont KO quand la liste des disponibles est vide. On réutilise la méthode précédente.
|
||||||
|
|
||||||
|
??? tip "Par où commencer : `__repr__`"
|
||||||
|
Le texte attendu tient sur plusieurs lignes :
|
||||||
|
|
||||||
|
```
|
||||||
|
Dresseur Sacha - 2 Pokémon
|
||||||
|
- Pikachu (Electrik) - Nv.25 - 80/80 PV
|
||||||
|
- Dracaufeu (Feu) - Nv.50 - 150/150 PV
|
||||||
|
```
|
||||||
|
|
||||||
|
- Construire la première ligne dans une variable `texte`.
|
||||||
|
- Pour chaque Pokémon de l'équipe, ajouter à `texte` un retour à la ligne (`\n`), deux espaces, un tiret, et le Pokémon.
|
||||||
|
- Renvoyer `texte`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Dresseur:
|
||||||
|
def __init__(self, nom):
|
||||||
|
"""
|
||||||
|
Constructeur de la classe Dresseur.
|
||||||
|
|
||||||
|
:param nom: (str) Nom du dresseur
|
||||||
|
"""
|
||||||
|
self.nom = nom
|
||||||
|
self.equipe = [] # pas de paramètre : chaque dresseur démarre avec une équipe vide
|
||||||
|
|
||||||
|
def ajouter_pokemon(self, pokemon):
|
||||||
|
"""
|
||||||
|
Ajoute un Pokémon à l'équipe si possible (max 6).
|
||||||
|
|
||||||
|
:param pokemon: (Pokemon) Pokémon à ajouter
|
||||||
|
:return: (bool) True si ajouté, False sinon
|
||||||
|
"""
|
||||||
|
if len(self.equipe) < 6:
|
||||||
|
self.equipe.append(pokemon)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def pokemon_disponibles(self):
|
||||||
|
"""
|
||||||
|
Renvoie la liste des Pokémon non KO.
|
||||||
|
|
||||||
|
:return: (list) Liste des Pokémon encore en état de combattre
|
||||||
|
"""
|
||||||
|
disponibles = []
|
||||||
|
for pokemon in self.equipe:
|
||||||
|
if not pokemon.est_ko(): # on demande au Pokémon s'il est KO
|
||||||
|
disponibles.append(pokemon)
|
||||||
|
return disponibles
|
||||||
|
|
||||||
|
def premier_pokemon_dispo(self):
|
||||||
|
"""
|
||||||
|
Renvoie le premier Pokémon non KO.
|
||||||
|
|
||||||
|
:return: (Pokemon/None) Premier Pokémon dispo ou None
|
||||||
|
"""
|
||||||
|
for pokemon in self.equipe:
|
||||||
|
if not pokemon.est_ko():
|
||||||
|
return pokemon # le return arrête la boucle immédiatement
|
||||||
|
return None # on n'arrive ici que si aucun n'est disponible
|
||||||
|
|
||||||
|
def tous_ko(self):
|
||||||
|
"""
|
||||||
|
Vérifie si tous les Pokémon sont KO.
|
||||||
|
|
||||||
|
:return: (bool) True si tous KO, False sinon
|
||||||
|
"""
|
||||||
|
return len(self.pokemon_disponibles()) == 0
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""Représentation du dresseur."""
|
||||||
|
texte = f"Dresseur {self.nom} - {len(self.equipe)} Pokémon"
|
||||||
|
for pokemon in self.equipe:
|
||||||
|
texte = texte + f"\n - {pokemon}" # {pokemon} utilise le __repr__ de Pokemon
|
||||||
|
return texte
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
```python
|
||||||
|
sacha = Dresseur("Sacha")
|
||||||
|
sacha.ajouter_pokemon(Pokemon("Pikachu", "Electrik", 25, 80, 15))
|
||||||
|
```
|
||||||
|
|
||||||
|
1. `sacha` est créé avec `nom` qui vaut `"Sacha"` et `equipe` qui vaut `[]`.
|
||||||
|
2. `ajouter_pokemon` : `len(self.equipe)` vaut 0, qui est inférieur à 6. Le Pokémon est ajouté, la méthode renvoie `True`.
|
||||||
|
|
||||||
|
Si Pikachu tombe KO et qu'on appelle `sacha.premier_pokemon_dispo()` :
|
||||||
|
|
||||||
|
1. premier tour de boucle, `pokemon` vaut Pikachu, `pokemon.est_ko()` vaut `True`, donc `not True` vaut `False` : on passe au suivant ;
|
||||||
|
2. deuxième tour, `pokemon` vaut Dracaufeu, qui n'est pas KO : la méthode renvoie Dracaufeu et s'arrête.
|
||||||
|
|
||||||
|
!!! warning "Erreur fréquente"
|
||||||
|
Mettre le `return None` **dans** la boucle, au même niveau que le `if`. La méthode s'arrêterait alors dès le premier Pokémon KO, sans regarder les suivants. Le `return None` se place **après** la boucle, aligné avec le `for`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partie 3 : La classe Combat
|
||||||
|
|
||||||
|
### Exercice 5 : Simulateur de combat
|
||||||
|
|
||||||
|
??? tip "Par où commencer"
|
||||||
|
Une bonne partie du code est déjà donnée. Avant de compléter, **jouez un tour à la main** sur votre brouillon : Pikachu (80 PV, attaque 15) contre Onix (120 PV, attaque 18).
|
||||||
|
|
||||||
|
- Pikachu attaque Onix. Onix est-il KO ? Non : il riposte.
|
||||||
|
- Onix attaque Pikachu. Pikachu est-il KO ? Non : on passe au tour suivant.
|
||||||
|
|
||||||
|
Traduisez ensuite chaque commentaire `# À compléter` :
|
||||||
|
|
||||||
|
1. **Le Pokémon 1 attaque** : une seule ligne, `poke1.attaquer(poke2)`.
|
||||||
|
2. **Vérifier si le Pokémon 2 est KO** : `if poke2.est_ko():`. Si oui, on l'annonce, et on annonce le remplaçant s'il y en a un.
|
||||||
|
3. **Le Pokémon 2 attaque (s'il n'est pas KO)** : c'est le `else` du test précédent. Un Pokémon KO ne riposte pas.
|
||||||
|
4. **Vérifier si le Pokémon 1 est KO** : même chose que l'étape 2, dans l'autre sens.
|
||||||
|
5. **Afficher le vainqueur** : après la boucle, l'un des deux dresseurs n'a plus de Pokémon. Si c'est le dresseur 1, le dresseur 2 a gagné, et inversement.
|
||||||
|
|
||||||
|
Pour `afficher_etat`, on récupère le Pokémon actif de chaque dresseur avec `premier_pokemon_dispo()`, puis on affiche son nom et ses PV.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Combat:
|
||||||
|
def __init__(self, dresseur1, dresseur2):
|
||||||
|
"""
|
||||||
|
Constructeur de la classe Combat.
|
||||||
|
|
||||||
|
:param dresseur1: (Dresseur) Premier dresseur
|
||||||
|
:param dresseur2: (Dresseur) Second dresseur
|
||||||
|
"""
|
||||||
|
self.dresseur1 = dresseur1
|
||||||
|
self.dresseur2 = dresseur2
|
||||||
|
self.tour = 0
|
||||||
|
|
||||||
|
def afficher_etat(self):
|
||||||
|
"""Affiche l'état actuel du combat."""
|
||||||
|
print(f"\n{'='*40}")
|
||||||
|
print(f"Tour {self.tour}")
|
||||||
|
print(f"{'='*40}")
|
||||||
|
poke1 = self.dresseur1.premier_pokemon_dispo()
|
||||||
|
poke2 = self.dresseur2.premier_pokemon_dispo()
|
||||||
|
print(f"{self.dresseur1.nom}: {poke1.nom} ({poke1.pv}/{poke1.pv_max} PV)")
|
||||||
|
print(f"{self.dresseur2.nom}: {poke2.nom} ({poke2.pv}/{poke2.pv_max} PV)")
|
||||||
|
print()
|
||||||
|
|
||||||
|
def lancer_combat(self):
|
||||||
|
"""
|
||||||
|
Lance le combat tour par tour.
|
||||||
|
Chaque tour, les deux Pokémon actifs s'attaquent.
|
||||||
|
Quand un Pokémon est KO, le suivant prend sa place.
|
||||||
|
Le combat s'arrête quand un dresseur n'a plus de Pokémon.
|
||||||
|
"""
|
||||||
|
print(f"\n*** COMBAT : {self.dresseur1.nom} VS {self.dresseur2.nom} ***\n")
|
||||||
|
|
||||||
|
while not self.dresseur1.tous_ko() and not self.dresseur2.tous_ko():
|
||||||
|
self.tour += 1
|
||||||
|
self.afficher_etat()
|
||||||
|
|
||||||
|
# Récupérer les Pokémon actifs
|
||||||
|
poke1 = self.dresseur1.premier_pokemon_dispo()
|
||||||
|
poke2 = self.dresseur2.premier_pokemon_dispo()
|
||||||
|
|
||||||
|
# Le Pokémon 1 attaque
|
||||||
|
poke1.attaquer(poke2)
|
||||||
|
|
||||||
|
# Vérifier si Pokémon 2 est KO
|
||||||
|
if poke2.est_ko():
|
||||||
|
print(f"\n{poke2.nom} est KO !")
|
||||||
|
suivant = self.dresseur2.premier_pokemon_dispo()
|
||||||
|
if suivant is not None:
|
||||||
|
print(f"{self.dresseur2.nom} envoie {suivant.nom} !")
|
||||||
|
else:
|
||||||
|
# Le Pokémon 2 attaque (s'il n'est pas KO)
|
||||||
|
poke2.attaquer(poke1)
|
||||||
|
|
||||||
|
# Vérifier si Pokémon 1 est KO
|
||||||
|
if poke1.est_ko():
|
||||||
|
print(f"\n{poke1.nom} est KO !")
|
||||||
|
suivant = self.dresseur1.premier_pokemon_dispo()
|
||||||
|
if suivant is not None:
|
||||||
|
print(f"{self.dresseur1.nom} envoie {suivant.nom} !")
|
||||||
|
|
||||||
|
# Afficher le vainqueur
|
||||||
|
print(f"\n{'='*40}")
|
||||||
|
if self.dresseur1.tous_ko():
|
||||||
|
print(f"Tous les Pokémon de {self.dresseur1.nom} sont KO !")
|
||||||
|
print(f"*** {self.dresseur2.nom.upper()} REMPORTE LE COMBAT ! ***")
|
||||||
|
else:
|
||||||
|
print(f"Tous les Pokémon de {self.dresseur2.nom} sont KO !")
|
||||||
|
print(f"*** {self.dresseur1.nom.upper()} REMPORTE LE COMBAT ! ***")
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
Sacha (Pikachu, Dracaufeu, Tortank) contre Pierre (Onix, Racaillou).
|
||||||
|
|
||||||
|
**Tour 1.** Les Pokémon actifs sont Pikachu (80 PV) et Onix (120 PV).
|
||||||
|
|
||||||
|
- Pikachu attaque : Onix passe à 105 PV. Il n'est pas KO, donc on entre dans le `else`.
|
||||||
|
- Onix riposte : Pikachu passe à 62 PV. Il n'est pas KO.
|
||||||
|
- Fin du tour. La condition du `while` est toujours vraie : chaque dresseur a encore des Pokémon debout.
|
||||||
|
|
||||||
|
**Quelques tours plus tard**, Pikachu tombe à 0 PV pendant la riposte d'Onix. On affiche `Pikachu est KO !`, puis `premier_pokemon_dispo()` renvoie Dracaufeu : `Sacha envoie Dracaufeu !`.
|
||||||
|
|
||||||
|
**Au tour suivant**, on n'a rien eu à faire pour changer de Pokémon : `premier_pokemon_dispo()` saute Pikachu, qui est KO, et renvoie Dracaufeu.
|
||||||
|
|
||||||
|
**À la fin**, Racaillou tombe KO. `pierre.tous_ko()` vaut `True`, la condition du `while` devient fausse et la boucle s'arrête. Le `if` final affiche que Sacha remporte le combat.
|
||||||
|
|
||||||
|
!!! warning "Erreur fréquente"
|
||||||
|
Oublier le `else` et faire riposter le Pokémon 2 même s'il vient d'être mis KO. On voit alors un Pokémon à 0 PV attaquer, ce qui est le signe de cette erreur.
|
||||||
|
|
||||||
|
!!! note "Pourquoi `afficher_etat` ne vérifie pas `None`"
|
||||||
|
`afficher_etat` est appelée au début d'un tour, donc seulement quand la condition du `while` est vraie : chaque dresseur a forcément un Pokémon disponible. `premier_pokemon_dispo()` ne peut pas renvoyer `None` à ce moment-là.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partie 4 : Améliorations
|
||||||
|
|
||||||
|
### Exercice 6 : Centre Pokémon
|
||||||
|
|
||||||
|
??? tip "Par où commencer"
|
||||||
|
1. **De quoi ai-je besoin ?** Le paramètre `dresseur`. Son équipe est accessible par `dresseur.equipe`.
|
||||||
|
2. **Que dois-je produire ?** **Modifier** les PV de chaque Pokémon de l'équipe, et afficher un message d'accueil.
|
||||||
|
3. **Les étapes :**
|
||||||
|
- afficher un message de bienvenue ;
|
||||||
|
- pour chaque Pokémon de l'équipe, remettre ses PV au maximum ;
|
||||||
|
- afficher un message de fin.
|
||||||
|
|
||||||
|
Pour remettre les PV au maximum, on peut réutiliser `soigner` : soigner de `pv_max` PV ramène forcément à `pv_max`, puisque `soigner` plafonne.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CentrePokemon:
|
||||||
|
def __init__(self, ville):
|
||||||
|
"""
|
||||||
|
:param ville: (str) Ville où se trouve le centre
|
||||||
|
"""
|
||||||
|
self.ville = ville
|
||||||
|
|
||||||
|
def soigner_equipe(self, dresseur):
|
||||||
|
"""
|
||||||
|
Soigne tous les Pokémon d'un dresseur à 100% de leurs PV.
|
||||||
|
|
||||||
|
:param dresseur: (Dresseur) Dresseur dont l'équipe doit être soignée
|
||||||
|
"""
|
||||||
|
print(f"Bienvenue au Centre Pokémon de {self.ville}, {dresseur.nom} !")
|
||||||
|
for pokemon in dresseur.equipe:
|
||||||
|
pokemon.soigner(pokemon.pv_max)
|
||||||
|
print("Vos Pokémon sont en pleine forme !")
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
Après le combat, Dracaufeu a 96 PV sur 150. `centre.soigner_equipe(sacha)` parcourt l'équipe de Sacha. Arrivé à Dracaufeu, il appelle `soigner(150)` : 96 + 150 = 246, ce qui dépasse 150, donc les PV sont ramenés à 150.
|
||||||
|
|
||||||
|
Remarquez la chaîne d'objets : le **centre** reçoit un **dresseur**, qui contient une **équipe**, qui contient des **Pokémon**, sur lesquels on appelle `soigner`.
|
||||||
|
|
||||||
|
On aurait aussi pu écrire `pokemon.pv = pokemon.pv_max`. Passer par la méthode `soigner` est plus propre : c'est le Pokémon qui gère ses propres PV.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Exercice 7 : Capacités spéciales (Pour aller plus loin)
|
||||||
|
|
||||||
|
??? tip "Par où commencer"
|
||||||
|
L'énoncé est plus ouvert : c'est à vous de choisir les méthodes. Posez-vous la question « qu'est-ce qu'un Pokémon doit pouvoir **faire** avec ses capacités ? ».
|
||||||
|
|
||||||
|
- **Apprendre** une capacité : l'ajouter à une liste, 4 au maximum. C'est le même principe que `ajouter_pokemon` du dresseur.
|
||||||
|
- **Attaquer avec** une capacité : choisir laquelle, vérifier qu'il reste des PP, calculer les dégâts, les infliger.
|
||||||
|
|
||||||
|
Pour stocker les capacités, il faut un nouvel attribut dans `Pokemon` : une liste vide, créée dans `__init__`.
|
||||||
|
|
||||||
|
On complète la classe `Capacite` avec une méthode qui consomme un PP :
|
||||||
|
|
||||||
|
```python
|
||||||
|
class Capacite:
|
||||||
|
def __init__(self, nom, puissance, type_capacite, pp_max):
|
||||||
|
"""
|
||||||
|
:param nom: (str) Nom de la capacité
|
||||||
|
:param puissance: (int) Puissance de base
|
||||||
|
:param type_capacite: (str) Type de la capacité
|
||||||
|
:param pp_max: (int) Nombre d'utilisations max
|
||||||
|
"""
|
||||||
|
self.nom = nom
|
||||||
|
self.puissance = puissance
|
||||||
|
self.type_capacite = type_capacite
|
||||||
|
self.pp_max = pp_max
|
||||||
|
self.pp = pp_max
|
||||||
|
|
||||||
|
def utiliser(self):
|
||||||
|
"""
|
||||||
|
Consomme un PP si possible.
|
||||||
|
|
||||||
|
:return: (bool) True si la capacité a pu être utilisée, False sinon
|
||||||
|
"""
|
||||||
|
if self.pp > 0:
|
||||||
|
self.pp -= 1
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.nom} ({self.type_capacite}) - {self.puissance} DMG - {self.pp}/{self.pp_max} PP"
|
||||||
|
```
|
||||||
|
|
||||||
|
Côté `Pokemon`, on ajoute la ligne `self.capacites = []` à la fin de `__init__`, puis deux méthodes :
|
||||||
|
|
||||||
|
```python
|
||||||
|
def apprendre(self, capacite):
|
||||||
|
"""
|
||||||
|
Ajoute une capacité au Pokémon (4 au maximum).
|
||||||
|
|
||||||
|
:param capacite: (Capacite) Capacité à apprendre
|
||||||
|
:return: (bool) True si apprise, False sinon
|
||||||
|
"""
|
||||||
|
if len(self.capacites) < 4:
|
||||||
|
self.capacites.append(capacite)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def attaquer_avec(self, numero, cible):
|
||||||
|
"""
|
||||||
|
Attaque la cible avec la capacité numéro numero.
|
||||||
|
|
||||||
|
:param numero: (int) Indice de la capacité dans self.capacites
|
||||||
|
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
||||||
|
"""
|
||||||
|
capacite = self.capacites[numero] # un objet Capacite
|
||||||
|
if capacite.utiliser(): # consomme un PP, renvoie False s'il n'en reste plus
|
||||||
|
degats = self.attaque + capacite.puissance
|
||||||
|
print(f"{self.nom} utilise {capacite.nom} et inflige {degats} dégâts !")
|
||||||
|
cible.subir_degats(degats)
|
||||||
|
else:
|
||||||
|
print(f"{capacite.nom} n'a plus de PP !")
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Ce qui se passe à l'exécution"
|
||||||
|
```python
|
||||||
|
pikachu = Pokemon("Pikachu", "Electrik", 25, 80, 15)
|
||||||
|
onix = Pokemon("Onix", "Roche", 30, 120, 18)
|
||||||
|
pikachu.apprendre(Capacite("Tonnerre", 30, "Electrik", 2))
|
||||||
|
pikachu.attaquer_avec(0, onix)
|
||||||
|
```
|
||||||
|
|
||||||
|
1. `apprendre` : Pikachu n'a aucune capacité, il apprend Tonnerre, la méthode renvoie `True`.
|
||||||
|
2. `attaquer_avec(0, onix)` : `self.capacites[0]` est Tonnerre.
|
||||||
|
3. `capacite.utiliser()` : il reste 2 PP, on passe à 1, la méthode renvoie `True`.
|
||||||
|
4. Les dégâts valent 15 + 30 = 45. Python affiche `Pikachu utilise Tonnerre et inflige 45 dégâts !`, et Onix passe de 120 à 75 PV.
|
||||||
|
5. Au troisième appel, `utiliser()` renverra `False` et Python affichera `Tonnerre n'a plus de PP !`.
|
||||||
|
|
||||||
|
Remarquez le `if capacite.utiliser():` : la méthode **fait** quelque chose (elle consomme un PP) **et** renvoie une réponse qu'on teste directement.
|
||||||
|
|
||||||
|
C'est une **composition** d'objets : un `Pokemon` possède une liste d'objets `Capacite`, comme un `Dresseur` possède une liste d'objets `Pokemon`. La formule de dégâts (`attaque + puissance`) est un choix parmi d'autres : toute règle cohérente et justifiée est acceptée.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Auteurs : Florian Mathieu, Enzo Frémeaux, Timothée Decoster
|
||||||
|
|
||||||
|
Licence CC BY-SA
|
||||||
|
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||||
@@ -1,358 +0,0 @@
|
|||||||
"""
|
|
||||||
Corrigé du TP Pokémon Arena — Programmation Orientée Objet
|
|
||||||
"""
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# Dictionnaire des faiblesses (Bonus Exercice 3)
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
FAIBLESSES = {
|
|
||||||
"Eau": ["Feu"],
|
|
||||||
"Feu": ["Plante"],
|
|
||||||
"Plante": ["Eau"],
|
|
||||||
"Electrik": ["Eau"],
|
|
||||||
"Roche": ["Eau", "Plante"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# PARTIE 1 : Classe Pokemon
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
class Pokemon:
|
|
||||||
def __init__(self, nom, type_pokemon, niveau=1, pv_max=100, attaque=10):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Pokemon.
|
|
||||||
|
|
||||||
:param nom: (str) Nom du Pokémon
|
|
||||||
:param type_pokemon: (str) Type élémentaire
|
|
||||||
:param niveau: (int) Niveau du Pokémon
|
|
||||||
:param pv_max: (int) Points de vie maximum
|
|
||||||
:param attaque: (int) Puissance d'attaque
|
|
||||||
"""
|
|
||||||
self.nom = nom
|
|
||||||
self.type_pokemon = type_pokemon
|
|
||||||
self.niveau = niveau
|
|
||||||
self.pv_max = pv_max
|
|
||||||
self.pv = pv_max
|
|
||||||
self.attaque = attaque
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Représentation textuelle du Pokémon."""
|
|
||||||
return f"{self.nom} ({self.type_pokemon}) - Nv.{self.niveau} - {self.pv}/{self.pv_max} PV"
|
|
||||||
|
|
||||||
def est_ko(self):
|
|
||||||
"""
|
|
||||||
Vérifie si le Pokémon est KO.
|
|
||||||
|
|
||||||
:return: (bool) True si PV <= 0, False sinon
|
|
||||||
"""
|
|
||||||
return self.pv <= 0
|
|
||||||
|
|
||||||
def subir_degats(self, degats):
|
|
||||||
"""
|
|
||||||
Inflige des dégâts au Pokémon.
|
|
||||||
Les PV ne peuvent pas descendre en dessous de 0.
|
|
||||||
|
|
||||||
:param degats: (int) Nombre de dégâts subis
|
|
||||||
"""
|
|
||||||
self.pv = max(0, self.pv - degats)
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque un autre Pokémon avec prise en compte des faiblesses.
|
|
||||||
|
|
||||||
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
|
||||||
"""
|
|
||||||
degats = self.attaque
|
|
||||||
|
|
||||||
# Vérifier si le type de la cible est faible contre notre type
|
|
||||||
if self.type_pokemon in FAIBLESSES:
|
|
||||||
if cible.type_pokemon in FAIBLESSES[self.type_pokemon]:
|
|
||||||
degats *= 2
|
|
||||||
print(f"C'est super efficace !")
|
|
||||||
|
|
||||||
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
|
|
||||||
cible.subir_degats(degats)
|
|
||||||
|
|
||||||
def soigner(self, soin):
|
|
||||||
"""
|
|
||||||
Soigne le Pokémon.
|
|
||||||
Les PV ne peuvent pas dépasser pv_max.
|
|
||||||
|
|
||||||
:param soin: (int) Nombre de PV récupérés
|
|
||||||
"""
|
|
||||||
self.pv = min(self.pv_max, self.pv + soin)
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# PARTIE 2 : Classe Dresseur
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
class Dresseur:
|
|
||||||
def __init__(self, nom):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Dresseur.
|
|
||||||
|
|
||||||
:param nom: (str) Nom du dresseur
|
|
||||||
"""
|
|
||||||
self.nom = nom
|
|
||||||
self.equipe = []
|
|
||||||
|
|
||||||
def ajouter_pokemon(self, pokemon):
|
|
||||||
"""
|
|
||||||
Ajoute un Pokémon à l'équipe si possible (max 6).
|
|
||||||
|
|
||||||
:param pokemon: (Pokemon) Pokémon à ajouter
|
|
||||||
:return: (bool) True si ajouté, False sinon
|
|
||||||
"""
|
|
||||||
if len(self.equipe) < 6:
|
|
||||||
self.equipe.append(pokemon)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print("L'équipe est complète (6 Pokémon maximum) !")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def pokemon_disponibles(self):
|
|
||||||
"""
|
|
||||||
Renvoie la liste des Pokémon non KO.
|
|
||||||
|
|
||||||
:return: (list) Liste des Pokémon encore en état de combattre
|
|
||||||
"""
|
|
||||||
disponibles = []
|
|
||||||
for pokemon in self.equipe:
|
|
||||||
if not pokemon.est_ko():
|
|
||||||
disponibles.append(pokemon)
|
|
||||||
return disponibles
|
|
||||||
|
|
||||||
def premier_pokemon_dispo(self):
|
|
||||||
"""
|
|
||||||
Renvoie le premier Pokémon non KO.
|
|
||||||
|
|
||||||
:return: (Pokemon/None) Premier Pokémon dispo ou None
|
|
||||||
"""
|
|
||||||
for pokemon in self.equipe:
|
|
||||||
if not pokemon.est_ko():
|
|
||||||
return pokemon
|
|
||||||
return None
|
|
||||||
|
|
||||||
def tous_ko(self):
|
|
||||||
"""
|
|
||||||
Vérifie si tous les Pokémon sont KO.
|
|
||||||
|
|
||||||
:return: (bool) True si tous KO, False sinon
|
|
||||||
"""
|
|
||||||
for pokemon in self.equipe:
|
|
||||||
if not pokemon.est_ko():
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Représentation du dresseur."""
|
|
||||||
result = f"Dresseur {self.nom} - {len(self.equipe)} Pokémon"
|
|
||||||
for pokemon in self.equipe:
|
|
||||||
result += f"\n - {pokemon}"
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# PARTIE 3 : Classe Combat
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
class Combat:
|
|
||||||
def __init__(self, dresseur1, dresseur2):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Combat.
|
|
||||||
|
|
||||||
:param dresseur1: (Dresseur) Premier dresseur
|
|
||||||
:param dresseur2: (Dresseur) Second dresseur
|
|
||||||
"""
|
|
||||||
self.dresseur1 = dresseur1
|
|
||||||
self.dresseur2 = dresseur2
|
|
||||||
self.tour = 0
|
|
||||||
|
|
||||||
def afficher_etat(self):
|
|
||||||
"""Affiche l'état actuel du combat."""
|
|
||||||
print(f"\n{'='*40}")
|
|
||||||
print(f"Tour {self.tour}")
|
|
||||||
print(f"{'='*40}")
|
|
||||||
|
|
||||||
poke1 = self.dresseur1.premier_pokemon_dispo()
|
|
||||||
poke2 = self.dresseur2.premier_pokemon_dispo()
|
|
||||||
|
|
||||||
if poke1:
|
|
||||||
print(f"{self.dresseur1.nom}: {poke1.nom} ({poke1.pv}/{poke1.pv_max} PV)")
|
|
||||||
if poke2:
|
|
||||||
print(f"{self.dresseur2.nom}: {poke2.nom} ({poke2.pv}/{poke2.pv_max} PV)")
|
|
||||||
print()
|
|
||||||
|
|
||||||
def lancer_combat(self):
|
|
||||||
"""
|
|
||||||
Lance le combat tour par tour.
|
|
||||||
Chaque tour, les deux Pokémon actifs s'attaquent.
|
|
||||||
Quand un Pokémon est KO, le suivant prend sa place.
|
|
||||||
Le combat s'arrête quand un dresseur n'a plus de Pokémon.
|
|
||||||
"""
|
|
||||||
print(f"\n*** COMBAT : {self.dresseur1.nom} VS {self.dresseur2.nom} ***")
|
|
||||||
|
|
||||||
while not self.dresseur1.tous_ko() and not self.dresseur2.tous_ko():
|
|
||||||
self.tour += 1
|
|
||||||
self.afficher_etat()
|
|
||||||
|
|
||||||
# Récupérer les Pokémon actifs
|
|
||||||
poke1 = self.dresseur1.premier_pokemon_dispo()
|
|
||||||
poke2 = self.dresseur2.premier_pokemon_dispo()
|
|
||||||
|
|
||||||
# Le Pokémon 1 attaque
|
|
||||||
poke1.attaquer(poke2)
|
|
||||||
|
|
||||||
# Vérifier si Pokémon 2 est KO
|
|
||||||
if poke2.est_ko():
|
|
||||||
print(f"\n{poke2.nom} est KO !")
|
|
||||||
nouveau = self.dresseur2.premier_pokemon_dispo()
|
|
||||||
if nouveau:
|
|
||||||
print(f"{self.dresseur2.nom} envoie {nouveau.nom} !")
|
|
||||||
continue # Passer au tour suivant
|
|
||||||
|
|
||||||
# Le Pokémon 2 attaque
|
|
||||||
poke2.attaquer(poke1)
|
|
||||||
|
|
||||||
# Vérifier si Pokémon 1 est KO
|
|
||||||
if poke1.est_ko():
|
|
||||||
print(f"\n{poke1.nom} est KO !")
|
|
||||||
nouveau = self.dresseur1.premier_pokemon_dispo()
|
|
||||||
if nouveau:
|
|
||||||
print(f"{self.dresseur1.nom} envoie {nouveau.nom} !")
|
|
||||||
|
|
||||||
# Afficher le vainqueur
|
|
||||||
print(f"\n{'='*40}")
|
|
||||||
if self.dresseur1.tous_ko():
|
|
||||||
print(f"Tous les Pokémon de {self.dresseur1.nom} sont KO !")
|
|
||||||
print(f"*** {self.dresseur2.nom.upper()} REMPORTE LE COMBAT ! ***")
|
|
||||||
else:
|
|
||||||
print(f"Tous les Pokémon de {self.dresseur2.nom} sont KO !")
|
|
||||||
print(f"*** {self.dresseur1.nom.upper()} REMPORTE LE COMBAT ! ***")
|
|
||||||
print(f"{'='*40}")
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# PARTIE 4 : Centre Pokémon
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
class CentrePokemon:
|
|
||||||
def __init__(self, ville):
|
|
||||||
"""
|
|
||||||
:param ville: (str) Ville où se trouve le centre
|
|
||||||
"""
|
|
||||||
self.ville = ville
|
|
||||||
|
|
||||||
def soigner_equipe(self, dresseur):
|
|
||||||
"""
|
|
||||||
Soigne tous les Pokémon d'un dresseur à 100% de leurs PV.
|
|
||||||
|
|
||||||
:param dresseur: (Dresseur) Dresseur dont l'équipe doit être soignée
|
|
||||||
"""
|
|
||||||
print(f"\n*** Centre Pokémon de {self.ville} ***")
|
|
||||||
print(f"Bienvenue {dresseur.nom} !")
|
|
||||||
print("Nous allons soigner vos Pokémon...")
|
|
||||||
|
|
||||||
for pokemon in dresseur.equipe:
|
|
||||||
pokemon.pv = pokemon.pv_max
|
|
||||||
|
|
||||||
print("Vos Pokémon sont en pleine forme !")
|
|
||||||
print("À bientôt !\n")
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# BONUS : Classe Capacite
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
class Capacite:
|
|
||||||
def __init__(self, nom, puissance, type_capacite, pp_max):
|
|
||||||
"""
|
|
||||||
:param nom: (str) Nom de la capacité
|
|
||||||
:param puissance: (int) Puissance de base
|
|
||||||
:param type_capacite: (str) Type de la capacité
|
|
||||||
:param pp_max: (int) Nombre d'utilisations max
|
|
||||||
"""
|
|
||||||
self.nom = nom
|
|
||||||
self.puissance = puissance
|
|
||||||
self.type_capacite = type_capacite
|
|
||||||
self.pp_max = pp_max
|
|
||||||
self.pp = pp_max
|
|
||||||
|
|
||||||
def utiliser(self):
|
|
||||||
"""Utilise la capacité si PP disponibles."""
|
|
||||||
if self.pp > 0:
|
|
||||||
self.pp -= 1
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
print(f"{self.nom} : plus de PP !")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"{self.nom} ({self.type_capacite}) - {self.puissance} DMG - {self.pp}/{self.pp_max} PP"
|
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
|
||||||
# TESTS
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
print("=" * 50)
|
|
||||||
print("TEST DES CLASSES POKEMON")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
# Création des Pokémon
|
|
||||||
pikachu = Pokemon("Pikachu", "Electrik", 25, 80, 15)
|
|
||||||
dracaufeu = Pokemon("Dracaufeu", "Feu", 50, 150, 25)
|
|
||||||
tortank = Pokemon("Tortank", "Eau", 45, 140, 22)
|
|
||||||
onix = Pokemon("Onix", "Roche", 30, 120, 18)
|
|
||||||
racaillou = Pokemon("Racaillou", "Roche", 20, 80, 12)
|
|
||||||
|
|
||||||
print("\nPokémon créés :")
|
|
||||||
print(f" - {pikachu}")
|
|
||||||
print(f" - {dracaufeu}")
|
|
||||||
print(f" - {tortank}")
|
|
||||||
print(f" - {onix}")
|
|
||||||
print(f" - {racaillou}")
|
|
||||||
|
|
||||||
# Test des attaques avec faiblesses
|
|
||||||
print("\n--- Test attaque avec faiblesse ---")
|
|
||||||
print(f"Avant : {onix}")
|
|
||||||
tortank.attaquer(onix) # Eau bat Roche -> x2
|
|
||||||
print(f"Après : {onix}")
|
|
||||||
|
|
||||||
# Création des dresseurs
|
|
||||||
print("\n" + "=" * 50)
|
|
||||||
print("CREATION DES DRESSEURS")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
sacha = Dresseur("Sacha")
|
|
||||||
sacha.ajouter_pokemon(Pokemon("Pikachu", "Electrik", 25, 80, 15))
|
|
||||||
sacha.ajouter_pokemon(Pokemon("Dracaufeu", "Feu", 50, 150, 25))
|
|
||||||
sacha.ajouter_pokemon(Pokemon("Tortank", "Eau", 45, 140, 22))
|
|
||||||
|
|
||||||
pierre = Dresseur("Pierre")
|
|
||||||
pierre.ajouter_pokemon(Pokemon("Onix", "Roche", 30, 120, 18))
|
|
||||||
pierre.ajouter_pokemon(Pokemon("Racaillou", "Roche", 20, 80, 12))
|
|
||||||
|
|
||||||
print(f"\n{sacha}")
|
|
||||||
print(f"\n{pierre}")
|
|
||||||
|
|
||||||
# Lancement du combat
|
|
||||||
print("\n" + "=" * 50)
|
|
||||||
print("LANCEMENT DU COMBAT")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
combat = Combat(sacha, pierre)
|
|
||||||
combat.lancer_combat()
|
|
||||||
|
|
||||||
# Soins au Centre Pokémon
|
|
||||||
print("\n" + "=" * 50)
|
|
||||||
print("SOINS AU CENTRE POKEMON")
|
|
||||||
print("=" * 50)
|
|
||||||
|
|
||||||
centre = CentrePokemon("Argenta")
|
|
||||||
centre.soigner_equipe(sacha)
|
|
||||||
print(sacha)
|
|
||||||
@@ -1,543 +0,0 @@
|
|||||||
# TP : Pokémon Arena - Programmation Orientée Objet
|
|
||||||
|
|
||||||
> **Thème** : Classes, attributs, méthodes, interactions entre objets
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contexte
|
|
||||||
|
|
||||||
Depuis 1996, Pokémon est l'une des franchises les plus populaires au monde. En 2026, avec la sortie de Pokémon Legends: Z-A, la licence bat tous les records.
|
|
||||||
|
|
||||||
Dans ce TP, vous allez créer un **simulateur de combat Pokémon** en utilisant la Programmation Orientée Objet. Vous modéliserez des Pokémon, des dresseurs et des combats.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Partie 1 : La classe Pokémon
|
|
||||||
|
|
||||||
### Exercice 1 : Créer la classe de base
|
|
||||||
|
|
||||||
Créez une classe `Pokemon` avec les caractéristiques suivantes :
|
|
||||||
|
|
||||||
**Attributs :**
|
|
||||||
- `nom` : nom du Pokémon (str)
|
|
||||||
- `type_pokemon` : type élémentaire (str) - "Feu", "Eau", "Plante", "Electrik", etc.
|
|
||||||
- `niveau` : niveau du Pokémon (int, par défaut 1)
|
|
||||||
- `pv_max` : points de vie maximum (int, par défaut 100)
|
|
||||||
- `pv` : points de vie actuels (int, initialisé à `pv_max`)
|
|
||||||
- `attaque` : puissance d'attaque (int, par défaut 10)
|
|
||||||
|
|
||||||
**Méthodes :**
|
|
||||||
- `__init__` : constructeur
|
|
||||||
- `__repr__` : affiche le Pokémon sous la forme `"Pikachu (Electrik) - Nv.25 - 80/100 PV"`
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Pokemon:
|
|
||||||
def __init__(self, nom, type_pokemon, niveau=1, pv_max=100, attaque=10):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Pokemon.
|
|
||||||
|
|
||||||
:param nom: (str) Nom du Pokémon
|
|
||||||
:param type_pokemon: (str) Type élémentaire
|
|
||||||
:param niveau: (int) Niveau du Pokémon
|
|
||||||
:param pv_max: (int) Points de vie maximum
|
|
||||||
:param attaque: (int) Puissance d'attaque
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Représentation textuelle du Pokémon."""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tests :**
|
|
||||||
```python
|
|
||||||
>>> pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
|
||||||
>>> print(pikachu)
|
|
||||||
Pikachu (Electrik) - Nv.25 - 80/80 PV
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 2 : Méthodes de combat
|
|
||||||
|
|
||||||
Ajoutez les méthodes suivantes à la classe `Pokemon` :
|
|
||||||
|
|
||||||
```python
|
|
||||||
def est_ko(self):
|
|
||||||
"""
|
|
||||||
Vérifie si le Pokémon est KO.
|
|
||||||
|
|
||||||
:return: (bool) True si PV <= 0, False sinon
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def subir_degats(self, degats):
|
|
||||||
"""
|
|
||||||
Inflige des dégâts au Pokémon.
|
|
||||||
Les PV ne peuvent pas descendre en dessous de 0.
|
|
||||||
|
|
||||||
:param degats: (int) Nombre de dégâts subis
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque un autre Pokémon.
|
|
||||||
Affiche un message et inflige des dégâts à la cible.
|
|
||||||
|
|
||||||
:param cible: (Pokemon) Pokémon ciblé par l'attaque
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def soigner(self, soin):
|
|
||||||
"""
|
|
||||||
Soigne le Pokémon.
|
|
||||||
Les PV ne peuvent pas dépasser pv_max.
|
|
||||||
|
|
||||||
:param soin: (int) Nombre de PV récupérés
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tests :**
|
|
||||||
```python
|
|
||||||
>>> pikachu = Pokemon("Pikachu", "Electrik", niveau=25, pv_max=80, attaque=15)
|
|
||||||
>>> salameche = Pokemon("Salamèche", "Feu", niveau=20, pv_max=70, attaque=12)
|
|
||||||
>>> pikachu.attaquer(salameche)
|
|
||||||
Pikachu attaque Salamèche et inflige 15 dégâts !
|
|
||||||
>>> print(salameche)
|
|
||||||
Salamèche (Feu) - Nv.20 - 55/70 PV
|
|
||||||
>>> salameche.est_ko()
|
|
||||||
False
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 3 : Système de faiblesses (Bonus)
|
|
||||||
|
|
||||||
En Pokémon, certains types sont plus efficaces contre d'autres :
|
|
||||||
- **Eau** bat **Feu** (×2 dégâts)
|
|
||||||
- **Feu** bat **Plante** (×2 dégâts)
|
|
||||||
- **Plante** bat **Eau** (×2 dégâts)
|
|
||||||
- **Electrik** bat **Eau** (×2 dégâts)
|
|
||||||
|
|
||||||
Modifiez la méthode `attaquer` pour prendre en compte les faiblesses :
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Dictionnaire des faiblesses : type_attaquant -> liste des types faibles
|
|
||||||
FAIBLESSES = {
|
|
||||||
"Eau": ["Feu"],
|
|
||||||
"Feu": ["Plante"],
|
|
||||||
"Plante": ["Eau"],
|
|
||||||
"Electrik": ["Eau"]
|
|
||||||
}
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque un autre Pokémon avec prise en compte des faiblesses.
|
|
||||||
"""
|
|
||||||
degats = self.attaque
|
|
||||||
|
|
||||||
# Vérifier si le type de la cible est faible contre notre type
|
|
||||||
if self.type_pokemon in FAIBLESSES:
|
|
||||||
if cible.type_pokemon in FAIBLESSES[self.type_pokemon]:
|
|
||||||
degats *= 2
|
|
||||||
print(f"C'est super efficace !")
|
|
||||||
|
|
||||||
print(f"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !")
|
|
||||||
cible.subir_degats(degats)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Partie 2 : La classe Dresseur
|
|
||||||
|
|
||||||
### Exercice 4 : Créer la classe Dresseur
|
|
||||||
|
|
||||||
Un dresseur possède une équipe de Pokémon (maximum 6).
|
|
||||||
|
|
||||||
**Attributs :**
|
|
||||||
- `nom` : nom du dresseur (str)
|
|
||||||
- `equipe` : liste de Pokémon (list, vide par défaut)
|
|
||||||
|
|
||||||
**Méthodes :**
|
|
||||||
- `__init__` : constructeur
|
|
||||||
- `ajouter_pokemon(pokemon)` : ajoute un Pokémon à l'équipe (max 6)
|
|
||||||
- `pokemon_disponibles()` : renvoie la liste des Pokémon non KO
|
|
||||||
- `premier_pokemon_dispo()` : renvoie le premier Pokémon non KO ou None
|
|
||||||
- `tous_ko()` : renvoie True si tous les Pokémon sont KO
|
|
||||||
- `__repr__` : affiche le dresseur et son équipe
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Dresseur:
|
|
||||||
def __init__(self, nom):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Dresseur.
|
|
||||||
|
|
||||||
:param nom: (str) Nom du dresseur
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def ajouter_pokemon(self, pokemon):
|
|
||||||
"""
|
|
||||||
Ajoute un Pokémon à l'équipe si possible (max 6).
|
|
||||||
|
|
||||||
:param pokemon: (Pokemon) Pokémon à ajouter
|
|
||||||
:return: (bool) True si ajouté, False sinon
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def pokemon_disponibles(self):
|
|
||||||
"""
|
|
||||||
Renvoie la liste des Pokémon non KO.
|
|
||||||
|
|
||||||
:return: (list) Liste des Pokémon encore en état de combattre
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def premier_pokemon_dispo(self):
|
|
||||||
"""
|
|
||||||
Renvoie le premier Pokémon non KO.
|
|
||||||
|
|
||||||
:return: (Pokemon/None) Premier Pokémon dispo ou None
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def tous_ko(self):
|
|
||||||
"""
|
|
||||||
Vérifie si tous les Pokémon sont KO.
|
|
||||||
|
|
||||||
:return: (bool) True si tous KO, False sinon
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
"""Représentation du dresseur."""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tests :**
|
|
||||||
```python
|
|
||||||
>>> sacha = Dresseur("Sacha")
|
|
||||||
>>> sacha.ajouter_pokemon(Pokemon("Pikachu", "Electrik", 25, 80, 15))
|
|
||||||
True
|
|
||||||
>>> sacha.ajouter_pokemon(Pokemon("Dracaufeu", "Feu", 50, 150, 25))
|
|
||||||
True
|
|
||||||
>>> print(sacha)
|
|
||||||
Dresseur Sacha - 2 Pokémon
|
|
||||||
- Pikachu (Electrik) - Nv.25 - 80/80 PV
|
|
||||||
- Dracaufeu (Feu) - Nv.50 - 150/150 PV
|
|
||||||
>>> sacha.tous_ko()
|
|
||||||
False
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Partie 3 : La classe Combat
|
|
||||||
|
|
||||||
### Exercice 5 : Simulateur de combat
|
|
||||||
|
|
||||||
Créez une classe `Combat` qui simule un affrontement entre deux dresseurs.
|
|
||||||
|
|
||||||
**Attributs :**
|
|
||||||
- `dresseur1` : premier dresseur (Dresseur)
|
|
||||||
- `dresseur2` : second dresseur (Dresseur)
|
|
||||||
- `tour` : numéro du tour actuel (int)
|
|
||||||
|
|
||||||
**Méthodes :**
|
|
||||||
- `__init__` : constructeur
|
|
||||||
- `lancer_combat()` : lance le combat jusqu'à ce qu'un dresseur n'ait plus de Pokémon
|
|
||||||
- `afficher_etat()` : affiche l'état actuel du combat
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Combat:
|
|
||||||
def __init__(self, dresseur1, dresseur2):
|
|
||||||
"""
|
|
||||||
Constructeur de la classe Combat.
|
|
||||||
|
|
||||||
:param dresseur1: (Dresseur) Premier dresseur
|
|
||||||
:param dresseur2: (Dresseur) Second dresseur
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def afficher_etat(self):
|
|
||||||
"""Affiche l'état actuel du combat."""
|
|
||||||
print(f"\n{'='*40}")
|
|
||||||
print(f"Tour {self.tour}")
|
|
||||||
print(f"{'='*40}")
|
|
||||||
# Afficher les Pokémon actifs
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
def lancer_combat(self):
|
|
||||||
"""
|
|
||||||
Lance le combat tour par tour.
|
|
||||||
Chaque tour, les deux Pokémon actifs s'attaquent.
|
|
||||||
Quand un Pokémon est KO, le suivant prend sa place.
|
|
||||||
Le combat s'arrête quand un dresseur n'a plus de Pokémon.
|
|
||||||
"""
|
|
||||||
print(f"\n*** COMBAT : {self.dresseur1.nom} VS {self.dresseur2.nom} ***\n")
|
|
||||||
|
|
||||||
while not self.dresseur1.tous_ko() and not self.dresseur2.tous_ko():
|
|
||||||
self.tour += 1
|
|
||||||
self.afficher_etat()
|
|
||||||
|
|
||||||
# Récupérer les Pokémon actifs
|
|
||||||
poke1 = self.dresseur1.premier_pokemon_dispo()
|
|
||||||
poke2 = self.dresseur2.premier_pokemon_dispo()
|
|
||||||
|
|
||||||
# Le Pokémon 1 attaque
|
|
||||||
# À compléter
|
|
||||||
|
|
||||||
# Vérifier si Pokémon 2 est KO
|
|
||||||
# À compléter
|
|
||||||
|
|
||||||
# Le Pokémon 2 attaque (s'il n'est pas KO)
|
|
||||||
# À compléter
|
|
||||||
|
|
||||||
# Vérifier si Pokémon 1 est KO
|
|
||||||
# À compléter
|
|
||||||
|
|
||||||
# Afficher le vainqueur
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
**Exemple d'exécution :**
|
|
||||||
```
|
|
||||||
*** COMBAT : Sacha VS Pierre ***
|
|
||||||
|
|
||||||
========================================
|
|
||||||
Tour 1
|
|
||||||
========================================
|
|
||||||
Sacha: Pikachu (80/80 PV)
|
|
||||||
Pierre: Onix (120/120 PV)
|
|
||||||
|
|
||||||
Pikachu attaque Onix et inflige 15 dégâts !
|
|
||||||
Onix attaque Pikachu et inflige 20 dégâts !
|
|
||||||
|
|
||||||
========================================
|
|
||||||
Tour 2
|
|
||||||
========================================
|
|
||||||
Sacha: Pikachu (60/80 PV)
|
|
||||||
Pierre: Onix (105/120 PV)
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Pikachu est KO !
|
|
||||||
Sacha envoie Dracaufeu !
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
Tous les Pokémon de Pierre sont KO !
|
|
||||||
*** SACHA REMPORTE LE COMBAT ! ***
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Partie 4 : Améliorations
|
|
||||||
|
|
||||||
### Exercice 6 : Centre Pokémon
|
|
||||||
|
|
||||||
Créez une classe `CentrePokemon` qui permet de soigner une équipe :
|
|
||||||
|
|
||||||
```python
|
|
||||||
class CentrePokemon:
|
|
||||||
def __init__(self, ville):
|
|
||||||
"""
|
|
||||||
:param ville: (str) Ville où se trouve le centre
|
|
||||||
"""
|
|
||||||
self.ville = ville
|
|
||||||
|
|
||||||
def soigner_equipe(self, dresseur):
|
|
||||||
"""
|
|
||||||
Soigne tous les Pokémon d'un dresseur à 100% de leurs PV.
|
|
||||||
|
|
||||||
:param dresseur: (Dresseur) Dresseur dont l'équipe doit être soignée
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 7 : Capacités spéciales (Pour aller plus loin)
|
|
||||||
|
|
||||||
Créez une classe `Capacite` pour donner des attaques spéciales aux Pokémon :
|
|
||||||
|
|
||||||
```python
|
|
||||||
class Capacite:
|
|
||||||
def __init__(self, nom, puissance, type_capacite, pp_max):
|
|
||||||
"""
|
|
||||||
:param nom: (str) Nom de la capacité
|
|
||||||
:param puissance: (int) Puissance de base
|
|
||||||
:param type_capacite: (str) Type de la capacité
|
|
||||||
:param pp_max: (int) Nombre d'utilisations max
|
|
||||||
"""
|
|
||||||
self.nom = nom
|
|
||||||
self.puissance = puissance
|
|
||||||
self.type_capacite = type_capacite
|
|
||||||
self.pp_max = pp_max
|
|
||||||
self.pp = pp_max
|
|
||||||
```
|
|
||||||
|
|
||||||
Modifiez la classe `Pokemon` pour qu'un Pokémon possède une liste de capacités (max 4) et puisse choisir son attaque.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Partie 5 : Héritage - Spécialiser les Pokémon
|
|
||||||
|
|
||||||
> ⚠️ Cette section est hors programme NSI.
|
|
||||||
>
|
|
||||||
> **Prérequis** : avoir vu la section "Pour aller plus loin" du cours POO.
|
|
||||||
|
|
||||||
Jusqu'ici, tous les Pokémon utilisent la même méthode `attaquer`. Mais en vrai, un Pokémon Feu n'attaque pas comme un Pokémon Eau. Plutôt que de gérer ça avec un dictionnaire de faiblesses dans `attaquer`, on peut utiliser l'**héritage** pour créer des sous-classes spécialisées.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 8 : Sous-classes par type
|
|
||||||
|
|
||||||
Créez trois sous-classes qui héritent de `Pokemon` :
|
|
||||||
|
|
||||||
- `PokemonFeu` : inflige ×2 dégâts aux Pokémon Plante
|
|
||||||
- `PokemonEau` : inflige ×2 dégâts aux Pokémon Feu
|
|
||||||
- `PokemonPlante` : inflige ×2 dégâts aux Pokémon Eau
|
|
||||||
|
|
||||||
Chaque sous-classe doit :
|
|
||||||
1. Hériter de `Pokemon` via `class PokemonFeu(Pokemon):`
|
|
||||||
2. Appeler `super().__init__(...)` dans son constructeur en fixant `type_pokemon` automatiquement
|
|
||||||
3. Surcharger la méthode `attaquer` pour appliquer le bonus de dégâts
|
|
||||||
|
|
||||||
```python
|
|
||||||
class PokemonFeu(Pokemon):
|
|
||||||
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
|
|
||||||
super().__init__(nom, "Feu", niveau, pv_max, attaque)
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque avec ×2 dégâts si la cible est de type Plante.
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PokemonEau(Pokemon):
|
|
||||||
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
|
|
||||||
super().__init__(nom, "Eau", niveau, pv_max, attaque)
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque avec ×2 dégâts si la cible est de type Feu.
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PokemonPlante(Pokemon):
|
|
||||||
def __init__(self, nom, niveau=1, pv_max=100, attaque=10):
|
|
||||||
super().__init__(nom, "Plante", niveau, pv_max, attaque)
|
|
||||||
|
|
||||||
def attaquer(self, cible):
|
|
||||||
"""
|
|
||||||
Attaque avec ×2 dégâts si la cible est de type Eau.
|
|
||||||
"""
|
|
||||||
# À compléter
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
**Tests :**
|
|
||||||
```python
|
|
||||||
>>> salameche = PokemonFeu("Salamèche", niveau=15, pv_max=70, attaque=12)
|
|
||||||
>>> bulbizarre = PokemonPlante("Bulbizarre", niveau=15, pv_max=75, attaque=10)
|
|
||||||
>>> salameche.attaquer(bulbizarre)
|
|
||||||
C'est super efficace !
|
|
||||||
Salamèche attaque Bulbizarre et inflige 24 dégâts !
|
|
||||||
>>> bulbizarre.attaquer(salameche)
|
|
||||||
Bulbizarre attaque Salamèche et inflige 10 dégâts !
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 9 : isinstance() en pratique
|
|
||||||
|
|
||||||
1. Vérifiez que `salameche` est à la fois une instance de `PokemonFeu` **et** de `Pokemon`. Expliquez pourquoi.
|
|
||||||
2. Écrivez une fonction `compter_par_type(equipe)` qui prend une liste de Pokémon et renvoie un dictionnaire `{type: nombre}`.
|
|
||||||
|
|
||||||
```python
|
|
||||||
>>> equipe = [PokemonFeu("Dracaufeu"), PokemonEau("Tortank"), PokemonFeu("Sulfura"), PokemonPlante("Florizarre")]
|
|
||||||
>>> compter_par_type(equipe)
|
|
||||||
{'Feu': 2, 'Eau': 1, 'Plante': 1}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Exercice 10 : Refactoring
|
|
||||||
|
|
||||||
Relisez le dictionnaire `FAIBLESSES` de l'exercice 3. Maintenant que vous avez des sous-classes, ce dictionnaire est-il encore utile ? Quelle approche est plus lisible selon vous ? Discutez.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Résumé des classes
|
|
||||||
|
|
||||||
| Classe | Hérite de | Attributs supplémentaires | Méthodes modifiées |
|
|
||||||
|--------|-----------|---------------------------|--------------------|
|
|
||||||
| `Pokemon` | - | nom, type, niveau, pv, attaque | attaquer(), subir_degats(), est_ko() |
|
|
||||||
| `PokemonFeu` | `Pokemon` | - | attaquer() |
|
|
||||||
| `PokemonEau` | `Pokemon` | - | attaquer() |
|
|
||||||
| `PokemonPlante` | `Pokemon` | - | attaquer() |
|
|
||||||
| `Dresseur` | - | nom, equipe | ajouter_pokemon(), tous_ko() |
|
|
||||||
| `Combat` | - | dresseur1, dresseur2, tour | lancer_combat() |
|
|
||||||
| `CentrePokemon` | - | ville | soigner_equipe() |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Code de test final
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Création des Pokémon
|
|
||||||
pikachu = Pokemon("Pikachu", "Electrik", 25, 80, 15)
|
|
||||||
dracaufeu = Pokemon("Dracaufeu", "Feu", 50, 150, 25)
|
|
||||||
tortank = Pokemon("Tortank", "Eau", 45, 140, 22)
|
|
||||||
onix = Pokemon("Onix", "Roche", 30, 120, 18)
|
|
||||||
racaillou = Pokemon("Racaillou", "Roche", 20, 80, 12)
|
|
||||||
|
|
||||||
# Création des dresseurs
|
|
||||||
sacha = Dresseur("Sacha")
|
|
||||||
sacha.ajouter_pokemon(pikachu)
|
|
||||||
sacha.ajouter_pokemon(dracaufeu)
|
|
||||||
sacha.ajouter_pokemon(tortank)
|
|
||||||
|
|
||||||
pierre = Dresseur("Pierre")
|
|
||||||
pierre.ajouter_pokemon(onix)
|
|
||||||
pierre.ajouter_pokemon(racaillou)
|
|
||||||
|
|
||||||
# Lancement du combat
|
|
||||||
combat = Combat(sacha, pierre)
|
|
||||||
combat.lancer_combat()
|
|
||||||
|
|
||||||
# Soins au Centre Pokémon
|
|
||||||
centre = CentrePokemon("Argenta")
|
|
||||||
centre.soigner_equipe(sacha)
|
|
||||||
print(sacha)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Auteurs : Florian Mathieu, Enzo Frémeaux, Timothée Decoster
|
|
||||||
|
|
||||||
Licence CC BY-SA
|
|
||||||
|
|
||||||
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.
|
|
||||||
@@ -0,0 +1,791 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "8cc139ef",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"# TP : Pokémon Arena - Programmation Orientée Objet\n",
|
||||||
|
"\n",
|
||||||
|
"> **Thème** : Classes, attributs, méthodes, interactions entre objets\n",
|
||||||
|
"\n",
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Contexte\n",
|
||||||
|
"\n",
|
||||||
|
"Depuis 1996, Pokémon est l'une des franchises les plus populaires au monde. En 2026, avec la sortie de Pokémon Legends: Z-A, la licence bat tous les records.\n",
|
||||||
|
"\n",
|
||||||
|
"Dans ce TP, vous allez créer un **simulateur de combat Pokémon** en utilisant la Programmation Orientée Objet. Vous modéliserez des Pokémon, des dresseurs et des combats.\n",
|
||||||
|
"\n",
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Mode d'emploi du notebook\n",
|
||||||
|
"\n",
|
||||||
|
"- Complétez les cellules marquées `# À compléter`, puis exécutez-les (`Maj + Entrée`).\n",
|
||||||
|
"- Après chaque exercice, une cellule **Vérification** teste votre code. Si un test échoue, lisez la dernière ligne du message d'erreur : pour une `AssertionError`, elle indique ce qui ne va pas ; une `AttributeError` signale en général un attribut ou une méthode pas encore écrits.\n",
|
||||||
|
"- Quand vous modifiez une classe, **réexécutez sa cellule** avant de relancer les vérifications. En cas de doute : menu *Noyau* puis *Redémarrer et tout exécuter*."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "145f2f74",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Partie 1 : La classe Pokémon\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 1 : Créer la classe de base\n",
|
||||||
|
"\n",
|
||||||
|
"Complétez le constructeur et la méthode `__repr__` de la classe `Pokemon`.\n",
|
||||||
|
"\n",
|
||||||
|
"**Attributs :**\n",
|
||||||
|
"- `nom` : nom du Pokémon (str)\n",
|
||||||
|
"- `type_pokemon` : type élémentaire (str) : \"Feu\", \"Eau\", \"Plante\", \"Electrik\", etc.\n",
|
||||||
|
"- `niveau` : niveau du Pokémon (int, par défaut 1)\n",
|
||||||
|
"- `pv_max` : points de vie maximum (int, par défaut 100)\n",
|
||||||
|
"- `pv` : points de vie actuels (int, initialisé à `pv_max`)\n",
|
||||||
|
"- `attaque` : puissance d'attaque (int, par défaut 10)\n",
|
||||||
|
"\n",
|
||||||
|
"**Méthodes :**\n",
|
||||||
|
"- `__init__` : constructeur\n",
|
||||||
|
"- `__repr__` : renvoie le Pokémon sous la forme `\"Pikachu (Electrik) - Nv.25 - 80/100 PV\"`\n",
|
||||||
|
"\n",
|
||||||
|
"Les méthodes de l'exercice 2 sont déjà présentes dans la classe : vous les compléterez ensuite, dans **la même cellule**."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "649474f4",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class Pokemon:\n",
|
||||||
|
" def __init__(self, nom, type_pokemon, niveau=1, pv_max=100, attaque=10):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Constructeur de la classe Pokemon.\n",
|
||||||
|
"\n",
|
||||||
|
" :param nom: (str) Nom du Pokémon\n",
|
||||||
|
" :param type_pokemon: (str) Type élémentaire\n",
|
||||||
|
" :param niveau: (int) Niveau du Pokémon\n",
|
||||||
|
" :param pv_max: (int) Points de vie maximum\n",
|
||||||
|
" :param attaque: (int) Puissance d'attaque\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter (exercice 1)\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def __repr__(self):\n",
|
||||||
|
" \"\"\"Représentation textuelle du Pokémon.\"\"\"\n",
|
||||||
|
" # À compléter (exercice 1)\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def est_ko(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Vérifie si le Pokémon est KO.\n",
|
||||||
|
"\n",
|
||||||
|
" :return: (bool) True si PV <= 0, False sinon\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter (exercice 2)\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def subir_degats(self, degats):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Inflige des dégâts au Pokémon.\n",
|
||||||
|
" Les PV ne peuvent pas descendre en dessous de 0.\n",
|
||||||
|
"\n",
|
||||||
|
" :param degats: (int) Nombre de dégâts subis\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter (exercice 2)\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def attaquer(self, cible):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Attaque un autre Pokémon.\n",
|
||||||
|
" Affiche un message et inflige des dégâts à la cible.\n",
|
||||||
|
"\n",
|
||||||
|
" :param cible: (Pokemon) Pokémon ciblé par l'attaque\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter (exercice 2, puis exercice 3 en bonus)\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def soigner(self, soin):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Soigne le Pokémon.\n",
|
||||||
|
" Les PV ne peuvent pas dépasser pv_max.\n",
|
||||||
|
"\n",
|
||||||
|
" :param soin: (int) Nombre de PV récupérés\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter (exercice 2)\n",
|
||||||
|
" pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "99482193",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Vérification de l'exercice 1**\n",
|
||||||
|
"\n",
|
||||||
|
"Affichage attendu : `Pikachu (Electrik) - Nv.25 - 80/80 PV`"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "1e050c69",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"pikachu = Pokemon(\"Pikachu\", \"Electrik\", niveau=25, pv_max=80, attaque=15)\n",
|
||||||
|
"\n",
|
||||||
|
"assert pikachu.nom == \"Pikachu\", \"L'attribut nom est incorrect\"\n",
|
||||||
|
"assert pikachu.type_pokemon == \"Electrik\", \"L'attribut type_pokemon est incorrect\"\n",
|
||||||
|
"assert pikachu.niveau == 25, \"L'attribut niveau est incorrect\"\n",
|
||||||
|
"assert pikachu.pv_max == 80, \"L'attribut pv_max est incorrect\"\n",
|
||||||
|
"assert pikachu.pv == 80, \"Les PV doivent être initialisés à pv_max\"\n",
|
||||||
|
"assert pikachu.attaque == 15, \"L'attribut attaque est incorrect\"\n",
|
||||||
|
"assert repr(pikachu) == \"Pikachu (Electrik) - Nv.25 - 80/80 PV\", \"__repr__ ne renvoie pas le bon texte\"\n",
|
||||||
|
"\n",
|
||||||
|
"magicarpe = Pokemon(\"Magicarpe\", \"Eau\")\n",
|
||||||
|
"assert magicarpe.niveau == 1 and magicarpe.pv_max == 100 and magicarpe.pv == 100 and magicarpe.attaque == 10, \\\n",
|
||||||
|
" \"Les valeurs par défaut sont incorrectes\"\n",
|
||||||
|
"\n",
|
||||||
|
"print(pikachu)\n",
|
||||||
|
"print(\"Exercice 1 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "247ab7c0",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 2 : Méthodes de combat\n",
|
||||||
|
"\n",
|
||||||
|
"Revenez dans la cellule de la classe `Pokemon` et complétez les méthodes `est_ko`, `subir_degats`, `attaquer` et `soigner`, en suivant leur docstring. Réexécutez ensuite la cellule de la classe.\n",
|
||||||
|
"\n",
|
||||||
|
"La méthode `attaquer` inflige à la cible autant de dégâts que la valeur d'`attaque` du Pokémon, et affiche un message de la forme :\n",
|
||||||
|
"\n",
|
||||||
|
"```\n",
|
||||||
|
"Pikachu attaque Salamèche et inflige 15 dégâts !\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "06394e37",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Vérification de l'exercice 2**\n",
|
||||||
|
"\n",
|
||||||
|
"Affichage attendu :\n",
|
||||||
|
"\n",
|
||||||
|
"```\n",
|
||||||
|
"Pikachu attaque Salamèche et inflige 15 dégâts !\n",
|
||||||
|
"Salamèche (Feu) - Nv.20 - 55/70 PV\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "0799edc6",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"pikachu = Pokemon(\"Pikachu\", \"Electrik\", niveau=25, pv_max=80, attaque=15)\n",
|
||||||
|
"salameche = Pokemon(\"Salamèche\", \"Feu\", niveau=20, pv_max=70, attaque=12)\n",
|
||||||
|
"\n",
|
||||||
|
"pikachu.attaquer(salameche)\n",
|
||||||
|
"print(salameche)\n",
|
||||||
|
"\n",
|
||||||
|
"assert salameche.pv == 55, \"attaquer doit retirer attaque PV à la cible\"\n",
|
||||||
|
"assert pikachu.pv == 80, \"attaquer ne doit pas modifier les PV de l'attaquant\"\n",
|
||||||
|
"assert salameche.est_ko() is False, \"est_ko doit renvoyer False quand il reste des PV\"\n",
|
||||||
|
"\n",
|
||||||
|
"salameche.subir_degats(100)\n",
|
||||||
|
"assert salameche.pv == 0, \"Les PV ne doivent pas descendre en dessous de 0\"\n",
|
||||||
|
"assert salameche.est_ko() is True, \"est_ko doit renvoyer True quand les PV sont à 0\"\n",
|
||||||
|
"\n",
|
||||||
|
"salameche.soigner(30)\n",
|
||||||
|
"assert salameche.pv == 30, \"soigner doit ajouter les PV indiqués\"\n",
|
||||||
|
"salameche.soigner(100)\n",
|
||||||
|
"assert salameche.pv == 70, \"Les PV ne doivent pas dépasser pv_max\"\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"Exercice 2 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "907d0e25",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 3 : Système de faiblesses (Bonus)\n",
|
||||||
|
"\n",
|
||||||
|
"En Pokémon, certains types sont plus efficaces contre d'autres :\n",
|
||||||
|
"- **Eau** bat **Feu** (×2 dégâts)\n",
|
||||||
|
"- **Feu** bat **Plante** (×2 dégâts)\n",
|
||||||
|
"- **Plante** bat **Eau** (×2 dégâts)\n",
|
||||||
|
"- **Electrik** bat **Eau** (×2 dégâts)\n",
|
||||||
|
"\n",
|
||||||
|
"Exécutez la cellule ci-dessous, qui définit le dictionnaire des faiblesses."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "11d5c707",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# Dictionnaire des faiblesses : type_attaquant -> liste des types faibles\n",
|
||||||
|
"FAIBLESSES = {\n",
|
||||||
|
" \"Eau\": [\"Feu\"],\n",
|
||||||
|
" \"Feu\": [\"Plante\"],\n",
|
||||||
|
" \"Plante\": [\"Eau\"],\n",
|
||||||
|
" \"Electrik\": [\"Eau\"]\n",
|
||||||
|
"}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "f2e0fc37",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Modifiez ensuite la méthode `attaquer` de la classe `Pokemon` : si le type de la cible est faible contre celui de l'attaquant, les dégâts sont doublés et le message `C'est super efficace !` s'affiche avant le message d'attaque.\n",
|
||||||
|
"\n",
|
||||||
|
"```python\n",
|
||||||
|
"def attaquer(self, cible):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Attaque un autre Pokémon avec prise en compte des faiblesses.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" degats = self.attaque\n",
|
||||||
|
"\n",
|
||||||
|
" # Vérifier si le type de la cible est faible contre notre type\n",
|
||||||
|
" if self.type_pokemon in FAIBLESSES:\n",
|
||||||
|
" if cible.type_pokemon in FAIBLESSES[self.type_pokemon]:\n",
|
||||||
|
" degats *= 2\n",
|
||||||
|
" print(\"C'est super efficace !\")\n",
|
||||||
|
"\n",
|
||||||
|
" print(f\"{self.nom} attaque {cible.nom} et inflige {degats} dégâts !\")\n",
|
||||||
|
" cible.subir_degats(degats)\n",
|
||||||
|
"```\n",
|
||||||
|
"\n",
|
||||||
|
"Réexécutez la cellule de la classe `Pokemon`, puis la vérification ci-dessous.\n",
|
||||||
|
"\n",
|
||||||
|
"**Vérification de l'exercice 3**\n",
|
||||||
|
"\n",
|
||||||
|
"Affichage attendu :\n",
|
||||||
|
"\n",
|
||||||
|
"```\n",
|
||||||
|
"C'est super efficace !\n",
|
||||||
|
"Carapuce attaque Salamèche et inflige 20 dégâts !\n",
|
||||||
|
"Salamèche attaque Carapuce et inflige 12 dégâts !\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "dcc9de27",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"carapuce = Pokemon(\"Carapuce\", \"Eau\", niveau=15, pv_max=75, attaque=10)\n",
|
||||||
|
"salameche = Pokemon(\"Salamèche\", \"Feu\", niveau=15, pv_max=70, attaque=12)\n",
|
||||||
|
"\n",
|
||||||
|
"carapuce.attaquer(salameche)\n",
|
||||||
|
"assert salameche.pv == 50, \"Eau contre Feu : les dégâts doivent être doublés\"\n",
|
||||||
|
"\n",
|
||||||
|
"salameche.attaquer(carapuce)\n",
|
||||||
|
"assert carapuce.pv == 63, \"Feu contre Eau : les dégâts ne doivent pas être doublés\"\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"Exercice 3 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "babba110",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Partie 2 : La classe Dresseur\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 4 : Créer la classe Dresseur\n",
|
||||||
|
"\n",
|
||||||
|
"Un dresseur possède une équipe de Pokémon (maximum 6).\n",
|
||||||
|
"\n",
|
||||||
|
"**Attributs :**\n",
|
||||||
|
"- `nom` : nom du dresseur (str)\n",
|
||||||
|
"- `equipe` : liste de Pokémon (list, vide au départ)\n",
|
||||||
|
"\n",
|
||||||
|
"**Méthodes :**\n",
|
||||||
|
"- `__init__` : constructeur\n",
|
||||||
|
"- `ajouter_pokemon(pokemon)` : ajoute un Pokémon à l'équipe (max 6)\n",
|
||||||
|
"- `pokemon_disponibles()` : renvoie la liste des Pokémon non KO\n",
|
||||||
|
"- `premier_pokemon_dispo()` : renvoie le premier Pokémon non KO ou `None`\n",
|
||||||
|
"- `tous_ko()` : renvoie `True` si tous les Pokémon sont KO\n",
|
||||||
|
"- `__repr__` : renvoie le dresseur et son équipe, un Pokémon par ligne"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "7e51328d",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class Dresseur:\n",
|
||||||
|
" def __init__(self, nom):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Constructeur de la classe Dresseur.\n",
|
||||||
|
"\n",
|
||||||
|
" :param nom: (str) Nom du dresseur\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def ajouter_pokemon(self, pokemon):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Ajoute un Pokémon à l'équipe si possible (max 6).\n",
|
||||||
|
"\n",
|
||||||
|
" :param pokemon: (Pokemon) Pokémon à ajouter\n",
|
||||||
|
" :return: (bool) True si ajouté, False sinon\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def pokemon_disponibles(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Renvoie la liste des Pokémon non KO.\n",
|
||||||
|
"\n",
|
||||||
|
" :return: (list) Liste des Pokémon encore en état de combattre\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def premier_pokemon_dispo(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Renvoie le premier Pokémon non KO.\n",
|
||||||
|
"\n",
|
||||||
|
" :return: (Pokemon/None) Premier Pokémon dispo ou None\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def tous_ko(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Vérifie si tous les Pokémon sont KO.\n",
|
||||||
|
"\n",
|
||||||
|
" :return: (bool) True si tous KO, False sinon\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def __repr__(self):\n",
|
||||||
|
" \"\"\"Représentation du dresseur.\"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "5f99837d",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Vérification de l'exercice 4**\n",
|
||||||
|
"\n",
|
||||||
|
"Affichage attendu :\n",
|
||||||
|
"\n",
|
||||||
|
"```\n",
|
||||||
|
"Dresseur Sacha - 2 Pokémon\n",
|
||||||
|
" - Pikachu (Electrik) - Nv.25 - 80/80 PV\n",
|
||||||
|
" - Dracaufeu (Feu) - Nv.50 - 150/150 PV\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "e735fc8f",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"sacha = Dresseur(\"Sacha\")\n",
|
||||||
|
"assert sacha.nom == \"Sacha\" and sacha.equipe == [], \"Un dresseur commence avec une équipe vide\"\n",
|
||||||
|
"\n",
|
||||||
|
"assert sacha.ajouter_pokemon(Pokemon(\"Pikachu\", \"Electrik\", 25, 80, 15)) is True\n",
|
||||||
|
"assert sacha.ajouter_pokemon(Pokemon(\"Dracaufeu\", \"Feu\", 50, 150, 25)) is True\n",
|
||||||
|
"\n",
|
||||||
|
"assert repr(sacha) == \"Dresseur Sacha - 2 Pokémon\\n - Pikachu (Electrik) - Nv.25 - 80/80 PV\\n - Dracaufeu (Feu) - Nv.50 - 150/150 PV\", \\\n",
|
||||||
|
" \"__repr__ ne renvoie pas le bon texte\"\n",
|
||||||
|
"print(sacha)\n",
|
||||||
|
"assert sacha.tous_ko() is False\n",
|
||||||
|
"\n",
|
||||||
|
"sacha.equipe[0].subir_degats(100)\n",
|
||||||
|
"assert sacha.premier_pokemon_dispo().nom == \"Dracaufeu\", \"Pikachu est KO, le premier disponible est Dracaufeu\"\n",
|
||||||
|
"assert len(sacha.pokemon_disponibles()) == 1, \"Un seul Pokémon est encore disponible\"\n",
|
||||||
|
"\n",
|
||||||
|
"sacha.equipe[1].subir_degats(200)\n",
|
||||||
|
"assert sacha.tous_ko() is True, \"Tous les Pokémon sont KO\"\n",
|
||||||
|
"assert sacha.premier_pokemon_dispo() is None, \"Aucun Pokémon disponible : il faut renvoyer None\"\n",
|
||||||
|
"\n",
|
||||||
|
"for i in range(4):\n",
|
||||||
|
" sacha.ajouter_pokemon(Pokemon(f\"Pokémon {i}\", \"Normal\"))\n",
|
||||||
|
"assert sacha.ajouter_pokemon(Pokemon(\"Septième\", \"Normal\")) is False, \"Une équipe est limitée à 6 Pokémon\"\n",
|
||||||
|
"assert len(sacha.equipe) == 6\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"Exercice 4 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "fa138c5d",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Partie 3 : La classe Combat\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 5 : Simulateur de combat\n",
|
||||||
|
"\n",
|
||||||
|
"Créez une classe `Combat` qui simule un affrontement entre deux dresseurs.\n",
|
||||||
|
"\n",
|
||||||
|
"**Attributs :**\n",
|
||||||
|
"- `dresseur1` : premier dresseur (Dresseur)\n",
|
||||||
|
"- `dresseur2` : second dresseur (Dresseur)\n",
|
||||||
|
"- `tour` : numéro du tour actuel (int, 0 au départ)\n",
|
||||||
|
"\n",
|
||||||
|
"**Méthodes :**\n",
|
||||||
|
"- `__init__` : constructeur\n",
|
||||||
|
"- `afficher_etat()` : affiche le numéro du tour et les Pokémon actifs des deux dresseurs\n",
|
||||||
|
"- `lancer_combat()` : lance le combat jusqu'à ce qu'un dresseur n'ait plus de Pokémon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "5b189d40",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class Combat:\n",
|
||||||
|
" def __init__(self, dresseur1, dresseur2):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Constructeur de la classe Combat.\n",
|
||||||
|
"\n",
|
||||||
|
" :param dresseur1: (Dresseur) Premier dresseur\n",
|
||||||
|
" :param dresseur2: (Dresseur) Second dresseur\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def afficher_etat(self):\n",
|
||||||
|
" \"\"\"Affiche l'état actuel du combat.\"\"\"\n",
|
||||||
|
" print(f\"\\n{'='*40}\")\n",
|
||||||
|
" print(f\"Tour {self.tour}\")\n",
|
||||||
|
" print(f\"{'='*40}\")\n",
|
||||||
|
" # Afficher les Pokémon actifs\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass\n",
|
||||||
|
"\n",
|
||||||
|
" def lancer_combat(self):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Lance le combat tour par tour.\n",
|
||||||
|
" Chaque tour, les deux Pokémon actifs s'attaquent.\n",
|
||||||
|
" Quand un Pokémon est KO, le suivant prend sa place.\n",
|
||||||
|
" Le combat s'arrête quand un dresseur n'a plus de Pokémon.\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" print(f\"\\n*** COMBAT : {self.dresseur1.nom} VS {self.dresseur2.nom} ***\")\n",
|
||||||
|
"\n",
|
||||||
|
" while not self.dresseur1.tous_ko() and not self.dresseur2.tous_ko():\n",
|
||||||
|
" self.tour += 1\n",
|
||||||
|
" self.afficher_etat()\n",
|
||||||
|
"\n",
|
||||||
|
" # Récupérer les Pokémon actifs\n",
|
||||||
|
" poke1 = self.dresseur1.premier_pokemon_dispo()\n",
|
||||||
|
" poke2 = self.dresseur2.premier_pokemon_dispo()\n",
|
||||||
|
"\n",
|
||||||
|
" # Le Pokémon 1 attaque\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
"\n",
|
||||||
|
" # Vérifier si Pokémon 2 est KO\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
"\n",
|
||||||
|
" # Le Pokémon 2 attaque (s'il n'est pas KO)\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
"\n",
|
||||||
|
" # Vérifier si Pokémon 1 est KO\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
"\n",
|
||||||
|
" # Afficher le vainqueur\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "9585a7c3",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Vérification de l'exercice 5**\n",
|
||||||
|
"\n",
|
||||||
|
"Début de l'affichage attendu :\n",
|
||||||
|
"\n",
|
||||||
|
"```\n",
|
||||||
|
"*** COMBAT : Sacha VS Pierre ***\n",
|
||||||
|
"\n",
|
||||||
|
"========================================\n",
|
||||||
|
"Tour 1\n",
|
||||||
|
"========================================\n",
|
||||||
|
"Sacha: Pikachu (80/80 PV)\n",
|
||||||
|
"Pierre: Onix (120/120 PV)\n",
|
||||||
|
"\n",
|
||||||
|
"Pikachu attaque Onix et inflige 15 dégâts !\n",
|
||||||
|
"Onix attaque Pikachu et inflige 18 dégâts !\n",
|
||||||
|
"\n",
|
||||||
|
"========================================\n",
|
||||||
|
"Tour 2\n",
|
||||||
|
"========================================\n",
|
||||||
|
"Sacha: Pikachu (62/80 PV)\n",
|
||||||
|
"Pierre: Onix (105/120 PV)\n",
|
||||||
|
"\n",
|
||||||
|
"Pikachu attaque Onix et inflige 15 dégâts !\n",
|
||||||
|
"Onix attaque Pikachu et inflige 18 dégâts !\n",
|
||||||
|
"\n",
|
||||||
|
"...\n",
|
||||||
|
"\n",
|
||||||
|
"Pikachu est KO !\n",
|
||||||
|
"Sacha envoie Dracaufeu !\n",
|
||||||
|
"\n",
|
||||||
|
"...\n",
|
||||||
|
"\n",
|
||||||
|
"Tous les Pokémon de Pierre sont KO !\n",
|
||||||
|
"*** SACHA REMPORTE LE COMBAT ! ***\n",
|
||||||
|
"```\n",
|
||||||
|
"\n",
|
||||||
|
"Le combat doit durer **11 tours** et se terminer par la victoire de Sacha."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "a214d66b",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"sacha = Dresseur(\"Sacha\")\n",
|
||||||
|
"sacha.ajouter_pokemon(Pokemon(\"Pikachu\", \"Electrik\", 25, 80, 15))\n",
|
||||||
|
"sacha.ajouter_pokemon(Pokemon(\"Dracaufeu\", \"Feu\", 50, 150, 25))\n",
|
||||||
|
"sacha.ajouter_pokemon(Pokemon(\"Tortank\", \"Eau\", 45, 140, 22))\n",
|
||||||
|
"\n",
|
||||||
|
"pierre = Dresseur(\"Pierre\")\n",
|
||||||
|
"pierre.ajouter_pokemon(Pokemon(\"Onix\", \"Roche\", 30, 120, 18))\n",
|
||||||
|
"pierre.ajouter_pokemon(Pokemon(\"Racaillou\", \"Roche\", 20, 80, 12))\n",
|
||||||
|
"\n",
|
||||||
|
"combat = Combat(sacha, pierre)\n",
|
||||||
|
"combat.lancer_combat()\n",
|
||||||
|
"\n",
|
||||||
|
"assert pierre.tous_ko() is True, \"Pierre doit avoir perdu tous ses Pokémon\"\n",
|
||||||
|
"assert sacha.tous_ko() is False, \"Sacha doit avoir encore au moins un Pokémon\"\n",
|
||||||
|
"assert combat.tour == 11, \"Le nombre de tours n'est pas le bon\"\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"\\nExercice 5 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "89552429",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Partie 4 : Améliorations\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 6 : Centre Pokémon\n",
|
||||||
|
"\n",
|
||||||
|
"Complétez la classe `CentrePokemon`, qui permet de soigner toute l'équipe d'un dresseur."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "051b5163",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class CentrePokemon:\n",
|
||||||
|
" def __init__(self, ville):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" :param ville: (str) Ville où se trouve le centre\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" self.ville = ville\n",
|
||||||
|
"\n",
|
||||||
|
" def soigner_equipe(self, dresseur):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" Soigne tous les Pokémon d'un dresseur à 100% de leurs PV.\n",
|
||||||
|
"\n",
|
||||||
|
" :param dresseur: (Dresseur) Dresseur dont l'équipe doit être soignée\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" # À compléter\n",
|
||||||
|
" pass"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "641f5123",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"**Vérification de l'exercice 6**"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "e1bb51d5",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"sacha = Dresseur(\"Sacha\")\n",
|
||||||
|
"sacha.ajouter_pokemon(Pokemon(\"Pikachu\", \"Electrik\", 25, 80, 15))\n",
|
||||||
|
"sacha.ajouter_pokemon(Pokemon(\"Dracaufeu\", \"Feu\", 50, 150, 25))\n",
|
||||||
|
"sacha.equipe[0].subir_degats(100)\n",
|
||||||
|
"sacha.equipe[1].subir_degats(40)\n",
|
||||||
|
"\n",
|
||||||
|
"centre = CentrePokemon(\"Argenta\")\n",
|
||||||
|
"centre.soigner_equipe(sacha)\n",
|
||||||
|
"print(sacha)\n",
|
||||||
|
"\n",
|
||||||
|
"assert sacha.equipe[0].pv == 80, \"Pikachu doit retrouver tous ses PV\"\n",
|
||||||
|
"assert sacha.equipe[1].pv == 150, \"Dracaufeu doit retrouver tous ses PV\"\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"Exercice 6 : tous les tests sont passés.\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "22be32db",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"### Exercice 7 : Capacités spéciales (Pour aller plus loin)\n",
|
||||||
|
"\n",
|
||||||
|
"Voici une classe `Capacite` pour donner des attaques spéciales aux Pokémon.\n",
|
||||||
|
"\n",
|
||||||
|
"Modifiez la classe `Pokemon` pour qu'un Pokémon possède une liste de capacités (max 4) et puisse choisir son attaque. Vous pouvez aussi ajouter des méthodes à la classe `Capacite` (par exemple une méthode qui décrémente les PP à chaque utilisation)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "32a0e896",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"class Capacite:\n",
|
||||||
|
" def __init__(self, nom, puissance, type_capacite, pp_max):\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" :param nom: (str) Nom de la capacité\n",
|
||||||
|
" :param puissance: (int) Puissance de base\n",
|
||||||
|
" :param type_capacite: (str) Type de la capacité\n",
|
||||||
|
" :param pp_max: (int) Nombre d'utilisations max\n",
|
||||||
|
" \"\"\"\n",
|
||||||
|
" self.nom = nom\n",
|
||||||
|
" self.puissance = puissance\n",
|
||||||
|
" self.type_capacite = type_capacite\n",
|
||||||
|
" self.pp_max = pp_max\n",
|
||||||
|
" self.pp = pp_max"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "7d856e73",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Résumé des classes\n",
|
||||||
|
"\n",
|
||||||
|
"| Classe | Attributs | Méthodes principales |\n",
|
||||||
|
"|--------|-----------|----------------------|\n",
|
||||||
|
"| `Pokemon` | nom, type_pokemon, niveau, pv_max, pv, attaque | attaquer(), subir_degats(), est_ko(), soigner() |\n",
|
||||||
|
"| `Dresseur` | nom, equipe | ajouter_pokemon(), premier_pokemon_dispo(), tous_ko() |\n",
|
||||||
|
"| `Combat` | dresseur1, dresseur2, tour | afficher_etat(), lancer_combat() |\n",
|
||||||
|
"| `CentrePokemon` | ville | soigner_equipe() |\n",
|
||||||
|
"\n",
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"## Code de test final\n",
|
||||||
|
"\n",
|
||||||
|
"Toutes vos classes sont prêtes ? Lancez le combat complet."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"id": "bd1fa15a",
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# Création des Pokémon\n",
|
||||||
|
"pikachu = Pokemon(\"Pikachu\", \"Electrik\", 25, 80, 15)\n",
|
||||||
|
"dracaufeu = Pokemon(\"Dracaufeu\", \"Feu\", 50, 150, 25)\n",
|
||||||
|
"tortank = Pokemon(\"Tortank\", \"Eau\", 45, 140, 22)\n",
|
||||||
|
"onix = Pokemon(\"Onix\", \"Roche\", 30, 120, 18)\n",
|
||||||
|
"racaillou = Pokemon(\"Racaillou\", \"Roche\", 20, 80, 12)\n",
|
||||||
|
"\n",
|
||||||
|
"# Création des dresseurs\n",
|
||||||
|
"sacha = Dresseur(\"Sacha\")\n",
|
||||||
|
"sacha.ajouter_pokemon(pikachu)\n",
|
||||||
|
"sacha.ajouter_pokemon(dracaufeu)\n",
|
||||||
|
"sacha.ajouter_pokemon(tortank)\n",
|
||||||
|
"\n",
|
||||||
|
"pierre = Dresseur(\"Pierre\")\n",
|
||||||
|
"pierre.ajouter_pokemon(onix)\n",
|
||||||
|
"pierre.ajouter_pokemon(racaillou)\n",
|
||||||
|
"\n",
|
||||||
|
"# Lancement du combat\n",
|
||||||
|
"combat = Combat(sacha, pierre)\n",
|
||||||
|
"combat.lancer_combat()\n",
|
||||||
|
"\n",
|
||||||
|
"# Soins au Centre Pokémon\n",
|
||||||
|
"centre = CentrePokemon(\"Argenta\")\n",
|
||||||
|
"centre.soigner_equipe(sacha)\n",
|
||||||
|
"print()\n",
|
||||||
|
"print(sacha)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"id": "e44fab5c",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"---\n",
|
||||||
|
"\n",
|
||||||
|
"Auteurs : Florian Mathieu, Enzo Frémeaux, Timothée Decoster\n",
|
||||||
|
"\n",
|
||||||
|
"Licence CC BY-SA\n",
|
||||||
|
"\n",
|
||||||
|
"<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\"><img alt=\"Licence Creative Commons\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-sa/4.0/88x31.png\" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"name": "python"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
@@ -25,9 +25,9 @@ L'utilisateur a l'impression que les programmes s'exécutent simultanément grâ
|
|||||||
1. **Le découpage en processus** : Chaque programme est divisé en plusieurs processus (unités d'exécution).
|
1. **Le découpage en processus** : Chaque programme est divisé en plusieurs processus (unités d'exécution).
|
||||||
|
|
||||||
2. **L'ordonnancement** : Le système d'exploitation utilise un ordonnanceur qui :
|
2. **L'ordonnancement** : Le système d'exploitation utilise un ordonnanceur qui :
|
||||||
- Gère une file d'attente des processus prêts à s'exécuter
|
- Gère une file d'attente des processus prêts à s'exécuter
|
||||||
- Alloue le processeur à chaque processus pendant un court laps de temps (quantum)
|
- Alloue le processeur à chaque processus pendant un court laps de temps (quantum)
|
||||||
- Effectue des changements de contexte très rapides entre les processus
|
- Effectue des changements de contexte très rapides entre les processus
|
||||||
|
|
||||||
3. **La rapidité du processeur** : Le processeur exécute des milliards d'instructions par seconde. Les changements de contexte sont si rapides (quelques millisecondes) que l'utilisateur ne perçoit pas les interruptions.
|
3. **La rapidité du processeur** : Le processeur exécute des milliards d'instructions par seconde. Les changements de contexte sont si rapides (quelques millisecondes) que l'utilisateur ne perçoit pas les interruptions.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# NSI Terminale - Lycée Charlotte Perriand
|
# NSI Terminale - Lycée Charlotte Perriand
|
||||||
|
|
||||||
[](LICENCE.md)
|
[](https://creativecommons.org/licenses/by-sa/4.0/deed.fr)
|
||||||
[](https://jupyter.org/)
|
[](https://jupyter.org/)
|
||||||
|
|
||||||
Cours de **Numérique et Sciences Informatiques** pour les élèves de Terminale.
|
Cours de **Numérique et Sciences Informatiques** pour les élèves de Terminale.
|
||||||
@@ -22,18 +22,18 @@ Les fichiers `.ipynb` peuvent être ouverts avec :
|
|||||||
<tr>
|
<tr>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Modularité" href="Modularité/"><img src='assets/modular.svg' width="80px"/><br/><b>Modularité</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Modularité" href="Modularité/"><img src='assets/modular.svg' width="80px"/><br/><b>Modularité</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Récursivité" href="Recursivité/"><img src='assets/recursivite.svg' width="80px"/><br/><b>Récursivité</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Récursivité" href="Recursivité/"><img src='assets/recursivite.svg' width="80px"/><br/><b>Récursivité</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="POO" href="POO"><img src='assets/poo.svg' width="80px"/><br/><b>POO</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="POO" href="POO/"><img src='assets/poo.svg' width="80px"/><br/><b>POO</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Pile et File" href="Pile_File/"><img src='assets/pile_file.svg' width="80px"/><br/><b>Pile & File</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Pile et File" href="Structures_lineaires/Pile_File/"><img src='assets/pile_file.svg' width="80px"/><br/><b>Pile & File</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Arbres" href="Arbres/"><img src='assets/arbre.svg' width="80px"/><br/><b>Arbres</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Arbres" href="Arbres/"><img src='assets/arbre.svg' width="80px"/><br/><b>Arbres</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Graphes" href="Graphes/"><img src='assets/graphe.svg' width="80px"/><br/><b>Graphes</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Graphes" href="Graphes/"><img src='assets/graphe.svg' width="80px"/><br/><b>Graphes</b></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Bases de données" href="BDD_SGBD"><img src='assets/bdd.svg' width="80px"/><br/><b>BDD</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Bases de données" href="BDD_SGBD/"><img src='assets/bdd.svg' width="80px"/><br/><b>BDD</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="SQL" href="SQL"><img src='assets/sgbd.svg' width="80px"/><br/><b>SQL</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="SQL" href="SQL/"><img src='assets/sgbd.svg' width="80px"/><br/><b>SQL</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Routage" href="Routage"><img src='assets/routage.svg' width="80px"/><br/><b>Routage</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Routage" href="Routage/"><img src='assets/routage.svg' width="80px"/><br/><b>Routage</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Calculabilité" href="Calculabilité"><img src='assets/calculabilite.svg' width="80px"/><br/><b>Calculabilité</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Calculabilité" href="Calculabilité/"><img src='assets/calculabilite.svg' width="80px"/><br/><b>Calculabilité</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Recherche textuelle" href="Recherche_textuelle"><img src='assets/recherche.svg' width="80px"/><br/><b>Recherche textuelle</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Recherche textuelle" href="Recherche_textuelle/"><img src='assets/recherche.svg' width="80px"/><br/><b>Recherche textuelle</b></a></td>
|
||||||
<td style="text-align: center; padding: 10px;"><a title="Paradigmes" href="Paradigmes"><img src='assets/paradigme.svg' width="80px"/><br/><b>Paradigmes</b></a></td>
|
<td style="text-align: center; padding: 10px;"><a title="Paradigmes" href="Paradigmes/"><img src='assets/paradigme.svg' width="80px"/><br/><b>Paradigmes</b></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ Les fichiers `.ipynb` peuvent être ouverts avec :
|
|||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
Ce cours est sous licence [Creative Commons BY 4.0](LICENCE.md).
|
Ce cours est sous licence [Creative Commons BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.fr).
|
||||||
Vous pouvez le réutiliser et le modifier librement en citant l'auteur.
|
Vous pouvez le réutiliser et le modifier librement en citant l'auteur.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# Exercices : Diviser pour régner
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Les trois premiers exercices se traitent sur papier avant de toucher au clavier. Un algorithme que vous ne savez pas dérouler à la main est un algorithme que vous ne saurez pas déboguer à l'écran. Les derniers sont volontairement plus exigeants.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 1 : Dérouler le tri fusion
|
||||||
|
|
||||||
|
On trie la liste suivante avec le tri fusion vu en cours :
|
||||||
|
|
||||||
|
```python
|
||||||
|
[5, 3, 8, 1, 9, 2, 7]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Dessiner l'arbre des divisions, jusqu'à n'obtenir que des listes d'un seul élément.
|
||||||
|
2. Écrire, étage par étage, les fusions successives qui reconstituent la liste triée.
|
||||||
|
3. Combien d'étages de division compte-t-on pour une liste de 8 éléments ? De 16 éléments ? De 1024 éléments ?
|
||||||
|
4. En déduire la relation entre le nombre d'étages et la taille de la liste. Quel est le rapport avec la complexité annoncée en cours ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 2 : La fusion vue de près
|
||||||
|
|
||||||
|
On reprend la fonction `fusionner` du cours, celle qui réunit deux listes déjà triées.
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Dérouler l'appel `fusionner([2, 5, 9], [1, 3, 12])` dans un tableau, en notant à chaque tour de boucle les valeurs de `i`, de `j` et de `resultat`.
|
||||||
|
2. Combien de comparaisons entre éléments cette fusion a-t-elle demandées ?
|
||||||
|
3. Donner deux listes de trois éléments chacune dont la fusion ne demande que trois comparaisons. Expliquer ce qui se produit.
|
||||||
|
4. Quel est le nombre maximal de comparaisons pour fusionner une liste de *p* éléments et une liste de *q* éléments ? Justifier.
|
||||||
|
5. La fonction se termine par `return resultat + gauche[i:] + droite[j:]`. Pourquoi peut-on ajouter d'un seul coup tout ce qui reste, sans le comparer à quoi que ce soit ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 3 : Recherche dichotomique
|
||||||
|
|
||||||
|
Chercher une valeur dans une liste **triée** est le deuxième exemple canonique du diviser pour régner : on compare avec l'élément du milieu, et on élimine la moitié de la liste à chaque étape.
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Écrire une fonction récursive `recherche(tab, x)` qui renvoie `True` si `x` figure dans la liste triée `tab`, et `False` sinon.
|
||||||
|
2. Dérouler `recherche([1, 4, 6, 9, 12, 15, 20], 12)`. Quelles sous-listes sont successivement examinées, et combien d'appels sont nécessaires ?
|
||||||
|
3. On veut maintenant connaître l'**indice** de `x`, et plus seulement sa présence. Expliquer pourquoi la fonction de la question 1, qui découpe la liste en tranches, ne permet pas d'y répondre directement.
|
||||||
|
4. Écrire une fonction `indice(tab, x, debut, fin)` qui renvoie l'indice de `x` dans `tab`, ou `-1` s'il est absent, **sans jamais découper la liste**.
|
||||||
|
5. Sur une liste d'un million d'éléments, combien d'appels au maximum ? Combien pour une liste deux fois plus longue ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 4 : Le maximum, avec et sans diviser pour régner
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Écrire une fonction récursive `maximum(tab)` qui applique le schéma du cours : si la liste ne contient qu'un élément, le renvoyer ; sinon la couper en deux, chercher le maximum de chaque moitié, et renvoyer le plus grand des deux résultats.
|
||||||
|
2. Combien de comparaisons cette fonction effectue-t-elle sur une liste de 8 éléments ? Et la boucle `for` que vous écririez spontanément ?
|
||||||
|
3. Le découpage apporte-t-il un gain ici ? Justifier.
|
||||||
|
4. Un tel découpage ne fait donc pas toujours gagner. À quelle condition sur l'étape « combiner » la méthode devient-elle intéressante ? Comparer avec le tri fusion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 5 : Compter les occurrences dans une liste triée
|
||||||
|
|
||||||
|
Un serveur de jeu conserve les scores de ses 500 000 joueurs dans une liste **triée par ordre croissant**. Plusieurs joueurs peuvent avoir exactement le même score, et l'on veut savoir combien.
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Écrire une fonction `compter_naif(tab, x)` qui parcourt la liste et compte les occurrences de `x`. Quelle est sa complexité ?
|
||||||
|
2. Écrire une fonction `premiere_occurrence(tab, x)` qui renvoie, par dichotomie, l'indice de la **première** apparition de `x`, ou `-1` s'il est absent. On prendra garde à ne pas s'arrêter à la première correspondance trouvée.
|
||||||
|
3. Écrire de même `derniere_occurrence(tab, x)`.
|
||||||
|
4. En déduire une fonction `compter(tab, x)` et donner sa complexité.
|
||||||
|
5. Sur les 500 000 scores, combien d'opérations séparent les deux méthodes, en ordre de grandeur ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Exercice 6 : Compter les inversions
|
||||||
|
|
||||||
|
Une **inversion** dans une liste `tab` est un couple d'indices (*i*, *j*) tel que *i* < *j* et `tab[i] > tab[j]`, autrement dit deux éléments rangés dans le mauvais ordre l'un par rapport à l'autre. Le nombre d'inversions mesure le désordre d'une liste : il vaut 0 pour une liste triée, et il est maximal pour une liste rangée à l'envers. Les sites de recommandation s'en servent pour estimer à quel point deux classements se ressemblent.
|
||||||
|
|
||||||
|
**Questions :**
|
||||||
|
|
||||||
|
1. Donner les inversions de la liste `[2, 4, 1, 3, 5]`. Combien y en a-t-il ?
|
||||||
|
2. Quelle liste de *n* éléments en compte le plus ? Combien exactement ?
|
||||||
|
3. Écrire une fonction `inversions_naif(tab)` qui les compte avec deux boucles imbriquées. Quelle est sa complexité ?
|
||||||
|
4. On veut faire mieux en s'appuyant sur le tri fusion. Pendant la fusion de `gauche` et de `droite`, toutes deux déjà triées, on prend parfois un élément de `droite` alors qu'il reste encore des éléments dans `gauche`. Combien d'inversions ce seul choix révèle-t-il d'un coup ? Justifier soigneusement.
|
||||||
|
5. Écrire `fusionner_et_compter(gauche, droite)` qui renvoie le couple formé de la liste fusionnée et du nombre d'inversions découvertes pendant cette fusion.
|
||||||
|
6. En déduire `tri_fusion_inversions(tab)` qui renvoie le couple formé de la liste triée et du nombre total d'inversions. Attention à ne pas oublier les inversions comptées dans chaque moitié.
|
||||||
|
7. Quelle est la complexité obtenue ? Sur une liste de 100 000 éléments, quel facteur sépare cette version de celle de la question 3 ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Auteur : Florian Mathieu
|
||||||
|
|
||||||
|
Licence CC BY-SA
|
||||||
|
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
## La Flamme - Algorithmes de tri
|
||||||
|
|
||||||
|
<img src="https://upload.wikimedia.org/wikipedia/commons/7/72/La_Flamme_-_Logo.png" alt="La Flamme" style="zoom:50%;" />
|
||||||
|
|
||||||
|
*La Flamme est une série Canal+ parodiant les émissions de téléréalité sentimentale de type Bachelor.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Contexte
|
||||||
|
|
||||||
|
Marc, le Bachelor de *La Flamme*, arrive à la **Grande Cérémonie des Roses Finale**.
|
||||||
|
Il a rencontré douze prétendant·e·s au fil des épisodes, et son équipe de production a calculé un **score de compatibilité** pour chacun·e.
|
||||||
|
|
||||||
|
Le problème : la liste est dans le désordre, et Marc doit la parcourir **classée du moins compatible au plus compatible** pour ménager le suspense et remettre la rose en dernier au ou à la grand·e vainqueur·e.
|
||||||
|
|
||||||
|
La production lui propose deux stratégies. À vous de les implémenter et de les comparer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Les données
|
||||||
|
|
||||||
|
Le score de compatibilité est calculé selon la formule :
|
||||||
|
|
||||||
|
```
|
||||||
|
score = charme + sincérité - drama + karaoké + cuisine
|
||||||
|
```
|
||||||
|
|
||||||
|
Marc aime le charme, la sincérité, le talent au karaoké et la cuisine maison.
|
||||||
|
En revanche, **chaque point de drama retire un point au score**.
|
||||||
|
|
||||||
|
```python
|
||||||
|
pretendants = [
|
||||||
|
{"nom": "Nadjim", "charme": 9, "sincerite": 5, "drama": 8, "karaoké": 7, "cuisine": 6, "score": 19},
|
||||||
|
{"nom": "Bibou", "charme": 6, "sincerite": 9, "drama": 2, "karaoké": 5, "cuisine": 8, "score": 26},
|
||||||
|
{"nom": "Sébastien", "charme": 8, "sincerite": 7, "drama": 3, "karaoké": 9, "cuisine": 4, "score": 25},
|
||||||
|
{"nom": "Valérie", "charme": 7, "sincerite": 8, "drama": 1, "karaoké": 6, "cuisine": 9, "score": 29},
|
||||||
|
{"nom": "Kevin", "charme": 5, "sincerite": 6, "drama": 9, "karaoké": 4, "cuisine": 3, "score": 9},
|
||||||
|
{"nom": "Stéphanie", "charme": 9, "sincerite": 4, "drama": 7, "karaoké": 8, "cuisine": 5, "score": 19},
|
||||||
|
{"nom": "Martial", "charme": 4, "sincerite":10, "drama": 1, "karaoké": 3, "cuisine": 7, "score": 23},
|
||||||
|
{"nom": "Chrystel", "charme": 8, "sincerite": 3, "drama": 6, "karaoké": 9, "cuisine": 6, "score": 20},
|
||||||
|
{"nom": "Didier", "charme": 6, "sincerite": 7, "drama": 4, "karaoké": 5, "cuisine":10, "score": 24},
|
||||||
|
{"nom": "Sandrine", "charme":10, "sincerite": 6, "drama": 5, "karaoké": 7, "cuisine": 4, "score": 22},
|
||||||
|
{"nom": "Jérémy", "charme": 3, "sincerite": 9, "drama": 2, "karaoké": 6, "cuisine": 8, "score": 24},
|
||||||
|
{"nom": "Natacha", "charme": 7, "sincerite": 5, "drama": 8, "karaoké":10, "cuisine": 5, "score": 19},
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Vérifier sur deux ou trois prétendant·e·s que la formule donne bien le score indiqué.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Partie 1 - Tri par sélection *(rappel de Première)*
|
||||||
|
|
||||||
|
La première stratégie de la production s'appelle **"La Rose du Moins Aimé"** :
|
||||||
|
|
||||||
|
> "À chaque cérémonie, on parcourt *tous* les prétendant·e·s encore classé·e·s, on identifie celui ou celle qui a le score le plus bas, et on le ou la place en premier. On recommence jusqu'à avoir tout classé."
|
||||||
|
|
||||||
|
1. En une phrase, expliquer en quoi cette description correspond au **tri par sélection**.
|
||||||
|
|
||||||
|
2. Compléter la fonction suivante :
|
||||||
|
|
||||||
|
```python
|
||||||
|
def tri_selection(tab):
|
||||||
|
n = len(tab)
|
||||||
|
for i in range(n):
|
||||||
|
idx_min = i
|
||||||
|
for j in range(i + 1, n):
|
||||||
|
if tab[j]["score"] < tab[idx_min]["score"]:
|
||||||
|
# à compléter
|
||||||
|
pass
|
||||||
|
# à compléter : echanger tab[i] et tab[idx_min]
|
||||||
|
return tab
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Appliquer `tri_selection` à la liste `pretendants` et afficher les noms dans l'ordre obtenu.
|
||||||
|
|
||||||
|
4. Pour une liste de **n** prétendant·e·s, combien de comparaisons de scores effectue cet algorithme au total ? Exprimer le résultat en fonction de n, puis calculer pour n = 12.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Partie 2 - Tri fusion *(diviser pour régner)*
|
||||||
|
|
||||||
|
La deuxième stratégie de la production s'appelle **"Les Deux Villas"** :
|
||||||
|
|
||||||
|
> "On sépare les prétendant·e·s en deux groupes. On classe chaque groupe séparément. Puis on réunit les deux listes classées en une seule, en les fusionnant."
|
||||||
|
|
||||||
|
C'est exactement l'algorithme de **tri fusion**, vu dans le cours.
|
||||||
|
|
||||||
|
#### 2.1 - La fonction `fusionner`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def fusionner(gauche, droite):
|
||||||
|
resultat = []
|
||||||
|
i, j = 0, 0
|
||||||
|
while i < len(gauche) and j < len(droite):
|
||||||
|
if gauche[i]["score"] <= droite[j]["score"]:
|
||||||
|
resultat.append(gauche[i])
|
||||||
|
i += 1
|
||||||
|
else:
|
||||||
|
resultat.append(droite[j])
|
||||||
|
j += 1
|
||||||
|
return resultat + gauche[i:] + droite[j:]
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Expliquer le rôle des variables `i` et `j` dans cette fonction.
|
||||||
|
2. Que se passe-t-il à la ligne `return resultat + gauche[i:] + droite[j:]` ?
|
||||||
|
Pourquoi est-il nécessaire d'ajouter `gauche[i:]` et `droite[j:]` à la fin ?
|
||||||
|
3. Appliquer *à la main* `fusionner` sur ces deux sous-listes déjà triées, et écrire le résultat étape par étape :
|
||||||
|
|
||||||
|
```python
|
||||||
|
gauche = [{"nom": "Kevin", "score": 9}, {"nom": "Martial", "score": 23}]
|
||||||
|
droite = [{"nom": "Chrystel", "score": 20}, {"nom": "Valérie", "score": 29}]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 - La fonction `tri_fusion`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def tri_fusion(tab):
|
||||||
|
if len(tab) <= 1:
|
||||||
|
return tab
|
||||||
|
milieu = len(tab) // 2
|
||||||
|
gauche = tri_fusion( ) # à compléter
|
||||||
|
droite = tri_fusion( ) # à compléter
|
||||||
|
return fusionner(gauche, droite)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Compléter la fonction `tri_fusion`.
|
||||||
|
5. Quel est le **cas de base** de cette fonction récursive ? Pourquoi une liste de taille 0 ou 1 est-elle "déjà triée" ?
|
||||||
|
6. Appliquer `tri_fusion` à la liste `pretendants`. Vérifier que le résultat est identique à celui du tri par sélection.
|
||||||
|
|
||||||
|
#### 2.3 - Déroulé de l'algorithme
|
||||||
|
|
||||||
|
7. Sur la sous-liste ci-dessous, montrer **toutes les étapes** de `tri_fusion` : les divisions successives, puis les fusions, jusqu'au résultat final.
|
||||||
|
|
||||||
|
```python
|
||||||
|
sous_liste = [
|
||||||
|
{"nom": "Sandrine", "score": 22},
|
||||||
|
{"nom": "Kevin", "score": 9},
|
||||||
|
{"nom": "Bibou", "score": 26},
|
||||||
|
{"nom": "Chrystel", "score": 20},
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Partie 3 - Comparaison des complexités
|
||||||
|
|
||||||
|
| Algorithme | Complexité |
|
||||||
|
|-----------------|------------|
|
||||||
|
| Tri par sélection | O(n²) |
|
||||||
|
| Tri fusion | O(n log n) |
|
||||||
|
|
||||||
|
1. Pour **n = 12** prétendant·e·s :
|
||||||
|
- Combien d'opérations environ pour le tri par sélection ?
|
||||||
|
- Combien d'opérations environ pour le tri fusion ? *(rappel : log₂(12) ≈ 3,58)*
|
||||||
|
|
||||||
|
2. La saison 2 de La Flamme est un succès planétaire. Marc reçoit désormais **1 000 candidatures**.
|
||||||
|
Calculer l'ordre de grandeur du nombre d'opérations pour chaque algorithme.
|
||||||
|
Que remarquez-vous ?
|
||||||
|
|
||||||
|
3. La production doit choisir un algorithme à intégrer dans leur logiciel de classement. Lequel recommandez-vous, et pourquoi ?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Bonus - Marc change d'avis
|
||||||
|
|
||||||
|
Marc, dans un élan de narcissisme, décide finalement de classer les prétendant·e·s **par charme décroissant** plutôt que par score.
|
||||||
|
|
||||||
|
Modifier la fonction `fusionner` pour trier selon `charme` en ordre **décroissant**. Appliquer le tri fusion modifié à la liste et afficher le classement final.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Sources :
|
||||||
|
- Programme officiel NSI Terminale - Algorithmique
|
||||||
|
- [La Flamme - Canal+](https://www.canalplus.com/series/la-flamme/)
|
||||||
|
|
||||||
|
Auteur : Florian Mathieu - Licence CC BY-SA
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
## Activité : La récursivité dans les jeux vidéo
|
|
||||||
|
|
||||||
### Contexte :
|
|
||||||
Imaginez un jeu vidéo populaire où le héros doit traverser différents niveaux pour sauver un personnage captif. Chaque niveau est plus difficile que le précédent, et chaque niveau contient des mini-boss qu'il faut vaincre avant de passer au suivant.
|
|
||||||
|
|
||||||
### Objectif de l'activité :
|
|
||||||
Utiliser la récursivité pour simuler le parcours du héros à travers les niveaux du jeu.
|
|
||||||
|
|
||||||
### Instructions :
|
|
||||||
|
|
||||||
### Présentation du problème :
|
|
||||||
- Le héros commence au niveau 1 et doit atteindre le niveau `n`.
|
|
||||||
- À chaque niveau, il y a un certain nombre de mini-boss à vaincre avant de passer au niveau suivant.
|
|
||||||
- Si le héros vainc tous les mini-boss d'un niveau, il passe au niveau suivant, sinon il recommence le même niveau.
|
|
||||||
|
|
||||||
### Modélisation en pseudo-code :
|
|
||||||
Écrire une fonction récursive `traverse_levels` qui prend en entrée le niveau actuel et le nombre total de niveaux.
|
|
||||||
|
|
||||||
- Si le niveau actuel est supérieur au nombre total de niveaux, le héros a gagné.
|
|
||||||
- Sinon, le héros combat les mini-boss et passe au niveau suivant.
|
|
||||||
|
|
||||||
### 3. Exemple de code en Python
|
|
||||||
```python
|
|
||||||
def combat_mini_bosses(level):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def traverse_levels(current_level, total_levels):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
@@ -1,349 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "66904fb8",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# TP : La Récursivité et le Diviser pour Régner\n",
|
|
||||||
"\n",
|
|
||||||
"## Objectifs :\n",
|
|
||||||
"- Comprendre le principe de la récursivité.\n",
|
|
||||||
"- Appliquer la récursivité pour résoudre des problèmes simples.\n",
|
|
||||||
"- Approfondir la méthode du **diviser pour régner** à travers des exemples concrets.\n",
|
|
||||||
"- Compléter un algorithme de **tri fusion**.\n",
|
|
||||||
"\n",
|
|
||||||
"### Rappel sur la récursivité :\n",
|
|
||||||
"La récursivité est une méthode où une fonction s'appelle elle-même pour résoudre un problème. Chaque appel de la fonction permet de simplifier le problème jusqu'à atteindre une condition de base (appelée **cas de base**) qui permet de terminer la récursion.\n",
|
|
||||||
"\n",
|
|
||||||
"**Exemple classique :** Calcul de la factorielle d'un nombre entier positif `n`.\n",
|
|
||||||
"```python\n",
|
|
||||||
"def factorielle(n):\n",
|
|
||||||
" if n == 0:\n",
|
|
||||||
" return 1 # Cas de base\n",
|
|
||||||
" else:\n",
|
|
||||||
" return n * factorielle(n-1) # Appel récursif\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "bb057eb6",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Exercice 1 : Fonction récursive `traduire_romain`\n",
|
|
||||||
"**But :** Écrire une fonction récursive `traduire_romain` qui prend en paramètre une chaîne de caractères non vide représentant un nombre écrit en chiffres romains, et qui renvoie son écriture décimale.\n",
|
|
||||||
"\n",
|
|
||||||
"**Consignes :**\n",
|
|
||||||
"- Chaque chiffre romain a une valeur : `I=1, V=5, X=10, L=50, C=100, D=500, M=1000`.\n",
|
|
||||||
"- Si un chiffre plus petit précède un chiffre plus grand (ex : IV), cela signifie qu'il faut soustraire la valeur du chiffre plus petit.\n",
|
|
||||||
" \n",
|
|
||||||
"**Exemple :**\n",
|
|
||||||
"```python\n",
|
|
||||||
"traduire_romain(\"IX\") # Renvoie 9\n",
|
|
||||||
"traduire_romain(\"MCMXCIV\") # Renvoie 1994\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"**Indication :** Utilisez la récursion pour traiter un caractère à la fois, et soustrayez ou ajoutez en fonction de la position relative des caractères.\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 7,
|
|
||||||
"id": "ff49f2f3",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"None\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def traduire_romain(chaine):\n",
|
|
||||||
" pass\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"print(traduire_romain(\"IX\")) # Doit afficher 9\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "1aedbf03",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Exercice 2 : Compléter un Tri Fusion\n",
|
|
||||||
"**But :** Compléter l'algorithme du tri fusion.\n",
|
|
||||||
"\n",
|
|
||||||
"Le tri fusion est un exemple typique de la méthode de **diviser pour régner**. L'idée est de diviser le tableau en deux, de trier chaque moitié, puis de fusionner les deux moitiés triées.\n",
|
|
||||||
"\n",
|
|
||||||
"Voici un code partiellement écrit que vous devez compléter :\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 8,
|
|
||||||
"id": "31d950ac",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"[38, 27, 43, 3, 9, 82, 10]\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def tri_fusion(tab):\n",
|
|
||||||
" if len(tab) <= 1:\n",
|
|
||||||
" return tab # Cas de base\n",
|
|
||||||
" milieu = len(tab) // 2\n",
|
|
||||||
" gauche = tri_fusion(tab[:milieu]) # Appel récursif\n",
|
|
||||||
" droite = tri_fusion(tab[milieu:]) # Appel récursif\n",
|
|
||||||
" return fusionner(gauche, droite)\n",
|
|
||||||
"\n",
|
|
||||||
"def fusionner(gauche, droite):\n",
|
|
||||||
" tableau_fusionne = []\n",
|
|
||||||
" i, j = 0, 0\n",
|
|
||||||
" # Complétez la fonction pour fusionner les deux sous-tableaux ici :\n",
|
|
||||||
" # ---------------------------------------------\n",
|
|
||||||
"\n",
|
|
||||||
" # ---------------------------------------------\n",
|
|
||||||
" # Ajoutez ici les éléments restants des sous-tableaux\n",
|
|
||||||
" tableau_fusionne += gauche[i:]\n",
|
|
||||||
" tableau_fusionne += droite[j:]\n",
|
|
||||||
" return tableau_fusionne\n",
|
|
||||||
"\n",
|
|
||||||
"# Test de la fonction tri_fusion\n",
|
|
||||||
"print(tri_fusion([38, 27, 43, 3, 9, 82, 10])) # Doit afficher une liste triée\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "15791934",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Exercice 3 : Diviser pour Régner — Recherche d'un élément dans un tableau\n",
|
|
||||||
"**But :** Implémenter la recherche d'un élément dans un tableau trié en utilisant la méthode de **diviser pour régner** (recherche dichotomique).\n",
|
|
||||||
"\n",
|
|
||||||
"La recherche dichotomique consiste à diviser le tableau en deux parties à chaque étape :\n",
|
|
||||||
"- Si l'élément recherché est au milieu, vous avez terminé.\n",
|
|
||||||
"- Si l'élément est plus petit que l'élément du milieu, il se trouve dans la première moitié du tableau.\n",
|
|
||||||
"- Sinon, il se trouve dans la deuxième moitié.\n",
|
|
||||||
"\n",
|
|
||||||
"Voici un squelette à compléter :\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 9,
|
|
||||||
"id": "ab9509b5",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"None\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def recherche_dichotomique(tab, element, debut=0, fin=None):\n",
|
|
||||||
" if fin is None:\n",
|
|
||||||
" fin = len(tab) - 1\n",
|
|
||||||
" if debut > fin:\n",
|
|
||||||
" return -1 # L'élément n'est pas dans le tableau\n",
|
|
||||||
" milieu = (debut + fin) // 2\n",
|
|
||||||
" if tab[milieu] == element:\n",
|
|
||||||
" return # L'élément est trouvé\n",
|
|
||||||
" # Complétez ici avec les appels récursifs manquants :\n",
|
|
||||||
" # --------------------------------------------------\n",
|
|
||||||
" \n",
|
|
||||||
" # --------------------------------------------------\n",
|
|
||||||
" \n",
|
|
||||||
"# Test de la fonction\n",
|
|
||||||
"tab = [3, 9, 10, 27, 38, 43, 82]\n",
|
|
||||||
"element = 27\n",
|
|
||||||
"print(recherche_dichotomique(tab, element)) # Doit afficher l'index de l'élément trouvé\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "99671e3b",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Exercice 4 : \n",
|
|
||||||
"\n",
|
|
||||||
"On considère des tableaux de nombres dont tous les éléments sont présents\n",
|
|
||||||
"exactement trois fois à la suite, sauf un élément qui est présent une unique fois et\n",
|
|
||||||
"que l'on appelle « l'intrus ». \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Voici quelques exemples :\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"id": "f7a2fa7d",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5,\n",
|
|
||||||
"5, 5]\n",
|
|
||||||
"#l'intrus est 7\n",
|
|
||||||
"tab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n",
|
|
||||||
"#l'intrus est 8\n",
|
|
||||||
"tab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n",
|
|
||||||
"#l'intrus est 3"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "f693789b",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"On remarque qu'avec de tels tableaux : \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
" pour les indices multiples de 3 situés strictement avant l'intrus, l'élément\n",
|
|
||||||
"correspondant et son voisin de droite sont égaux,\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
" pour les indices multiples de 3 situés après l'intrus, l'élément correspondant et\n",
|
|
||||||
"son voisin de droite - s'il existe - sont différents.\n",
|
|
||||||
"\n",
|
|
||||||
"Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins\n",
|
|
||||||
"marquées par des caractères ^"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "b0549a7c",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n",
|
|
||||||
"^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n",
|
|
||||||
"0 3 6 9 12 15 18 21 "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "fbb578a8",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Dans des listes comme celles ci-dessus, un algorithme récursif pour trouver l'intrus\n",
|
|
||||||
"consiste alors à choisir un indice i multiple de 3 situé approximativement au milieu\n",
|
|
||||||
"des indices parmi lesquels se trouve l'intrus.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Puis, en fonction des valeurs de l'élément d'indice i et de son voisin de droite, à\n",
|
|
||||||
"appliquer récursivement l'algorithme à la moitié droite ou à la moitié gauche des\n",
|
|
||||||
"indices parmi lesquels se trouve l'intrus."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "b0603315",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Par exemple, si on s’intéresse à l’indice 12, on voit les valeurs 2 et 4 qui sont\n",
|
|
||||||
"différentes : l’intrus est donc à gauche de l’indice 12 (indice 12 compris)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"En revanche, si on s’intéresse à l’indice 3, on voit les valeurs 9 et 9 qui sont\n",
|
|
||||||
"identiques : l’intrus est donc à droite des indices 3-4-5, donc à partir de l’indice 6."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "bb44af36",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Compléter la fonction récursive **trouver_intrus** proposée page suivante qui met\n",
|
|
||||||
"en œuvre cet algorithme."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 11,
|
|
||||||
"id": "887c8914",
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"ename": "SyntaxError",
|
|
||||||
"evalue": "invalid character '–' (U+2013) (617363500.py, line 9)",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"\u001b[0;36m Cell \u001b[0;32mIn[11], line 9\u001b[0;36m\u001b[0m\n\u001b[0;31m nombre_de_triplets = (d – g) // ...\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid character '–' (U+2013)\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def trouver_intrus(tab, g, d):\n",
|
|
||||||
" \n",
|
|
||||||
" '''Renvoie la valeur de l'intrus situé entre les indices g et d dans la liste tab où :\n",
|
|
||||||
" tab vérifie les conditions de l'exercice, g et d sont des multiples de 3.\n",
|
|
||||||
" '''\n",
|
|
||||||
" if g == d:\n",
|
|
||||||
" return ...\n",
|
|
||||||
" else:\n",
|
|
||||||
" nombre_de_triplets = (d – g) // ...\n",
|
|
||||||
" indice = g + 3 * (nombre_de_triplets // 2)\n",
|
|
||||||
" if ... :\n",
|
|
||||||
" return ...\n",
|
|
||||||
" else:\n",
|
|
||||||
" return ..."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "679501d0",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Exemples :"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"id": "d06a36b2",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
">>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4,\n",
|
|
||||||
"4, 4, 8, 8, 8, 5, 5, 5], 0, 21)\n",
|
|
||||||
"7\n",
|
|
||||||
">>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3],\n",
|
|
||||||
"0, 12)\n",
|
|
||||||
"8\n",
|
|
||||||
">>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8,\n",
|
|
||||||
"8, 8], 0, 15)\n",
|
|
||||||
"3"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python (myenv)",
|
|
||||||
"language": "python",
|
|
||||||
"name": "myenv"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.12.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 5
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
# TP Récursivité
|
|
||||||
|
|
||||||
------
|
|
||||||
|
|
||||||
## 1. Courbe de Koch
|
|
||||||
|
|
||||||
> Prérequis : Module turtle
|
|
||||||
|
|
||||||
La courbe de Koch est une figure fractale récursive. Elle fait partie des premières fractales décrites mathématiquement (1904).
|
|
||||||
|
|
||||||
### Principe de construction
|
|
||||||
|
|
||||||
**Ordre 0** : Un simple segment de longueur `cote`.
|
|
||||||
|
|
||||||
```
|
|
||||||
─────────────────────
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ordre 1** : Le segment est divisé en 3 parties égales. La partie centrale est remplacée par deux segments formant un triangle équilatéral sans sa base (un "chapeau" ^).
|
|
||||||
|
|
||||||
```
|
|
||||||
/\
|
|
||||||
/ \
|
|
||||||
──────/ \──────
|
|
||||||
```
|
|
||||||
|
|
||||||
**Ordre 2 et suivants** : On applique la même transformation à chaque segment de la figure précédente.
|
|
||||||
|
|
||||||
```
|
|
||||||
/\
|
|
||||||
/ \ /\
|
|
||||||
/ \ / \
|
|
||||||
─/ \──/ \─
|
|
||||||
```
|
|
||||||
|
|
||||||
### Questions
|
|
||||||
|
|
||||||
1. Écrire de manière récursive le code de la fonction `courbe_koch(n, cote)` permettant de dessiner cette courbe à l'ordre `n` avec des segments de longueur `cote`.
|
|
||||||
|
|
||||||
Nous voulons obtenir maintenant un **flocon de Koch**. Celui-ci est composé de trois courbes de Koch disposées en triangle équilatéral.
|
|
||||||
|
|
||||||
2. Écrire le code de la fonction `flocon(n, cote)` qui dessine le flocon de Koch.
|
|
||||||
|
|
||||||
> **Indice** : Le flocon est formé de 3 courbes de Koch, avec un angle de 120° entre chaque courbe.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Triangle de Pascal
|
|
||||||
|
|
||||||
Le triangle de Pascal représente les coefficients binomiaux sous la forme d'un triangle :
|
|
||||||
|
|
||||||
```
|
|
||||||
1
|
|
||||||
1 1
|
|
||||||
1 2 1
|
|
||||||
1 3 3 1
|
|
||||||
1 4 6 4 1
|
|
||||||
1 5 10 10 5 1
|
|
||||||
```
|
|
||||||
|
|
||||||
La fonction `coef(n, p)` permet de calculer le coefficient à la ligne `n` et colonne `p` :
|
|
||||||
|
|
||||||
$$
|
|
||||||
coef(n, p) = \begin{cases}
|
|
||||||
1 & \text{si } p = 0 \text{ ou } n = p\\
|
|
||||||
coef(n-1, p-1) + coef(n-1, p) & \text{sinon}
|
|
||||||
\end{cases}
|
|
||||||
$$
|
|
||||||
|
|
||||||
### Questions
|
|
||||||
|
|
||||||
1. Écrire le code de la fonction récursive `coef(n, p)`.
|
|
||||||
|
|
||||||
Le sommet du triangle est le résultat de `coef(0, 0)`, la première ligne est représentée par `coef(1, 0)` et `coef(1, 1)`, ainsi de suite pour les autres lignes.
|
|
||||||
|
|
||||||
2. À l'aide de deux boucles, écrire un code permettant d'afficher les 6 premières lignes du triangle.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Recherche dichotomique
|
|
||||||
|
|
||||||
La recherche dichotomique fonctionne sur un tableau trié et permet de trouver un élément de façon optimale en O(log n).
|
|
||||||
|
|
||||||
Voici le code de la recherche dichotomique (programme de 1ère) de manière itérative :
|
|
||||||
|
|
||||||
```python
|
|
||||||
def recherche_dichotomique(t, v):
|
|
||||||
debut = 0
|
|
||||||
fin = len(t) - 1
|
|
||||||
while debut <= fin:
|
|
||||||
milieu = (debut + fin) // 2
|
|
||||||
if t[milieu] == v:
|
|
||||||
return True
|
|
||||||
elif t[milieu] > v:
|
|
||||||
fin = milieu - 1
|
|
||||||
else:
|
|
||||||
debut = milieu + 1
|
|
||||||
return False
|
|
||||||
```
|
|
||||||
|
|
||||||
### Question
|
|
||||||
|
|
||||||
1. Réécrire ce code en version récursive. La fonction prendra en paramètres le tableau `t`, la valeur cherchée `v`, ainsi que les indices `debut` et `fin`.
|
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
" if g == d:\n",
|
" if g == d:\n",
|
||||||
" return ...\n",
|
" return ...\n",
|
||||||
" else:\n",
|
" else:\n",
|
||||||
" nombre_de_triplets = (d – g) // ...\n",
|
" nombre_de_triplets = (d - g) // ...\n",
|
||||||
" indice = g + 3 * (nombre_de_triplets // 2)\n",
|
" indice = g + 3 * (nombre_de_triplets // 2)\n",
|
||||||
" if ... :\n",
|
" if ... :\n",
|
||||||
" return ...\n",
|
" return ...\n",
|
||||||
|
|||||||
@@ -110,9 +110,9 @@ L'algorithme de Dijkstra trouve le plus court chemin depuis une source vers tous
|
|||||||
1. Initialiser toutes les distances à l'infini, sauf la source à 0
|
1. Initialiser toutes les distances à l'infini, sauf la source à 0
|
||||||
2. Marquer tous les sommets comme non visités
|
2. Marquer tous les sommets comme non visités
|
||||||
3. Tant qu'il reste des sommets non visités :
|
3. Tant qu'il reste des sommets non visités :
|
||||||
- Sélectionner le sommet non visité avec la plus petite distance
|
- Sélectionner le sommet non visité avec la plus petite distance
|
||||||
- Pour chaque voisin, mettre à jour la distance si on trouve un chemin plus court
|
- Pour chaque voisin, mettre à jour la distance si on trouve un chemin plus court
|
||||||
- Marquer le sommet comme visité
|
- Marquer le sommet comme visité
|
||||||
|
|
||||||
### 2.2. Implémentation
|
### 2.2. Implémentation
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -63,53 +63,53 @@ Si vous n'êtes pas à l'aise avec le chiffre magique, une autre solution existe
|
|||||||
|
|
||||||
1. **Convertir l'adresse IP et le masque de sous-réseau en binaire** :
|
1. **Convertir l'adresse IP et le masque de sous-réseau en binaire** :
|
||||||
|
|
||||||
- Par exemple, pour l'adresse IP
|
- Par exemple, pour l'adresse IP
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
192.168.1.42
|
192.168.1.42
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
et le masque
|
et le masque
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
255.255.255.192
|
255.255.255.192
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- IP en binaire : `11000000.10101000.00000001.00101010`
|
- IP en binaire : `11000000.10101000.00000001.00101010`
|
||||||
- Masque en binaire : `11111111.11111111.11111111.11000000`
|
- Masque en binaire : `11111111.11111111.11111111.11000000`
|
||||||
|
|
||||||
2. **Effectuer une opération ET (AND) bit à bit** :
|
2. **Effectuer une opération ET (AND) bit à bit** :
|
||||||
|
|
||||||
- Multiplier chaque bit de l'adresse IP par le bit correspondant du masque.
|
- Multiplier chaque bit de l'adresse IP par le bit correspondant du masque.
|
||||||
- Cela revient à conserver les bits de l'adresse IP là où le masque a des `1`, et à mettre des `0` ailleurs.
|
- Cela revient à conserver les bits de l'adresse IP là où le masque a des `1`, et à mettre des `0` ailleurs.
|
||||||
|
|
||||||
3. **Convertir le résultat en décimal** :
|
3. **Convertir le résultat en décimal** :
|
||||||
|
|
||||||
- Le résultat de l'opération ET donne l'adresse réseau en binaire.
|
- Le résultat de l'opération ET donne l'adresse réseau en binaire.
|
||||||
- Convertir cette adresse binaire en décimal pour obtenir l'adresse réseau.
|
- Convertir cette adresse binaire en décimal pour obtenir l'adresse réseau.
|
||||||
|
|
||||||
**Pour trouver l'adresse de broadcast, la méthode est légèrement différente de celle utilisée pour trouver l'adresse réseau** :
|
**Pour trouver l'adresse de broadcast, la méthode est légèrement différente de celle utilisée pour trouver l'adresse réseau** :
|
||||||
|
|
||||||
### Méthode de calcul de l'adresse de broadcast en binaire
|
### Méthode de calcul de l'adresse de broadcast en binaire
|
||||||
|
|
||||||
1. **Convertir l'adresse IP et le masque de sous-réseau en binaire** :
|
1. **Convertir l'adresse IP et le masque de sous-réseau en binaire** :
|
||||||
- Comme précédemment, convertissez l'adresse IP et le masque en binaire.
|
- Comme précédemment, convertissez l'adresse IP et le masque en binaire.
|
||||||
2. **Inverser le masque de sous-réseau** :
|
2. **Inverser le masque de sous-réseau** :
|
||||||
- Changez tous les `1` en `0` et tous les `0` en `1` pour obtenir le masque de sous-réseau inversé.
|
- Changez tous les `1` en `0` et tous les `0` en `1` pour obtenir le masque de sous-réseau inversé.
|
||||||
3. **Effectuer une opération OU (OR) bit à bit** :
|
3. **Effectuer une opération OU (OR) bit à bit** :
|
||||||
- Ajoutez chaque bit de l'adresse IP au bit correspondant du masque inversé.
|
- Ajoutez chaque bit de l'adresse IP au bit correspondant du masque inversé.
|
||||||
- Cela revient à conserver les bits de l'adresse IP là où le masque inversé a des `0`, et à mettre des `1` ailleurs.
|
- Cela revient à conserver les bits de l'adresse IP là où le masque inversé a des `0`, et à mettre des `1` ailleurs.
|
||||||
4. **Convertir le résultat en décimal** :
|
4. **Convertir le résultat en décimal** :
|
||||||
- Le résultat de l'opération OU donne l'adresse de broadcast en binaire.
|
- Le résultat de l'opération OU donne l'adresse de broadcast en binaire.
|
||||||
- Convertir cette adresse binaire en décimal pour obtenir l'adresse de broadcast.
|
- Convertir cette adresse binaire en décimal pour obtenir l'adresse de broadcast.
|
||||||
|
|
||||||
### Exemple
|
### Exemple
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -139,17 +139,17 @@ Les réseaux sont la base d'Internet et des systèmes informatiques modernes. Co
|
|||||||
|
|
||||||
### Exercice d'application
|
### Exercice d'application
|
||||||
1. Trouvez votre adresse IP locale avec la commande :
|
1. Trouvez votre adresse IP locale avec la commande :
|
||||||
```sh
|
```sh
|
||||||
ipconfig (Windows) ou ifconfig / ip a (Linux/Mac)
|
ipconfig (Windows) ou ifconfig / ip a (Linux/Mac)
|
||||||
```
|
```
|
||||||
2. Testez une requête DNS avec :
|
2. Testez une requête DNS avec :
|
||||||
```sh
|
```sh
|
||||||
nslookup www.example.com
|
nslookup www.example.com
|
||||||
```
|
```
|
||||||
3. Comparez TCP et UDP en expliquant quel protocole vous utiliseriez pour :
|
3. Comparez TCP et UDP en expliquant quel protocole vous utiliseriez pour :
|
||||||
- Envoyer un e-mail
|
- Envoyer un e-mail
|
||||||
- Jouer en ligne
|
- Jouer en ligne
|
||||||
- Regarder une vidéo en streaming
|
- Regarder une vidéo en streaming
|
||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -433,27 +433,27 @@ SELECT DISTINCT genre FROM LIVRES WHERE genre NOT IN (SELECT genre FROM LIVRES W
|
|||||||
## Exercice 11 : QCM
|
## Exercice 11 : QCM
|
||||||
|
|
||||||
1. **Quelle clause permet de filtrer les résultats d'un GROUP BY ?**
|
1. **Quelle clause permet de filtrer les résultats d'un GROUP BY ?**
|
||||||
- **Réponse : c) HAVING**
|
- **Réponse : c) HAVING**
|
||||||
|
|
||||||
2. **Quelle est la différence entre WHERE et HAVING ?**
|
2. **Quelle est la différence entre WHERE et HAVING ?**
|
||||||
- **Réponse : b) WHERE filtre avant GROUP BY, HAVING filtre après**
|
- **Réponse : b) WHERE filtre avant GROUP BY, HAVING filtre après**
|
||||||
|
|
||||||
Explication : WHERE filtre les lignes individuelles avant le regroupement. HAVING filtre les groupes après le regroupement et permet d'utiliser des fonctions d'agrégation.
|
Explication : WHERE filtre les lignes individuelles avant le regroupement. HAVING filtre les groupes après le regroupement et permet d'utiliser des fonctions d'agrégation.
|
||||||
|
|
||||||
3. **Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?**
|
3. **Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?**
|
||||||
- **Réponse : c) 0**
|
- **Réponse : c) 0**
|
||||||
|
|
||||||
Explication : La condition `1=0` est toujours fausse, donc aucune ligne n'est sélectionnée. COUNT(*) sur un ensemble vide retourne 0 (pas NULL, pas d'erreur).
|
Explication : La condition `1=0` est toujours fausse, donc aucune ligne n'est sélectionnée. COUNT(*) sur un ensemble vide retourne 0 (pas NULL, pas d'erreur).
|
||||||
|
|
||||||
4. **Quel type de jointure retourne tous les enregistrements de la table de gauche ?**
|
4. **Quel type de jointure retourne tous les enregistrements de la table de gauche ?**
|
||||||
- **Réponse : b) LEFT JOIN**
|
- **Réponse : b) LEFT JOIN**
|
||||||
|
|
||||||
Explication : LEFT JOIN retourne toutes les lignes de la table de gauche, même si elles n'ont pas de correspondance dans la table de droite (avec NULL pour les colonnes de droite).
|
Explication : LEFT JOIN retourne toutes les lignes de la table de gauche, même si elles n'ont pas de correspondance dans la table de droite (avec NULL pour les colonnes de droite).
|
||||||
|
|
||||||
5. **Quelle fonction d'agrégation ignore les valeurs NULL ?**
|
5. **Quelle fonction d'agrégation ignore les valeurs NULL ?**
|
||||||
- **Réponse : b) COUNT(colonne)**
|
- **Réponse : b) COUNT(colonne)**
|
||||||
|
|
||||||
Explication : `COUNT(*)` compte toutes les lignes, y compris celles avec des NULL. `COUNT(colonne)` ne compte que les valeurs non NULL de cette colonne.
|
Explication : `COUNT(*)` compte toutes les lignes, y compris celles avec des NULL. `COUNT(colonne)` ne compte que les valeurs non NULL de cette colonne.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+51
-51
@@ -175,19 +175,19 @@ Pour tous les exercices, on considère la base de données d'une médiathèque c
|
|||||||
## Exercice 8 : INSERT, UPDATE, DELETE
|
## Exercice 8 : INSERT, UPDATE, DELETE
|
||||||
|
|
||||||
1. Écrire une requête pour ajouter l'auteur suivant :
|
1. Écrire une requête pour ajouter l'auteur suivant :
|
||||||
- id : 9
|
- id : 9
|
||||||
- nom : "Le Guin"
|
- nom : "Le Guin"
|
||||||
- prénom : "Ursula K."
|
- prénom : "Ursula K."
|
||||||
- nationalité : "américain"
|
- nationalité : "américain"
|
||||||
- année de naissance : 1929
|
- année de naissance : 1929
|
||||||
|
|
||||||
2. Écrire une requête pour ajouter le livre suivant :
|
2. Écrire une requête pour ajouter le livre suivant :
|
||||||
- id : 13
|
- id : 13
|
||||||
- titre : "La Main gauche de la nuit"
|
- titre : "La Main gauche de la nuit"
|
||||||
- id_auteur : 9
|
- id_auteur : 9
|
||||||
- année de publication : 1969
|
- année de publication : 1969
|
||||||
- genre : "SF"
|
- genre : "SF"
|
||||||
- nombre de pages : 304
|
- nombre de pages : 304
|
||||||
|
|
||||||
3. Écrire une requête pour changer le genre de "Dune" en "SF".
|
3. Écrire une requête pour changer le genre de "Dune" en "SF".
|
||||||
|
|
||||||
@@ -200,17 +200,17 @@ Pour tous les exercices, on considère la base de données d'une médiathèque c
|
|||||||
## Exercice 9 : Création de tables
|
## Exercice 9 : Création de tables
|
||||||
|
|
||||||
1. Écrire la requête SQL pour créer la table EMPRUNTS avec :
|
1. Écrire la requête SQL pour créer la table EMPRUNTS avec :
|
||||||
- id (entier, clé primaire)
|
- id (entier, clé primaire)
|
||||||
- id_livre (entier, clé étrangère vers LIVRES)
|
- id_livre (entier, clé étrangère vers LIVRES)
|
||||||
- id_adherent (entier)
|
- id_adherent (entier)
|
||||||
- date_emprunt (date)
|
- date_emprunt (date)
|
||||||
- date_retour (date, peut être NULL)
|
- date_retour (date, peut être NULL)
|
||||||
|
|
||||||
2. Écrire la requête SQL pour créer une table EDITEURS avec :
|
2. Écrire la requête SQL pour créer une table EDITEURS avec :
|
||||||
- id (entier, clé primaire)
|
- id (entier, clé primaire)
|
||||||
- nom (texte)
|
- nom (texte)
|
||||||
- pays (texte)
|
- pays (texte)
|
||||||
- ann_creation (entier)
|
- ann_creation (entier)
|
||||||
|
|
||||||
3. Comment modifier la table LIVRES pour ajouter une colonne id_editeur qui référence la table EDITEURS ?
|
3. Comment modifier la table LIVRES pour ajouter une colonne id_editeur qui référence la table EDITEURS ?
|
||||||
|
|
||||||
@@ -221,54 +221,54 @@ Pour tous les exercices, on considère la base de données d'une médiathèque c
|
|||||||
Pour chaque requête suivante, décrire en français ce qu'elle retourne :
|
Pour chaque requête suivante, décrire en français ce qu'elle retourne :
|
||||||
|
|
||||||
1. ```sql
|
1. ```sql
|
||||||
SELECT titre FROM LIVRES WHERE ann_publi = (SELECT MIN(ann_publi) FROM LIVRES);
|
SELECT titre FROM LIVRES WHERE ann_publi = (SELECT MIN(ann_publi) FROM LIVRES);
|
||||||
```
|
```
|
||||||
|
|
||||||
2. ```sql
|
2. ```sql
|
||||||
SELECT A.nom, COUNT(*)
|
SELECT A.nom, COUNT(*)
|
||||||
FROM AUTEURS A
|
FROM AUTEURS A
|
||||||
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
INNER JOIN LIVRES L ON A.id = L.id_auteur
|
||||||
GROUP BY A.id
|
GROUP BY A.id
|
||||||
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) as cnt FROM LIVRES GROUP BY id_auteur));
|
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) as cnt FROM LIVRES GROUP BY id_auteur));
|
||||||
```
|
```
|
||||||
|
|
||||||
3. ```sql
|
3. ```sql
|
||||||
SELECT DISTINCT genre FROM LIVRES WHERE genre NOT IN (SELECT genre FROM LIVRES WHERE ann_publi < 1950);
|
SELECT DISTINCT genre FROM LIVRES WHERE genre NOT IN (SELECT genre FROM LIVRES WHERE ann_publi < 1950);
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Exercice 11 : QCM
|
## Exercice 11 : QCM
|
||||||
|
|
||||||
1. Quelle clause permet de filtrer les résultats d'un GROUP BY ?
|
1. Quelle clause permet de filtrer les résultats d'un GROUP BY ?
|
||||||
- [ ] a) WHERE
|
- [ ] a) WHERE
|
||||||
- [ ] b) FILTER
|
- [ ] b) FILTER
|
||||||
- [ ] c) HAVING
|
- [ ] c) HAVING
|
||||||
- [ ] d) GROUP FILTER
|
- [ ] d) GROUP FILTER
|
||||||
|
|
||||||
2. Quelle est la différence entre WHERE et HAVING ?
|
2. Quelle est la différence entre WHERE et HAVING ?
|
||||||
- [ ] a) Aucune, ils sont équivalents
|
- [ ] a) Aucune, ils sont équivalents
|
||||||
- [ ] b) WHERE filtre avant GROUP BY, HAVING filtre après
|
- [ ] b) WHERE filtre avant GROUP BY, HAVING filtre après
|
||||||
- [ ] c) HAVING filtre avant GROUP BY, WHERE filtre après
|
- [ ] c) HAVING filtre avant GROUP BY, WHERE filtre après
|
||||||
- [ ] d) WHERE ne fonctionne qu'avec les nombres
|
- [ ] d) WHERE ne fonctionne qu'avec les nombres
|
||||||
|
|
||||||
3. Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?
|
3. Que retourne `SELECT COUNT(*) FROM LIVRES WHERE 1=0;` ?
|
||||||
- [ ] a) Une erreur
|
- [ ] a) Une erreur
|
||||||
- [ ] b) NULL
|
- [ ] b) NULL
|
||||||
- [ ] c) 0
|
- [ ] c) 0
|
||||||
- [ ] d) Rien
|
- [ ] d) Rien
|
||||||
|
|
||||||
4. Quel type de jointure retourne tous les enregistrements de la table de gauche ?
|
4. Quel type de jointure retourne tous les enregistrements de la table de gauche ?
|
||||||
- [ ] a) INNER JOIN
|
- [ ] a) INNER JOIN
|
||||||
- [ ] b) LEFT JOIN
|
- [ ] b) LEFT JOIN
|
||||||
- [ ] c) RIGHT JOIN
|
- [ ] c) RIGHT JOIN
|
||||||
- [ ] d) CROSS JOIN
|
- [ ] d) CROSS JOIN
|
||||||
|
|
||||||
5. Quelle fonction d'agrégation ignore les valeurs NULL ?
|
5. Quelle fonction d'agrégation ignore les valeurs NULL ?
|
||||||
- [ ] a) COUNT(*)
|
- [ ] a) COUNT(*)
|
||||||
- [ ] b) COUNT(colonne)
|
- [ ] b) COUNT(colonne)
|
||||||
- [ ] c) Les deux
|
- [ ] c) Les deux
|
||||||
- [ ] d) Aucune
|
- [ ] d) Aucune
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+75
-75
@@ -12,123 +12,123 @@ Ce TP vous guidera à travers la création et la manipulation d'une base de donn
|
|||||||
|
|
||||||
1. **Lancer DB Browser for SQLite**. Vous devriez obtenir l'écran suivant :
|
1. **Lancer DB Browser for SQLite**. Vous devriez obtenir l'écran suivant :
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. **Créer une nouvelle base de données** :
|
2. **Créer une nouvelle base de données** :
|
||||||
|
|
||||||
- Cliquez sur "Nouvelle base de données".
|
- Cliquez sur "Nouvelle base de données".
|
||||||
- Nommez votre base de données, par exemple `db_livres.db`.
|
- Nommez votre base de données, par exemple `db_livres.db`.
|
||||||
- Vous verrez la fenêtre suivante :
|
- Vous verrez la fenêtre suivante :
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- Cliquez sur "Annuler" pour fermer cette fenêtre.
|
- Cliquez sur "Annuler" pour fermer cette fenêtre.
|
||||||
|
|
||||||
3. **Vérifier la création de la base de données** :
|
3. **Vérifier la création de la base de données** :
|
||||||
- Votre base de données est créée mais ne contient pas encore de tables.
|
- Votre base de données est créée mais ne contient pas encore de tables.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Activité 3.2 : Création d'une table
|
## Activité 3.2 : Création d'une table
|
||||||
|
|
||||||
1. **Accéder à l'onglet "Exécuter le SQL"** :
|
1. **Accéder à l'onglet "Exécuter le SQL"** :
|
||||||
|
|
||||||
- Cliquez sur l'onglet "Exécuter le SQL".
|
- Cliquez sur l'onglet "Exécuter le SQL".
|
||||||
|
|
||||||
2. **Créer la table `LIVRES`** :
|
2. **Créer la table `LIVRES`** :
|
||||||
- Dans la fenêtre "SQL 1", saisissez la requête suivante :
|
- Dans la fenêtre "SQL 1", saisissez la requête suivante :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE LIVRES (
|
CREATE TABLE LIVRES (
|
||||||
id INT PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
titre TEXT,
|
titre TEXT,
|
||||||
auteur TEXT,
|
auteur TEXT,
|
||||||
ann_publi INT,
|
ann_publi INT,
|
||||||
note INT
|
note INT
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
- Cliquez sur le bouton ▶ (ou appuyez sur F5) pour exécuter la requête.
|
- Cliquez sur le bouton ▶ (ou appuyez sur F5) pour exécuter la requête.
|
||||||
- Un message "Requête exécutée avec succès" devrait apparaître.
|
- Un message "Requête exécutée avec succès" devrait apparaître.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Activité 3.3 : Insertion de données
|
## Activité 3.3 : Insertion de données
|
||||||
|
|
||||||
1. **Insérer des enregistrements dans la table `LIVRES`** :
|
1. **Insérer des enregistrements dans la table `LIVRES`** :
|
||||||
|
|
||||||
- Toujours dans l'onglet "Exécuter le SQL", saisissez la requête suivante :
|
- Toujours dans l'onglet "Exécuter le SQL", saisissez la requête suivante :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
INSERT INTO LIVRES (id, titre, auteur, ann_publi, note) VALUES
|
INSERT INTO LIVRES (id, titre, auteur, ann_publi, note) VALUES
|
||||||
(1, '1984', 'Orwell', 1949, 10),
|
(1, '1984', 'Orwell', 1949, 10),
|
||||||
(2, 'Dune', 'Herbert', 1965, 8),
|
(2, 'Dune', 'Herbert', 1965, 8),
|
||||||
(3, 'Fondation', 'Asimov', 1951, 9),
|
(3, 'Fondation', 'Asimov', 1951, 9),
|
||||||
(4, 'Le meilleur des mondes', 'Huxley', 1931, 7),
|
(4, 'Le meilleur des mondes', 'Huxley', 1931, 7),
|
||||||
(5, 'Fahrenheit 451', 'Bradbury', 1953, 7),
|
(5, 'Fahrenheit 451', 'Bradbury', 1953, 7),
|
||||||
(6, 'Ubik', 'K.Dick', 1969, 9),
|
(6, 'Ubik', 'K.Dick', 1969, 9),
|
||||||
(7, 'Chroniques martiennes', 'Bradbury', 1950, 8),
|
(7, 'Chroniques martiennes', 'Bradbury', 1950, 8),
|
||||||
(8, 'La nuit des temps', 'Barjavel', 1968, 7),
|
(8, 'La nuit des temps', 'Barjavel', 1968, 7),
|
||||||
(9, 'Blade Runner', 'K.Dick', 1968, 8),
|
(9, 'Blade Runner', 'K.Dick', 1968, 8),
|
||||||
(10, 'Les Robots', 'Asimov', 1950, 9),
|
(10, 'Les Robots', 'Asimov', 1950, 9),
|
||||||
(11, 'La Planète des singes', 'Boulle', 1963, 8),
|
(11, 'La Planète des singes', 'Boulle', 1963, 8),
|
||||||
(12, 'Ravage', 'Barjavel', 1943, 8),
|
(12, 'Ravage', 'Barjavel', 1943, 8),
|
||||||
(13, 'Le Maître du Haut Château', 'K.Dick', 1962, 8),
|
(13, 'Le Maître du Haut Château', 'K.Dick', 1962, 8),
|
||||||
(14, 'Le monde des Ā', 'Van Vogt', 1945, 7),
|
(14, 'Le monde des Ā', 'Van Vogt', 1945, 7),
|
||||||
(15, 'La Fin de l’éternité', 'Asimov', 1955, 8),
|
(15, 'La Fin de l’éternité', 'Asimov', 1955, 8),
|
||||||
(16, 'De la Terre à la Lune', 'Verne', 1865, 10);
|
(16, 'De la Terre à la Lune', 'Verne', 1865, 10);
|
||||||
```
|
```
|
||||||
|
|
||||||
- Exécutez la requête en cliquant sur le bouton ▶ ou en appuyant sur F5.
|
- Exécutez la requête en cliquant sur le bouton ▶ ou en appuyant sur F5.
|
||||||
- Un message de confirmation devrait apparaître.
|
- Un message de confirmation devrait apparaître.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. **Vérifier les données insérées** :
|
2. **Vérifier les données insérées** :
|
||||||
- Cliquez sur l'onglet "Parcourir les données" pour voir les enregistrements ajoutés.
|
- Cliquez sur l'onglet "Parcourir les données" pour voir les enregistrements ajoutés.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Activité 3.4 : Exécution de requêtes SQL
|
## Activité 3.4 : Exécution de requêtes SQL
|
||||||
|
|
||||||
1. **Sélectionner tous les enregistrements** :
|
1. **Sélectionner tous les enregistrements** :
|
||||||
- Dans l'onglet "Exécuter le SQL", saisissez la requête suivante :
|
- Dans l'onglet "Exécuter le SQL", saisissez la requête suivante :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT id, titre, auteur, ann_publi, note FROM LIVRES;
|
SELECT id, titre, auteur, ann_publi, note FROM LIVRES;
|
||||||
```
|
```
|
||||||
|
|
||||||
- Exécutez la requête. Vous devriez obtenir tous les enregistrements de la table `LIVRES`.
|
- Exécutez la requête. Vous devriez obtenir tous les enregistrements de la table `LIVRES`.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. **Sélectionner des colonnes spécifiques** :
|
2. **Sélectionner des colonnes spécifiques** :
|
||||||
- Pour obtenir uniquement les titres et auteurs des livres, utilisez la requête :
|
- Pour obtenir uniquement les titres et auteurs des livres, utilisez la requête :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT titre, auteur FROM LIVRES;
|
SELECT titre, auteur FROM LIVRES;
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Filtrer les enregistrements** :
|
3. **Filtrer les enregistrements** :
|
||||||
- Pour obtenir les livres écrits par Asimov, utilisez :
|
- Pour obtenir les livres écrits par Asimov, utilisez :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT titre, ann_publi FROM LIVRES WHERE auteur = 'Asimov';
|
SELECT titre, ann_publi FROM LIVRES WHERE auteur = 'Asimov';
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Combiner des conditions** :
|
4. **Combiner des conditions** :
|
||||||
- Pour obtenir les livres d'Asimov publiés après 1953 :
|
- Pour obtenir les livres d'Asimov publiés après 1953 :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT titre, ann_publi FROM LIVRES WHERE auteur = 'Asimov' AND ann_publi > 1953;
|
SELECT titre, ann_publi FROM LIVRES WHERE auteur = 'Asimov' AND ann_publi > 1953;
|
||||||
```
|
```
|
||||||
|
|
||||||
5. **Trier les résultats** :
|
5. **Trier les résultats** :
|
||||||
- Pour trier les livres de K.Dick du plus ancien au plus récent :
|
- Pour trier les livres de K.Dick du plus ancien au plus récent :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT titre FROM LIVRES WHERE auteur = 'K.Dick' ORDER BY ann_publi;
|
SELECT titre FROM LIVRES WHERE auteur = 'K.Dick' ORDER BY ann_publi;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -136,13 +136,13 @@ Ce TP vous guidera à travers la création et la manipulation d'une base de donn
|
|||||||
|
|
||||||
7. Saisissez et testez la requête SQL suivante :
|
7. Saisissez et testez la requête SQL suivante :
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
SELECT titre, ann_publi
|
SELECT titre, ann_publi
|
||||||
FROM LIVRES
|
FROM LIVRES
|
||||||
WHERE auteur='Asimov' AND ann_publi>1953
|
WHERE auteur='Asimov' AND ann_publi>1953
|
||||||
```
|
```
|
||||||
|
|
||||||
Vérifiez que vous obtenez bien les livres écrits par Asimov publiés après 1953.
|
Vérifiez que vous obtenez bien les livres écrits par Asimov publiés après 1953.
|
||||||
|
|
||||||
8. Écrivez une requête permettant d'obtenir les titres des livres publiés après 1945 qui ont une note supérieure ou égale à 9.
|
8. Écrivez une requête permettant d'obtenir les titres des livres publiés après 1945 qui ont une note supérieure ou égale à 9.
|
||||||
|
|
||||||
|
|||||||
+38
-38
@@ -7,42 +7,42 @@
|
|||||||
1. **Réponse : b)** Le nombre de transistors double environ tous les deux ans (à coût constant)
|
1. **Réponse : b)** Le nombre de transistors double environ tous les deux ans (à coût constant)
|
||||||
|
|
||||||
2. **Réponse : d)** Toutes les réponses ci-dessus
|
2. **Réponse : d)** Toutes les réponses ci-dessus
|
||||||
- Les transistors approchent de la taille atomique
|
- Les transistors approchent de la taille atomique
|
||||||
- L'effet tunnel quantique perturbe le fonctionnement
|
- L'effet tunnel quantique perturbe le fonctionnement
|
||||||
- La chaleur dégagée devient difficile à évacuer
|
- La chaleur dégagée devient difficile à évacuer
|
||||||
|
|
||||||
3. **Réponse : b)** Multiplier le nombre de cœurs
|
3. **Réponse : b)** Multiplier le nombre de cœurs
|
||||||
- L'augmentation de la fréquence génère trop de chaleur
|
- L'augmentation de la fréquence génère trop de chaleur
|
||||||
- La multiplication des cœurs permet d'augmenter la puissance totale sans augmenter la fréquence unitaire
|
- La multiplication des cœurs permet d'augmenter la puissance totale sans augmenter la fréquence unitaire
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Exercice 2 : Composants d'un SoC
|
## Exercice 2 : Composants d'un SoC
|
||||||
|
|
||||||
1. **Composants intégrables dans un SoC :**
|
1. **Composants intégrables dans un SoC :**
|
||||||
- ✅ CPU
|
- ✅ CPU
|
||||||
- ✅ GPU
|
- ✅ GPU
|
||||||
- ❌ Disque dur mécanique
|
- ❌ Disque dur mécanique
|
||||||
- ✅ Contrôleur Wi-Fi
|
- ✅ Contrôleur Wi-Fi
|
||||||
- ✅ Mémoire cache
|
- ✅ Mémoire cache
|
||||||
- ✅ NPU (Neural Processing Unit)
|
- ✅ NPU (Neural Processing Unit)
|
||||||
- ❌ Écran
|
- ❌ Écran
|
||||||
- ✅ Contrôleur USB
|
- ✅ Contrôleur USB
|
||||||
|
|
||||||
2. **Pourquoi un disque dur mécanique ne peut pas être intégré :**
|
2. **Pourquoi un disque dur mécanique ne peut pas être intégré :**
|
||||||
- Un disque dur mécanique contient des pièces mobiles (plateaux rotatifs, têtes de lecture)
|
- Un disque dur mécanique contient des pièces mobiles (plateaux rotatifs, têtes de lecture)
|
||||||
- Ces composants mécaniques ne peuvent pas être miniaturisés à l'échelle d'une puce
|
- Ces composants mécaniques ne peuvent pas être miniaturisés à l'échelle d'une puce
|
||||||
- La technologie est fondamentalement différente (mécanique vs électronique)
|
- La technologie est fondamentalement différente (mécanique vs électronique)
|
||||||
- Les SSD (mémoire flash) peuvent en revanche être intégrés car ils sont purement électroniques
|
- Les SSD (mémoire flash) peuvent en revanche être intégrés car ils sont purement électroniques
|
||||||
|
|
||||||
3. **Avantages et inconvénients :**
|
3. **Avantages et inconvénients :**
|
||||||
|
|
||||||
| Avantages | Inconvénients |
|
| Avantages | Inconvénients |
|
||||||
|-----------|---------------|
|
|-----------|---------------|
|
||||||
| Compacité : tout tient sur une puce | Non évolutif : impossible de remplacer un composant |
|
| Compacité : tout tient sur une puce | Non évolutif : impossible de remplacer un composant |
|
||||||
| Consommation réduite : moins de distance entre composants | Obsolescence : tout le système vieillit ensemble |
|
| Consommation réduite : moins de distance entre composants | Obsolescence : tout le système vieillit ensemble |
|
||||||
| Performance : communication ultra-rapide | Réparation difficile : panne = remplacement total |
|
| Performance : communication ultra-rapide | Réparation difficile : panne = remplacement total |
|
||||||
| Coût de production réduit en masse | Impact environnemental : recyclage complexe |
|
| Coût de production réduit en masse | Impact environnemental : recyclage complexe |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -50,30 +50,30 @@
|
|||||||
|
|
||||||
1. **Facteur multiplicatif entre Intel 4004 et Apple M1 :**
|
1. **Facteur multiplicatif entre Intel 4004 et Apple M1 :**
|
||||||
|
|
||||||
```
|
```
|
||||||
Facteur = 16 000 000 000 / 2 300
|
Facteur = 16 000 000 000 / 2 300
|
||||||
Facteur = 6 956 521,7
|
Facteur = 6 956 521,7
|
||||||
Facteur ≈ 7 millions
|
Facteur ≈ 7 millions
|
||||||
```
|
```
|
||||||
|
|
||||||
Le nombre de transistors a été multiplié par environ **7 millions** en 49 ans.
|
Le nombre de transistors a été multiplié par environ **7 millions** en 49 ans.
|
||||||
|
|
||||||
2. **Calcul théorique selon la loi de Moore :**
|
2. **Calcul théorique selon la loi de Moore :**
|
||||||
|
|
||||||
Entre 1971 et 2020, il y a 49 ans, soit 49/2 = 24,5 doublements.
|
Entre 1971 et 2020, il y a 49 ans, soit 49/2 = 24,5 doublements.
|
||||||
|
|
||||||
```
|
```
|
||||||
Transistors théoriques = 2 300 × 2^24,5
|
Transistors théoriques = 2 300 × 2^24,5
|
||||||
Transistors théoriques = 2 300 × 23 726 566
|
Transistors théoriques = 2 300 × 23 726 566
|
||||||
Transistors théoriques ≈ 54,6 milliards
|
Transistors théoriques ≈ 54,6 milliards
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Comparaison :**
|
3. **Comparaison :**
|
||||||
|
|
||||||
- Valeur théorique : ~54,6 milliards de transistors
|
- Valeur théorique : ~54,6 milliards de transistors
|
||||||
- Valeur réelle (Apple M1) : 16 milliards de transistors
|
- Valeur réelle (Apple M1) : 16 milliards de transistors
|
||||||
|
|
||||||
L'Apple M1 a **moins** de transistors que prévu par la loi de Moore pure. Cependant, la loi de Moore a été globalement respectée jusqu'aux années 2010, puis le rythme a légèrement ralenti. De plus, l'Apple M3 (2023) atteint 37 milliards, montrant que la progression continue.
|
L'Apple M1 a **moins** de transistors que prévu par la loi de Moore pure. Cependant, la loi de Moore a été globalement respectée jusqu'aux années 2010, puis le rythme a légèrement ralenti. De plus, l'Apple M3 (2023) atteint 37 milliards, montrant que la progression continue.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+22
-22
@@ -5,22 +5,22 @@
|
|||||||
## Exercice 1 : Loi de Moore (QCM)
|
## Exercice 1 : Loi de Moore (QCM)
|
||||||
|
|
||||||
1. La loi de Moore prédit que :
|
1. La loi de Moore prédit que :
|
||||||
- [ ] a) La vitesse des processeurs double tous les ans
|
- [ ] a) La vitesse des processeurs double tous les ans
|
||||||
- [ ] b) Le nombre de transistors double environ tous les deux ans (à coût constant)
|
- [ ] b) Le nombre de transistors double environ tous les deux ans (à coût constant)
|
||||||
- [ ] c) La consommation électrique diminue de moitié tous les ans
|
- [ ] c) La consommation électrique diminue de moitié tous les ans
|
||||||
- [ ] d) Le prix des processeurs double tous les deux ans
|
- [ ] d) Le prix des processeurs double tous les deux ans
|
||||||
|
|
||||||
2. Pourquoi la loi de Moore atteint-elle ses limites physiques ?
|
2. Pourquoi la loi de Moore atteint-elle ses limites physiques ?
|
||||||
- [ ] a) Les transistors ne peuvent pas être plus petits qu'un atome
|
- [ ] a) Les transistors ne peuvent pas être plus petits qu'un atome
|
||||||
- [ ] b) Les effets quantiques perturbent le fonctionnement sous 5 nm
|
- [ ] b) Les effets quantiques perturbent le fonctionnement sous 5 nm
|
||||||
- [ ] c) La dissipation thermique devient ingérable
|
- [ ] c) La dissipation thermique devient ingérable
|
||||||
- [ ] d) Toutes les réponses ci-dessus
|
- [ ] d) Toutes les réponses ci-dessus
|
||||||
|
|
||||||
3. Quelle stratégie les fabricants utilisent-ils pour contourner ces limites ?
|
3. Quelle stratégie les fabricants utilisent-ils pour contourner ces limites ?
|
||||||
- [ ] a) Augmenter la fréquence indéfiniment
|
- [ ] a) Augmenter la fréquence indéfiniment
|
||||||
- [ ] b) Multiplier le nombre de cœurs
|
- [ ] b) Multiplier le nombre de cœurs
|
||||||
- [ ] c) Utiliser des matériaux radioactifs
|
- [ ] c) Utiliser des matériaux radioactifs
|
||||||
- [ ] d) Réduire la taille de la RAM
|
- [ ] d) Réduire la taille de la RAM
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -29,14 +29,14 @@
|
|||||||
Un SoC moderne comme l'Apple M3 contient plusieurs composants.
|
Un SoC moderne comme l'Apple M3 contient plusieurs composants.
|
||||||
|
|
||||||
1. Parmi les éléments suivants, lesquels peuvent être intégrés dans un SoC ? (Plusieurs réponses possibles)
|
1. Parmi les éléments suivants, lesquels peuvent être intégrés dans un SoC ? (Plusieurs réponses possibles)
|
||||||
- [ ] CPU
|
- [ ] CPU
|
||||||
- [ ] GPU
|
- [ ] GPU
|
||||||
- [ ] Disque dur mécanique
|
- [ ] Disque dur mécanique
|
||||||
- [ ] Contrôleur Wi-Fi
|
- [ ] Contrôleur Wi-Fi
|
||||||
- [ ] Mémoire cache
|
- [ ] Mémoire cache
|
||||||
- [ ] NPU (Neural Processing Unit)
|
- [ ] NPU (Neural Processing Unit)
|
||||||
- [ ] Écran
|
- [ ] Écran
|
||||||
- [ ] Contrôleur USB
|
- [ ] Contrôleur USB
|
||||||
|
|
||||||
2. Expliquer pourquoi un disque dur mécanique ne peut pas être intégré dans un SoC.
|
2. Expliquer pourquoi un disque dur mécanique ne peut pas être intégré dans un SoC.
|
||||||
|
|
||||||
@@ -141,8 +141,8 @@ RISC-V est une architecture de processeur open source.
|
|||||||
## Exercice 9 : Conversion et calculs
|
## Exercice 9 : Conversion et calculs
|
||||||
|
|
||||||
1. Un processeur utilise une gravure de 3 nm. Convertir cette valeur en :
|
1. Un processeur utilise une gravure de 3 nm. Convertir cette valeur en :
|
||||||
- Micromètres (µm)
|
- Micromètres (µm)
|
||||||
- Mètres
|
- Mètres
|
||||||
|
|
||||||
2. Sachant qu'un atome de silicium mesure environ 0,2 nm de diamètre, combien d'atomes de silicium peuvent théoriquement tenir sur une largeur de 3 nm ?
|
2. Sachant qu'un atome de silicium mesure environ 0,2 nm de diamètre, combien d'atomes de silicium peuvent théoriquement tenir sur une largeur de 3 nm ?
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ Le but du TD est de manipuler des piles et des files sans avoir d'implémentatio
|
|||||||

|

|
||||||
|
|
||||||
1. Quel sera l'état de la pile après l'utilisation des méthodes suivantes :
|
1. Quel sera l'état de la pile après l'utilisation des méthodes suivantes :
|
||||||
- Depile(), Depile(), Empile(7), Empile(8),Depile()
|
- Depile(), Depile(), Empile(7), Empile(8),Depile()
|
||||||
- Que renvoie la méthode top() ?
|
- Que renvoie la méthode top() ?
|
||||||
2. Reprenons la pile de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
|
2. Reprenons la pile de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
|
||||||
3. En partant de 0, écrire les méthodes permettant de créer une pile contenant les numéros dans cet ordre : 19982018. (1 est en bas de pile)
|
3. En partant de 0, écrire les méthodes permettant de créer une pile contenant les numéros dans cet ordre : 19982018. (1 est en bas de pile)
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ Le but du TD est de manipuler des piles et des files sans avoir d'implémentatio
|
|||||||

|

|
||||||
|
|
||||||
1. Quel sera l'état de la file après l'utilisation des méthodes suivantes :
|
1. Quel sera l'état de la file après l'utilisation des méthodes suivantes :
|
||||||
- Defile(), Defile(), Enfile(7), Enfile(8),Defile()
|
- Defile(), Defile(), Enfile(7), Enfile(8),Defile()
|
||||||
- Que renvoie la méthode top() ?
|
- Que renvoie la méthode top() ?
|
||||||
2. Reprenons la file de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
|
2. Reprenons la file de l'image, que faut-il faire comme méthode pour que Est_vide() soit vrai ?
|
||||||
3. En partant de 0, écrire les méthodes permettant de créer une file contenant les numéros dans cet ordre : 19982018. (1 est en tête de file)
|
3. En partant de 0, écrire les méthodes permettant de créer une file contenant les numéros dans cet ordre : 19982018. (1 est en tête de file)
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ Pour cette implémentation, le constructeur de la classe utilisera un tableau po
|
|||||||
|
|
||||||
1. Créez cette classe File contenant les méthodes suivantes :
|
1. Créez cette classe File contenant les méthodes suivantes :
|
||||||
|
|
||||||
* **enfile( )**
|
* **enfile( )**
|
||||||
|
|
||||||
* **defile( )**
|
* **defile( )**
|
||||||
|
|
||||||
* **top( )**
|
* **top( )**
|
||||||
|
|
||||||
* **est_vide( )**
|
* **est_vide( )**
|
||||||
|
|
||||||
* **taille( )**
|
* **taille( )**
|
||||||
|
|
||||||
## 2. File à taille fixe :
|
## 2. File à taille fixe :
|
||||||
|
|
||||||
@@ -30,11 +30,11 @@ Supposons que notre file à une taille fixe, disons 7 éléments maximum.
|
|||||||
Ici nous allons implémenter la file de manière récursive. Elle possèdera deux attributs, le premier sera un élément de la file nommé tête, le second sera une autre File. Cette seconde file possèdera elle aura un élément et une autre file en attribut. Ainsi de suite.
|
Ici nous allons implémenter la file de manière récursive. Elle possèdera deux attributs, le premier sera un élément de la file nommé tête, le second sera une autre File. Cette seconde file possèdera elle aura un élément et une autre file en attribut. Ainsi de suite.
|
||||||
|
|
||||||
1. Programmez cette classe nommée File2 avec les méthodes suivantes
|
1. Programmez cette classe nommée File2 avec les méthodes suivantes
|
||||||
* **enfile( )**
|
* **enfile( )**
|
||||||
* **defile( )**
|
* **defile( )**
|
||||||
* **top( )**
|
* **top( )**
|
||||||
* **est_vide( )**
|
* **est_vide( )**
|
||||||
* **taille( )**
|
* **taille( )**
|
||||||
|
|
||||||
## 4. Implémentation d'un jeu de bataille :
|
## 4. Implémentation d'un jeu de bataille :
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ Un fichier carte.py contient la classe carte et les fonctions suivantes :
|
|||||||
|
|
||||||
1. Pour ce travail vous allez devoir compléter les fonctions :
|
1. Pour ce travail vous allez devoir compléter les fonctions :
|
||||||
|
|
||||||
- tour
|
- tour
|
||||||
|
|
||||||
- bataille
|
- bataille
|
||||||
|
|
||||||
- jeu_fini
|
- jeu_fini
|
||||||
|
|
||||||
Ces fonctions se trouvent dans un fichier nommé carte_eleve.py
|
Ces fonctions se trouvent dans un fichier nommé carte_eleve.py
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user