Créer un programme pour PyRat

Dans cet article, nous créons ensemble un programme (pas très intelligent) pour ramasser un unique morceau de fromage dans un labyrinthe. Appelons le AIs/improved_random.py. La commande pour démarrer la partie dans ce mode de jeu sera donc la suivante : python pyrat.py –rat AIs/improved_random.py.

Présentation de l’algorithme

Une idée pour trouver un morceau de fromage dans le labyrinthe est de se déplacer au hasard. Toutefois, cela peut prendre du temps, car on visitera probablement plusieurs fois les mêmes endroits. Nous allons donc bouger au hasard, mais (un peu) plus intelligemment. L’algorithme que nous allons utiliser procède comme suit, tant que le morceau de fromage n’est pas atteint :

  1. On se déplace sur une case pas encore visitée.
  2. Si on ne peut pas le faire, on bouge au hasard.

La seconde étape pourrait être améliorée, par exemple en revenant à la dernière case connue ayant des voisins pas encore visités.

Implémentation

Pour implémenter cet algorithme, nous partons d’une copie du fichier AIs/template.py, renommée AIs/improved_random.py (les commentaires ne sont pas affichés ici par souci de lisibilité) :

Changeons le nom du programme, et de supprimons les corps des méthodes preprocessing et turn (qui servent juste de démo) :

Une fois cela fait, réfléchissons à ce dont nous avons besoin. Tout d’abord, nous aurons besoin de choisir des directions aléatoirement. Il nous faut donc importer la bibliothèque Python random, et créer une fonction renvoyant une direction aléatoire :

A chaque étape, nous voulons nous déplacer sur une case qui n’a pas encore été visitée. Il va donc falloir se souvenir des emplacements visités. Pour cela, nous choisissons d’utiliser une liste. Comme nous utiliserons cette structure lors de plusieurs appels de fonctions distincts, elle doit être déclarée comme variable globale, en dehors de tout corps de fonction :

Passons aux deux fonctions principales. Il n’y a rien de particulier à faire à l’initialisation. Nous allons donc utiliser le mot-clé Python pass pour indiquer que le corps de la méthode preprocessing est vide :

A présent, passons au gros du programme : la définition du comportement à chaque tour de jeu. Une première chose à faire est de trouver les mouvements qui peuvent nous emmener sur une case non visitée. Pour cela, on définit une nouvelle fonction qui nous renvoie la liste de ces mouvements. Appelons la listDiscoveryMoves :

Notez que la fonction listDiscoveryMoves utilise une fonction moveFromLocation que nous n’avons pas encore définie. Créons donc une telle fonction, qui pour une case d’origine et une case de destination, renvoie le mouvement à effectuer. La bibliothèque numpy de Python fournit une fonction permettant de soustraire aisément des paires d’entiers, élément par élément :

On peut à présent se servir de la fonction listDiscoveryMoves pour choisir un mouvement amenant à une nouvelle case. Toutefois, si un tel mouvement n’existe pas, on choisit de se diriger dans une direction au hasard. Attention ! N’oubliez pas de déclarer visitedCells comme variable globale pour la mettre à jour :

Maintenant, lançons notre programme pour voir comment il se débrouille !

Est-ce mieux ?

Afin d’évaluer si ce nouveau programme est meilleur qu’un simple programme se déplaçant aléatoirement, faisons quelques statistiques.

Pour cela, on va tester le nombre moyen de morceaux de déplacements réalisés par le programme créé, et le comparer au nombre de déplacements moyens réalisés par le programme aléatoire basique (“AIs/random.py”).

On va lancer le programme en utilisant plusieurs paramètres :

  • D’abord on va réduire la taille du labyrinthe pour ne pas que ça prenne trop de temps : “–width 5 –height 5″
  • On va ne générer qu’un seul morceau de fromage : “–pieces 1″
  • On ne va pas attendre 100ms à chaque fois pour que le joueur prenne une décision, mais jouer aussi vite que possible : “–synchronous”
  • Pour aller encore plus vite, on va désactiver l’affichage graphique des parties : “–nodrawing”
  • Enfin, on va faire une moyenne sur plusieurs tests : “–tests 100″

Au final :

On obtient par exemple :

Puis :

On obtient ici :

On constate que dans les deux cas le rat est parvenu à trouver le morceau de fromage (ce qui n’était pas garanti car par défaut une partie ne peut pas excéder 2000 tours (voir le paramètre “–max_turns”)). Mais notre programme amélioré a presque divisé par deux le nombre moyen de mouvements pour y parvenir !

Publié le

Laisser un commentaire