Le 20 juin 2022, nous sommes trois étudiants à devoir s'embarquer pour deux semaines d'apprentissage et de pratique intensive : Lisa Georges, Jamila Kamal et Kelvin Odier.
Nous avons deux semaines avec pour objectif de réaliser un jeu vidéo en langage C sur le thème de l'apprentissage par renforcement pour le 1er juillet 2022.
Durant la première semaine, nous avons réalisé une série d'exercices afin de maîtriser l'utilisation de la librairie SDL2 servant d'interface graphique, ainsi que les chaînes de Markov.
Dans la deuxième semaine, nous avons réalisé le jeu avec une intelligence artificielle.
Lundi, le 20/06/2022 :
Mardi, le 21/06/2022 :
Mercredi, le 22/06/2022 :
Jeudi, le 23/06/2022 :
Vendredi, le 24/06/2022 :
Samedi, le 25/06/2022 :
Lundi, le 27/06/2022 :
Mardi, le 28/06/2022 :
Mercredi, le 29/06/2022 :
Jeudi, le 30/06/2022 :
Vendredi, le 01/07/2022 :
En premier lieu, nous avons appris à manipuler des fenêtres.
Les animations ci-dessous montrent notre capacité du premier jour à ouvrir, fermer et déplacer différentes fenêtres.
Ensuite, nous avons étudié les différentes fonctionnalités de tracés graphiques proposées par SDL2.
Ici, nous avons un "serpent" (ligne) multicolore qui rebondit sur les bords.
Ici, nous avons un autre "serpent" (ruban) qui s'enroule autour de lui-même.
Une ligne multicolorée qui serpente dans une trajectoire elliptique pour rejoindre sa queue
Afin de mettre en pratique les dessins sur fenêtre, nous avons réalisé un jeu de la vie.
L'utilisateur choisit la configuration de base avec les clics de souris sur les cases.
En fonctionalités de plus, il est possible de sauvegarder une configuration et de la charger en indiquant
le fichier de sauvegarde en ligne de commande.
Flèche droite | Augmenter les FPS |
Flèche gauche | Diminuer les FPS |
Touche S | Sauvegarder la configuration |
Touche M | Passer de mode délimité à mode torique |
Enfin, pour terminer la série d'exercices individuels, nous avons vu comment charger et manipuler des images afin de réaliser quelques animations de sprite
Ici, nous avons un homme qui marche devant un pot de fleur
Ici, nous avons un sablier au milieu d'un désert
Et enfin, petite promenade nocturne de la part d'une maître de l'eau et une course d'un monsieur à son encontre.
Un développeur évite que des erreurs de code lui tombent dessus en effectuant des rotations sur son fauteuil roulant pour se déplacer à droite ou à gauche.
Si l'humain devant le jeu n'a pas réagit à temps pour l'aider dans sa tâche, le développeur se voit diminuer le nombre de coeurs de vie.
Sachant qu'il n'a que trois coeurs de vie, heurter son cerveau à un des ennemis de sa vie de développeur a comme conséquence :
À chaque "cycle", on a une probabilité de générer ou non des ennemis sur la première ligne de la matrice. Le cycle est également associé à un niveau de difficulté qui a pour paramètres la probabilité d'avoir des ennemis, la proportion du type de ces ennemis (forts ou faibles) et le nombre de ces ennemis sur chaque ligne.
Les variations dans le niveau de difficulté sont gérées par une chaîne de Markov.
  | Niveau 0 | Niveau 1 | Niveau 2 | Niveau 3 | Niveau 4 |
---|---|---|---|---|---|
Niveau 0 | 0.9 | 0.1 | 0 | 0 | 0 |
Niveau 1 | 0.1 | 0.8 | 0.1 | 0 | 0 |
Niveau 2 | 0 | 0.1 | 0.8 | 0.1 | 0 |
Niveau 3 | 0 | 0 | 0.1 | 0.8 | 0.1 |
Niveau 4 | 0 | 0 | 0 | 0.1 | 0.9 |
Cela permet au joueur de ne pas expérimenter la difficulté la plus élevée sans être passé par les niveaux intermédiaires tout en maintenant une variété des lignes d'ennemis pendant toute la partie.
La planche des sprites du jeu ci-dessous ainsi que le décors a entièrement été réalisée par Kelvin.
On affiche un score au joueur qui s'inscrémente régulièrement jusqu'au game over.
Le joueur possède trois vies qui sont représentées par trois coeurs rouges. Lorsqu'il perd une vie, le coeur est remplacé par un coeur noir.
Lors du game over, le fauteuil continue de tourner indéfiniment et le jeu affiche un message "Game Over".
Un aventurier évite de croiser un ennemi lors de sa traversée du labyrinthe.
Cet ennemi n'est pas un simple objet, il a bel et bien subit un long traitement pour dévélopper son cerveau artificiel.
Il peut se déplacer sans heurter quoique ce soit et sait reconnaître l'aventurier de jour comme de nuit ;-).
Mais n'oublions pas que c'est un humain qui est devant le jeu et que c'est grâce à lui que l'aventurier peut se déplacer dans le labyrinthe.
Nous verrons si l'humain peut battre l'ennemi ou si notre intelligente créature arrive à (toujours) gagner.
Ainsi, pour résumer :
Nous avons implémenté un simple Q-learning et un double Q-learning pour entraîner la créature à aller vers l'aventurier.
Tout en cherchant le chemin le plus court vers l'aventurier, la créature doit aussi respecter les bords du labyrinthe.
La table G est la table de passage entre les différentes positions du labyrinthe.
G | Haut | Bas | Droite | Gauche |
---|---|---|---|---|
0 | -1 | 12 | 1 | -1 |
1 | -1 | -1 | 2 | 0 |
2 | -1 | -1 | 3 | 1 |
La table Q définit la qualité des actions à partir d'un état. Son maximum indique quelle action l'ennemi doit réaliser afin d'atteindre le joueur le plus rapidement possible.
Q | Haut | Bas | Droite | Gauche |
---|---|---|---|---|
état(position joueur, position ennemi) |
Enfin, on définit les récompenses dans la table R. La valeur est de 100 quand l'action permet à l'ennemi d'arriver à la position du joueur, 0 sinon.
Afin de juger la qualité de l'apprentissage, on affiche le nombre de pas effectué par l'ordinateur à chaque run, c'est à dire le nombre de déplacement pour atteindre un joueur fixe sur le labyrinthe. En premier lieu, voici le graphe de l'évolution du nombre de pas d'un run au cours de l'apprentissage pour un joueur à la position 0 dans le labyrinthe 8x8.
Simple Q-Learning | Double Q-Learning |
Dans le labyrinthe 12x12, la simple évolution du nombre de pas rend la convergence moins visible car "parasitée". Ainsi il a été décider d'afficher l'évolution de la moyenne du nombre de pas au cours d'un run. Ici on voit une différence de la convergence entre les deux méthodes.
Simple Q-Learning | Double Q-Learning |
La planche des sprites du jeu ainsi que le décors a entièrement été réalisée par Kelvin Odier.
Le jeu peut se jouer de deux manières :
Le jeu a deux labyrinthes prédéfinis (8 x 8 et 12 x 12) rentrés à la main, en se servant du code conventionnel suivant pour les cases voisines d'une case o :
  | Haut1 |   |
---|---|---|
Gauche8 | o | Droite 4 |   | Bas2 |   |
Ci-dessous les deux modes d'executions du jeu pour un labyrinthe de taille 12 x 12 :