{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e0cc881a-e8c1-4ccd-8a30-728286f8f4ca",
   "metadata": {},
   "source": [
    "# ICS - Série 6\n",
    "15.10.25\n",
    "\n",
    "Cette série comporte trois parties. La première porte sur les classes, la deuxième contient quelques exercices pour vos révisions, et la troisième, optionnelle, vous donne l'occasion d'implémenter quelques petits jeux.\n",
    "\n",
    "# I - Classes\n",
    "\n",
    "# Exercice 1 : qu'affiche ce code\n",
    "\n",
    "Dans la première cellule ci-dessous, vous trouverez les classes `Livre` et `Biblio` vues en cours. Qu'affiche le code suivant?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a49937f0-b403-4c82-8aab-b0492d0ab0b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class Livre:\n",
    "    def __init__(self, titre, auteur, pages):\n",
    "        self.titre = titre \n",
    "        self.pages = pages\n",
    "        self.auteur = auteur\n",
    "        self.progression = 0\n",
    "        \n",
    "    def __str__(self):\n",
    "        pourcentage = str(int(self.progression * 100))\n",
    "        s = self.titre\n",
    "        s += ' par ' + self.auteur\n",
    "        s += ', ' + str(self.pages) + ' pages'\n",
    "        s += ', lu à ' + pourcentage + '%.'\n",
    "        return s\n",
    "    \n",
    "    def lire(self, nb_pages):\n",
    "        debut = self.progression * self.pages\n",
    "        self.progression = min((debut + nb_pages) / self.pages, 1)\n",
    "\n",
    "class Biblio:\n",
    "    def __init__(self, L, propriétaire):\n",
    "        self.contenu = [livre for livre in L if type(livre) == Livre]\n",
    "        self.propriétaire = propriétaire\n",
    "    \n",
    "    def livre_par_auteur(self, auteur):\n",
    "        return [livre for livre in self.contenu if livre.auteur == auteur]\n",
    "    \n",
    "    def grouper_par_auteur(self):\n",
    "        d = {}\n",
    "        for livre in self.contenu:\n",
    "            if livre.auteur in d:\n",
    "                d[livre.auteur].append(livre)\n",
    "            else:\n",
    "                d[livre.auteur] = [livre]\n",
    "        return d\n",
    "    \n",
    "    def acheter_livre(self, livre):\n",
    "        self.contenu.append(livre)\n",
    "    \n",
    "    def prêter_livre(self, livre):\n",
    "        self.contenu.remove(livre)\n",
    "        \n",
    "    def __str__(self):\n",
    "        return 'Voici la bibliothèque de ' + self.propriétaire + '. Elle contient ' + str(len(self.contenu)) + ' livres.'\n",
    "    \n",
    "    def afficher_livres(self):\n",
    "        for livre in self.contenu:\n",
    "            print(livre)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8001ea7a-e8c0-4fef-ae7e-e48facbed314",
   "metadata": {},
   "outputs": [],
   "source": [
    "eco1 = Livre(\"Le nom de la rose\", \"Eco\", 300)\n",
    "eco2 = Livre(\"Le nom de la rose\", \"Eco\", 300)\n",
    "eco1.lire(100)\n",
    "print(eco1)\n",
    "print(eco2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0c01c6e6-804b-41b1-b85f-746eea3597b4",
   "metadata": {},
   "outputs": [],
   "source": [
    "eco3 = Livre(\"Le pendule de Foucault\", \"Eco\", 500)\n",
    "flau1 = Livre(\"Madame Bovary\", \"Flaubert\", 400)\n",
    "flau2 = Livre(\"L'éducation sentimentale\", \"Flaubert\", 300)\n",
    "g_et_p = Livre(\"Guerre et Paix\", \"Tolstoi\", 1200)\n",
    "\n",
    "g_et_p.lire(600)\n",
    "\n",
    "ma_biblio = Biblio([eco1, eco2, eco3, flau1, flau2, g_et_p], \"moi\")\n",
    "print(ma_biblio)\n",
    "ma_biblio.afficher_livres()\n",
    "print()\n",
    "\n",
    "fl = ma_biblio.grouper_par_auteur()[\"Flaubert\"]\n",
    "print(\"Voici les livres de Flaubert:\")\n",
    "for x in fl:\n",
    "    print(x)\n",
    "\n",
    "print()\n",
    "print(\"J'ai\", len(ma_biblio.grouper_par_auteur()[\"Eco\"]), \"livres de Umberto Eco.\")\n",
    "print()\n",
    "\n",
    "ma_biblio.prêter_livre(eco2)\n",
    "ma_biblio.acheter_livre(Livre(\"Les Trois Mousquetaires\", \"Dumas\", 500))\n",
    "ma_biblio.afficher_livres()\n",
    "\n",
    "print()\n",
    "print(\"Ma dernière acquisition:\", ma_biblio.contenu[len(ma_biblio.contenu)-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6aba42c3-55ab-46fe-bae8-ea32dea0f4b1",
   "metadata": {},
   "source": [
    "\n",
    "# Exercice 2 : Classes\n",
    "\n",
    "Voici ci-dessous la classe `Etudiant` vue en cours. Nous avons rajouté la définition d'une classe `Cours`, ainsi que plusieurs définitions de méthodes des classes `Etudiant` et `Cours` dont vous devrez compléter le corps.\n",
    "\n",
    "**Attributs des classes:**\n",
    "\n",
    "Attributs de la classe `Etudiant`:\n",
    "- `mes_cours` est une liste d'objets de type `Cours` (les cours que prend l'étudiant)\n",
    "- `mes_notes` est un dictionnaire dont les clés seront les ID des cours pris par l'étudiant, et les valeurs sont les listes des notes obtenues dans ces cours.\n",
    "\n",
    "Attributs de la classe `Cours`:\n",
    "- `nom`: nom du cours, par exemple `\"ICS\"`\n",
    "- `id`: code unique identifiant le cours, par exemple `\"PREPA-025\"`\n",
    "- `coeff`: le coefficient du cours \n",
    "- `student_list`: liste d'objets de type `Etudiant` (les étudiants qui prennent ce cours).\n",
    "\n",
    "\n",
    "**Méthodes à implémenter:**\n",
    "\n",
    "Méthodes de la classe `Etudiant`:\n",
    "- `__str__` retourne le nom de l'étudiant.\n",
    "- `enrol(self, cours)` inscrit l'étudiant dans le cours `cours`: elle rajoute `cours` à l'attribut `mes_cours` de l'étudiant, et rajoute l'étudiant à l'attribut `student_list` du cours.\n",
    "- `take_exam(self, cours)` génère une note aléatoire obtenue par l'étudiant dans le cours `cours`. Elle ajoute cette note à la liste des notes associées à `cours.id` dans le dictionnaire `mes_notes` de l'étudiant.\n",
    "- `moyenne_cours(self, cours)` retourne la moyenne obtenue par l'étudiant dans le cours `cours`, si une telle moyenne existe, sinon `None`.\n",
    "- `moyenne(self)` retourne la moyenne générale de l'étudiant, pondérée par les coefficients des cours, si une telle moyenne existe, sinon `None`.\n",
    "- `print_classes(self)` affiche la liste des cours où l'étudiant est inscrit avec la moyenne qu'il a obtenue à chaque cours.\n",
    "\n",
    "Méthode de la classe `Cours`:\n",
    "- `__str__` retourne le nom du cours.\n",
    "- `print_student_list(self)` affiche la liste des étudiants inscrits dans le cours avec la moyenne de chacun\n",
    "- `moyenne(self)` retourne la moyenne du cours (sur tous les étudiants inscrits), si une telle moyenne existe, sinon `None`.\n",
    "\n",
    "Testez bien **chacune** de vos méthodes de classe. La cellule suivante contient quelques tests, mais vous pouvez en faire d'autres."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "466398ce-a55a-4007-a432-0e6fa632c9cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Etudiant:\n",
    "    def __init__(self, n, a):\n",
    "        self.nom = n\n",
    "        self.age = a\n",
    "        self.mes_cours = []\n",
    "        self.mes_notes = {}\n",
    "     \n",
    "    def se_presenter(self):\n",
    "        print('Je suis', self.nom)\n",
    "\n",
    "    def avoir_anniversaire(self):\n",
    "        self.age += 1\n",
    "\n",
    "    def __str__(self):\n",
    "        pass\n",
    "\n",
    "    def enrol(self, cours):\n",
    "        pass\n",
    "\n",
    "    def take_exam(self, cours):\n",
    "        pass\n",
    "\n",
    "    def moyenne_cours(self, cours):\n",
    "        pass\n",
    "\n",
    "    def moyenne(self):\n",
    "        pass\n",
    "            \n",
    "    def print_classes(self):\n",
    "        pass\n",
    "\n",
    "class Cours:\n",
    "    def __init__(self, nom, code, coefficient):\n",
    "        self.nom = nom\n",
    "        self.id = code\n",
    "        self.coeff = coefficient\n",
    "        self.student_list = []\n",
    "\n",
    "    def __str__(self):\n",
    "        pass\n",
    "\n",
    "    def print_student_list(self):\n",
    "        pass\n",
    "        \n",
    "    def moyenne(self):\n",
    "        pass\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64509b2b-0097-440e-9122-d820c31423e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TESTS\n",
    "\n",
    "'''\n",
    "alg_lin = Cours(\"Algèbre Linéaire\", \"PREPA-013\", 4)\n",
    "physique = Cours(\"Physique\", \"PREPA-015\", 6)\n",
    "an1 = Cours(\"Analyse 1\", \"PREPA-010\", 6)\n",
    "\n",
    "\n",
    "sam = Etudiant(\"Dubuis\", 22)\n",
    "hercule = Etudiant(\"Poirot\", 20)\n",
    "\n",
    "sam.enrol(alg_lin)\n",
    "sam.enrol(physique)\n",
    "sam.enrol(an1)\n",
    "hercule.enrol(alg_lin)\n",
    "hercule.enrol(physique)\n",
    "\n",
    "print(sam)\n",
    "sam.print_classes()\n",
    "print()\n",
    "\n",
    "for cours in sam.mes_cours:\n",
    "    sam.take_exam(cours)\n",
    "    sam.take_exam(cours)\n",
    "\n",
    "for cours in hercule.mes_cours:\n",
    "    hercule.take_exam(cours)\n",
    "    hercule.take_exam(cours)\n",
    "\n",
    "print(hercule)\n",
    "hercule.print_classes()\n",
    "print()\n",
    "\n",
    "print(sam, sam.mes_notes, sam.moyenne())\n",
    "print(hercule, hercule.mes_notes, hercule.moyenne())\n",
    "\n",
    "print()\n",
    "alg_lin.print_student_list()\n",
    "print(alg_lin.moyenne())\n",
    "\n",
    "\n",
    "print()\n",
    "an1.print_student_list()\n",
    "print(an1.moyenne())\n",
    "\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb4dd329-1808-49a0-8ada-7f88cc0d0fdd",
   "metadata": {},
   "source": [
    "# Exercice 3 : Vecteurs\n",
    "\n",
    "Nous avons vu au cours 5 de Géométrie Analytique que si on travaille dans un repère orthonormé, il existe des formules simples pour calculer la norme d'un vecteur, le produit scalaire de deux vecteurs et l'angle orienté entre deux vecteurs en fonction des coordonnées des vecteurs. Complétez le corps des fonctions et des méthodes de la classe `Vecteur` données ci-dessous.\n",
    "\n",
    "Les attributs d'un vecteur sont ses coordonnées `x` et `y` (dans le repère orthonormé où on travaille).\n",
    "\n",
    "Méthodes de classe à compléter:\n",
    "- `__str__(self)` affiche les coordonnées du vecteur (par exemple dans le format `(x, y)`)\n",
    "- `norme(self)` retourne la norme du vecteur\n",
    "- `multiple_scalaire(self, alpha)` où `alpha` est un réel, retourne la multiplication scalaire `alpha` fois le vecteur\n",
    "- `angle(self, autre_vec)` retourne le cosinus et le sinus de l'angle orienté du vecteur `self` au vecteur `autre_vec`\n",
    "- `projeté(self, autre_vec)` retourne le vecteur projeté orthogonal de `autre_vec` sur `self`\n",
    "\n",
    "Fonctions à compléter:\n",
    "- `somme(u, v)` retourne le vecteur correspondant à la somme `u + v`\n",
    "- `comb_lin(u, v, alpha, beta)` retourne la combinaison linéaire `alpha u + beta v`\n",
    "- `produit_scalaire(u, v)`retourne le produit scalaire de deux vecteurs `u` et `v`\n",
    "- `determinant(u, v)` retourne le déterminant de deux vecteurs `u` et `v`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "1adaeaaa-c0c0-43a9-940b-1687530ec1a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Vecteur:\n",
    "    def __init__(self, x_coord, y_coord):\n",
    "        self.x = x_coord\n",
    "        self.y = y_coord\n",
    "        \n",
    "    def __str__(self):\n",
    "        pass\n",
    "        \n",
    "    def norme(self):\n",
    "        pass\n",
    "\n",
    "    def multiple_scalaire(self, alpha):\n",
    "        pass\n",
    "     \n",
    "    def angle(self, autre_vec):\n",
    "        pass\n",
    "\n",
    "    def projeté(self, autre_vec): # projeté de autre_vec sur self\n",
    "        pass\n",
    "\n",
    "def somme(u, v):\n",
    "    pass\n",
    "\n",
    "def comb_lin(u, v, alpha, beta):\n",
    "    pass\n",
    "    \n",
    "def produit_scalaire(u, v):\n",
    "    pass\n",
    "\n",
    "def determinant(u, v):\n",
    "    pass \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9186d37-180e-4737-aaab-af4162999110",
   "metadata": {},
   "source": [
    "# II - Révision\n",
    "\n",
    "## Exercice 4 : des boucles\n",
    "\n",
    "Etant donné une liste `L = ['a', 'b', 'c', 'd']`, \n",
    "\n",
    "**(a)** écrivez une boucle qui produit l'affichage\n",
    "\n",
    "`0    a`\n",
    "\n",
    "`1    b`\n",
    "\n",
    "`2    c`\n",
    "\n",
    "`3    d`\n",
    "\n",
    "**(b)** écrivez une boucle qui produit l'affichage\n",
    "\n",
    "`a`\n",
    "\n",
    "`bb`\n",
    "\n",
    "`ccc`\n",
    "\n",
    "`dddd`\n",
    "\n",
    "**(c)** écrivez des boucles imbriquées qui produisent l'affichage\n",
    "\n",
    "`aa ab ac ad`\n",
    "\n",
    "`ba bb bc bd`\n",
    "\n",
    "`ca cb cc cd`\n",
    "\n",
    "`da db dc dd`\n",
    "\n",
    "**(d)** écrivez des boucles imbriquées qui produisent l'affichage\n",
    "\n",
    "`aa`\n",
    "\n",
    "`ba bb`\n",
    "\n",
    "`ca cb cc` \n",
    "\n",
    "`da db dc dd`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "02954214-a7b9-495d-882b-e550f8445cbf",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "52e3fdc3-83a4-4066-bbd8-d5be40fd938d",
   "metadata": {},
   "source": [
    "## Exercice 5: encore des boucles \n",
    "\n",
    "**(a)** Ecrivez une fonction `affichage_entiers` qui prend en entrée deux entiers positifs `d` et `N` et affiche les entiers de `1` jusqu'à `N`, avec `d` entiers par ligne (sauf peut-être la dernière ligne). Par exemple `affichage_entiers(5, 18)` doit afficher\n",
    "\n",
    "`1\t 2\t 3\t 4\t 5`\t\n",
    "\n",
    "`6\t 7\t 8\t 9\t 10`  \n",
    "\n",
    "`11    12\t13\t14\t 15`\t\n",
    "\n",
    "`16\t17\t18`\n",
    "\t\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "af429d14-1208-4161-8741-0c2bdad2d661",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "5604c903-434d-4e3a-b997-bd49a531f9d6",
   "metadata": {},
   "source": [
    "**(b)** Ecrivez une fonction `IloveICS` qui prend en entrée une chaîne de caractère `s` et retourne la chaîne de caractères qui contient les caractères que `s`, avec la chaîne `ICS` intercalée entre chaque deux caractères. Par exemple, l'appel `IloveICS('banane')` doit afficher \n",
    "`bICSaICSnICSaICSnICSeICS` ."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2d01b31c-77d4-4eca-8a63-db2ff4e7cd2d",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "247d2932-1ae5-47fe-84fa-2aff868c5ebf",
   "metadata": {},
   "source": [
    "**(c)** Ecrivez une fonction `lettres_et_mots` qui prend en entrée un tuple `t` de mots (chaînes de caractères) et une chaîne de caractères `s`, et pour chaque lettre de `s` affiche les mots dans lesquels elle apparaît (l'ordre n'importe pas). Par exemple, `lettres_et_mots((\"sable\", \"trois\", \"banane\"), \"abs\")` doit afficher\n",
    "\n",
    "`la lettre a apparaît dans le mot sable` \n",
    "\n",
    "`la lettre b apparaît dans le mot sable` \n",
    "\n",
    "`la lettre s apparaît dans le mot sable` \n",
    "\n",
    "`la lettre s apparaît dans le mot trois` \n",
    "\n",
    "`la lettre a apparaît dans le mot banane` \n",
    "\n",
    "`la lettre b apparaît dans le mot banane` \n",
    "\n",
    "mais elle peut aussi afficher\n",
    "\n",
    "`la lettre a apparaît dans le mot sable`\n",
    "\n",
    "`la lettre a apparaît dans le mot banane`\n",
    "\n",
    "`la lettre b apparaît dans le mot sable`\n",
    "\n",
    "`la lettre b apparaît dans le mot banane`\n",
    "\n",
    "`la lettre s apparaît dans le mot sable`\n",
    "\n",
    "`la lettre s apparaît dans le mot trois`\n",
    "\n",
    "Après avoir écrit la fonction: qu'est-ce qui fait qu'on obtient un affichage plutôt que l'autre?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0ebe529a-81a4-4080-97a6-c9e6eced7d6a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "0a74c705-d9e9-4b79-a87a-4d914cf766cf",
   "metadata": {},
   "source": [
    "**(d)** Modifiez la fonction pour créer une fonction `lettres_et_mots_compte` qui affiche le **nombre** de fois où chaque lettre apparaît dans chaque mot. Par exemple, l'appel `lettres_et_mots_compte((\"sable\", \"trois\", \"banane\"), \"abs\")` doit afficher\n",
    "\n",
    "`la lettre a apparaît 1 fois dans le mot sable`\n",
    "\n",
    "`la lettre b apparaît 1 fois dans le mot sable`\n",
    "\n",
    "`la lettre s apparaît 1 fois dans le mot sable`\n",
    "\n",
    "`la lettre s apparaît 1 fois dans le mot trois`\n",
    "\n",
    "`la lettre a apparaît 2 fois dans le mot banane`\n",
    "\n",
    "`la lettre b apparaît 1 fois dans le mot banane`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7ca20d64-456a-4530-affe-a45aac994302",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "c969c839-d256-487d-bfde-88a455eb63df",
   "metadata": {},
   "source": [
    "## Exercice 6 : listes et matrices\n",
    "\n",
    "**(a)** Ecrivez une fonction `matrix_extract_col` qui prend en entrée une liste de listes `L` représentant une matrice, et un indice `k`, et retourne une liste `col` contenant les éléments de la `k`-ème colonne de `L`.\n",
    "\n",
    "Par exemple, les instructions \n",
    "\n",
    "`L = [['a', 'b', 'c'], ['d', 'e', 'f']]`\n",
    "\n",
    "`print(matrix_extract_col(L, 1))`\n",
    "\n",
    "doivent afficher \n",
    "\n",
    "`['b', 'e']`\n",
    "\n",
    "Il n'y a pas besoin de vérifier que `L` correspond à une matrice bien définie: on peut supposer que `L`contient `m` éléments (correspondant aux `m` lignes de la matrice) qui sont toutes des listes de même taille `n` (correspondant aux `n` colonnes de la matrice).\n",
    "\n",
    "**(b)** Etant donné une matrice $M$ à $m$ lignes et $n$ colonnes, sa **transposée** est la matrice à $n$ lignes et $m$ colonnes dont les lignes sont les colonnes de $M$  et les colonnes sont les lignes de $M$. Par exemple, la transposée de \n",
    "$\\begin{matrix}\n",
    "a&b&c\\\\\n",
    "d&e&f\\\\\n",
    "\\end{matrix}$ \n",
    "est \n",
    "$\\begin{matrix}\n",
    "a & d \\\\\n",
    "b & e \\\\\n",
    "c&f \\\\\n",
    "\\end{matrix}$.\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "Ecrivez une fonction `matrix_transpose` qui prend en entrée une liste de listes `L` représentant une matrice, et retourne la matrice transposée de `L`. Par exemple, les instructions\n",
    "\n",
    "`L = [['a', 'b', 'c'], ['d', 'e', 'f']]`\n",
    "\n",
    "`print(matrix_transpose(L))`\n",
    "\n",
    "doivent afficher\n",
    "\n",
    "`[['a', 'd'], ['b', 'e'], ['c', 'f']]`\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9e6e34e6-bfd2-4a13-9974-9a2e248c9f76",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "e75faf7d-c287-447d-b5cc-7655e17d7039",
   "metadata": {},
   "source": [
    "# Exercice 7 : fusion de dictionnaires\n",
    "\n",
    "**(a)** Ecrivez une fonction `dict_merge` qui prend en entrée deux dictionnaires `d1` et `d2` et retourne un dictionnaire fusionné `d` qui contient tous les éléments de `d1` et `d2`. Si une clé apparaît dans les deux dictionnaires, gardez dans `d` la valeur qui lui est associée dans `d2`.\n",
    "\n",
    "Par exemple, `dict_merge({'a':123, 'b':456}, {'b':123, 'c':456})` doit retourner le dictionnaire `{'a': 123, 'b': 123, 'c': 456}`.\n",
    "\n",
    "**Remarque** Cette fonction simule l'opération `d = d1 | d2` en Python.\n",
    "\n",
    "**(b)** Même question mais au lieu de produire un nouveau dictionnaire `d`, la fonction doit mettre à jour le dictionnaire `d1` avec les éléments de `d2`. Elle ne retourne rien. Par exemple, les instructions\n",
    "\n",
    "`d1 = {'a':123, 'b':456}`\n",
    "\n",
    "`d2 = {'b':123, 'c':456}`\n",
    "\n",
    "`dict_update(d1, d2)`\n",
    "\n",
    "`print(d1)`\n",
    "\n",
    "doivent afficher\n",
    "\n",
    "`{'a': 123, 'b': 123, 'c': 456}`\n",
    "\n",
    "**Remarque** Cette fonction simule l'opération `d1.update(d2)` en Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d07d02e7-ff06-41cd-af49-21eb15247e14",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "a5d434e3-9fe9-421b-b671-4f1b18f06fb2",
   "metadata": {},
   "source": [
    "# III - Pour le plaisir...\n",
    "\n",
    "## Exercice 8 : jeu des pierres\n",
    "\n",
    "Il y a `n` pierres et deux joueurs. Chaque joueur peut à son tour enlever une ou deux pierres. Celui qui enlève la dernière pierre gagne.\n",
    "\n",
    "Implémentez le jeu des pierres via une classe ou fonction maître de jeu qui gère le tour, l'appel aux joueurs, la visualisation de l'état du jeu, et la détection d'un gagnant.\n",
    "\n",
    "Implémentez plusieurs stratégies de joueurs. Quelques stratégies possibles:\n",
    "- un joueur qui retire systématiquement une pierre\n",
    "- un joueur qui retire systématiquement deux pierres\n",
    "- un joueur qui retire aléatoirement une ou deux pierre \n",
    "- un joueur humain (utilisez la fonction `input` pour récupérer une chaîne de caractères de l'entrée standard)\n",
    "- un joueur optimal: quelle est sa stratégie?\n",
    "\n",
    "Un joueur optimal gagne toujours, s'il y a moyen de gagner. Pour comprendre sa stratégie, imaginez un jeu entre deux joueurs optimaux et raisonnez sur `n`: comment joue chacun des joueurs, et qui gagne, si `n` vaut 1, 2, 3, 4,... ?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a0815a99-dd61-4982-a498-9479df130b04",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "ad4f6cfc",
   "metadata": {},
   "source": [
    "## Exercice 9 : Connect-N\n",
    "\n",
    "**Objectif :** Créer une nouvelle classe `ConnectN` qui réutilise les classes `Board` et `Player` existantes pour implémenter un jeu de type \"Puissance 4\".\n",
    "\n",
    "**Règles du jeu :**\n",
    "Connect-N (ou Puissance-N) se joue sur une grille rectangulaire (traditionnellement 6 lignes × 7 colonnes). Les règles sont :\n",
    "\n",
    "- Les joueurs jouent à tour de rôle en choisissant une case (remarquez que comme on joue dans une grille verticale soumise à la gravité, pas toutes les cases sont jouables!)\n",
    "- Le premier joueur à aligner N pions consécutifs (horizontalement, verticalement ou en diagonale) gagne.\n",
    "- Si la grille est pleine sans gagnant, c'est un match nul.\n",
    "\n",
    "**Implémentation :**\n",
    "- La classe `ConnectN` devrait prendre 4 arguments, `row`, `col` et `N`. Le jeu doit alors être joué sur une grille `row`×`col` avec `N` pions alignés pour gagner.\n",
    "- La classe `Board` et `Player` vues en cours peuvent être réutilisées/étendues (elles sont disponibles sur Moodle).\n",
    "\n",
    "**Stratégie :**\n",
    "Au minimum, implémentez une stratégie de joueur aléatoire pour faire tourner le code. Dans un deuxième temps, essayez d'implémenter des stratégies plus intelligentes!\n",
    "\n",
    "\n",
    "Paramètres par défaut pour un jeu classique de Puissance 4 : grille 6×7 avec N=4.\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d5193eec",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "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.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
