Vous souhaitez vous initier à la programmation avec Python tout en vous amusant ?
Dans ce tutoriel, vous allez apprendre comment programmer un robot virtuel gladiateur (i.e. un agent) dans une arène de jeu TactX, pour lui transmettre de l’intelligence afin de lui permettre d’affronter les agents ennemis en temps réel, et tout ceci de manière autonome.
Sommaire
🌐 Connexion à une arène du jeu
Avant de se lancer dans le combat dans l’arène, il vous faut d’abord obtenir vos identifiants. Pour cela, rien de plus simple, 👉renseignez votre Prénom, Nom et Email dans ce formulaire. Vous recevrez vos identifiants gratuitement sous 48h.
Une fois reçus par mail, à vos claviers et neurones ! Sur play.jusdeliens.com renseignez vos username et password communiqués par mail, puis sélectionnez l’arène que vous souhaitez rejoindre.
L’accès aux arènes publiques est entièrement gratuit mais limité. Elles sont ouvertes à l’occasion d’affrontements ou de formations jusdeliens dont les dates vous seront communiquées via la newsletter (👉par ici pour vous abonner).
Pour plus de liberté, vous pouvez créer votre propre arène privée hébergée sur un serveur jusdeliens, ouverte 24h/24, 7 jours sur 7 et accessible dans le monde entier avec IDEAL Arena. Dans ce cas, votre arène privée sera uniquement accessible à ceux à qui vous communiquerez son nom.
Pour les plus téméraires, un tutoriel sera bientôt mis en ligne pour créer votre arène et l’héberger sur votre serveur privé (avec OVH ou free). Vous pouvez aussi vous 👉inscrire à notre prochaine session de formation.
👣 Vos premiers pas
📚 Les modules
Premier concept à maîtriser : la notion de module en python.
Un module en programmation (appelé encore librairie) est un fichier développé par d’autres personnes. Il contient un autre programme que vous allez pouvoir utiliser dans votre programme principale. Son intérêt principal est de vous faire gagner du temps pour ne pas avoir à tout recoder vous-même.
Pour jouer dans une arène TactX, on va importer le module pytactx contenu dans un autre fichier, à côté de votre fichier main dans l’arborescence du projet.
Dans le fichier main.py, ajoutons donc au début du programme la ligne suivante :
import j2l.pytactx.agent as pytactx
Et voilà ! Nous pouvons désormais créer notre agent pour combattre dans l’arène !
💾 Les variables
Pour incarner notre agent, il nous faut maîtriser un 2e concept : la notion de variable.
Dans un programme, une variable est comme une boîte de rangement. Elle vous permet de stocker une information (un texte, un nombre, une image …) afin de la manipuler par la suite. On donne un nom à cette boîte afin de pouvoir s’en servir par la suite.
Dans le module pytactx, la première variable à créer est votre agent. Pour créer cette variable nommée « agent » en Python, on utilise l’opérateur égal « = » (dit aussi opérateur d’affectation). Cette opérateur va nous permettre de placer dans notre « boîte » agent ce qu’il y a à droite du égal (on dit qu’on initialise la variable).
agent = pytactx.Agent(playerId="LeNomDeMonSuperAgent", username="VotreUserName", password="VotrePassword", arena="nomDeLArene")
L’expression à droite permet de créer votre agent et de le connecter à l’arène de jeu. A vous de remplacer les caractères entre guillemets:
- « LeNomDeMonSuperAgent » : c’est le nom de votre agent qui apparaitra dans l’arène
- « VotreUserName » : à remplacer par le username transmis par mail
- « VotrePassword » : à remplacer par le password transmis par mail
- « NomDeLArene » : à remplacer par le nom de l’arène à rejoindre
Une fois créée, cette variable agent va notamment vous permettre d’accéder aux variables de votre agent indiquée ci-dessous. Attention par contre, ces variables sont en lecture seule, autrement dit vous ne pourrez pas les modifier directement ! (Désolé les tricheurs en herbe 😉 )
Grâce à ces variables, vous pourrez modifier le comportement de votre agent en fonction de son environnement. Par exemple, si sa vie diminue, c’est … qu’il SE FAIT TIRER DESSUS !! Auquel cas, il serait pertinent de riposter !
🤔 Mais tu nous a pourtant dit qu’il n’était pas possible de les modifier directement ?
Et oui, pour les modifier, il faudra utiliser quelque chose d’autre de bien plus puissant, les fonctions !
⚙️Les fonctions
Heureusement, il est aussi possible de faire passer votre agent à l’action ! 3e concept : les fonctions.
Une fonction est un sous programme qui, dès lors qu’on l’appelle, exécute une suite d’instructions. Vous pouvez créer vos propres fonctions, par exemple si vous souhaitez ordonner votre programme, ou appeler plusieurs fois la même suite d’instructions (comme une routine ou une procédure). Vous pouvez aussi utiliser des fonctions que d’autres développeurs ont codées pour vous.
Pour appeler une fonction en Python, il suffit d’écrire sur une nouvelle ligne :
nomDeVotreFonction(parametre1, parametre2)
On reconnait une fonction par ses parenthèses après le nom de la fonction. Ces parenthèses délimitent les paramètres d’entrée à passer à la fonction. Selon la fonction, le nombre de paramètres peut varier. S’il y en a plusieurs, ils sont séparés par des virgules. Il peut ne pas avoir de paramètre du tout. Auquel cas, il n’y aura rien à mettre en parenthèse
# Importe le module de maths pour faire des calculs complexes
import math
# Appelle la fonction sqrt pour calculer la racine carré du nombre 4
math.sqrt(4)
# Appelle la fonction pow pour calculer 2 à la puissance 4
math.pow(2,4)
🤔 C’est quoi ces lignes qui commencent par des ‘#’ ?
Ce sont des commentaires en python. Ce n’est pas du code qui sera exécuté, mais une aide pour mieux se repérer dans le code. Une bonne habitude à prendre avant de coder est de toujours commencer par le commentaire, puis d’ajouter le code correspondant. De cette manière, si vous deviez reprendre votre code des mois plus tard, ou si un autre développeur devait reprendre votre travail, cela serait d’une aide considérable !
Bon, pour le moment, nous allons nous contenter d’utiliser les fonctions de votre agent qui ont déjà été développées pour vous. Voici les principales :
Pour tirer en rafale tout en déplaçant votre agent à la colonne 6 en partant de la gauche et à la ligne 7 en partant du haut de la grille, il faut donc écrire :
agent.fire(True)
agent.moveTowards(6,7)
agent.update()
N’oubliez pas d’appeler la fonction update() une fois toutes vos actions effectuées, afin d’envoyer votre demande au serveur.
🤔 Tu as mis un « T » majuscule à Towards c’est normal ?
⛔ Important
Oui, Python n’aime pas les caractères spéciaux comme les espaces ou les accents dans les noms de variables et de fonctions. Du coup, on peut mettre une majuscule à la place de l’espace, c’est la convention camelCase (comme les bosses du chameau 🐫), ou bien un underscore (le tiret du 8 qui rampe au sol comme un serpent 🐍) qui est la convention snake_case. Notez que Python est sensible à la casse, donc agent.movetowards() ne marchera pas car la fonction est connu sous le nom agent.moveTowards().
Bien maintenant que vous savez comment créer votre agent, récupérer ses variables d’état et le faire exécuter des actions, il ne reste plus qu’à relier tout cela avec de belles structures conditionnelles !
🚪Les structures conditionnelles
Et bien oui, c’est bien beau de savoir tirer mais vu votre nombre de munitions, il vaut mieux tirer uniquement quand un ennemi est devant vous non ? Et pour ça, il nous faut traduire l’expression suivante :
Si un ennemi est devant nous
Alors on lui tire dessus en rafale
Sinon
On arrête de tirer en rafale pour économiser nos précieuses munitions
Cette expression « Si Alors Sinon » est dite conditionnelle car l’action à réaliser dépend d’une condition. En python, cette expression se traduirait par cela :
if ( agent.distance != 0 ):
agent.tirer(True)
else:
agent.tirer(False)
Pour savoir si un ennemi est devant nous, nous comparons la variable d’état de l’agent « agent.distance ». Si elle est différente de 0, c’est qu’un ennemi est devant dans la direction de notre agent. Si elle est égale à 0, c’est qu’aucun ennemi n’est visible dans cette direction.
En python, on peut réaliser différents tests à l’aides des opérateurs suivants.
COMPARAISON | OPÉRATEUR PYTHON |
Strictement supérieur à | > |
Supérieur ou égal à | >= |
Strictement inférieur à | < |
Inférieur ou égal à | <= |
Egal à | == |
Différent de | != |
🤔 C’est normal que tu aies mis 2 signes égal pour la comparaison « égal à » ?
Absolument ! Souvenez vous, on a vu au début l’opérateur d’affection ‘=’ pour créer et initialiser une variable. Pour distinguer l’affection de la comparaison, python (comme d’autres langages) a fait le choix d’utiliser 2 signes égal ‘==’ pour la comparaison.
🤔 Pourquoi as-tu mis ‘:’ à la fin du ‘if’ et du ‘else’ ?
En python les structures conditionnelles, ainsi que les boucles et définitions de fonctions sont des blocs. Comme les blocs qui s’encapsulent sous Scratch, un bloc un python commence par ‘:’ . Les instructions à exécuter dans ce bloc doivent être précédés d’une indentation.
🤔 Une indentation ? Il faut que j’aille voir mon dentiste ?!
Une indentation permet une meilleur lisibilité du code. De cette manière on peut rapidement voir les blocs d’instructions qui seront exécutés selon les conditions. En python, en plus des ‘:’ au début du bloc, l’INDENTATION EST OBLIGATOIRE pour signifier que chaque instruction indentée est à exécuter dans le bloc supérieur qui la contient.
🤔 Combien de caractères espaces as-tu mis pour faire l’indentation ?
⛔ Important
Les indentations ne sont pas des caractères d’espace comme les autres. Il est coutume d’utiliser la touche tabulation sur le clavier pour faire une indentation (la touche avec 2 flèches parallèles horizontales et opposées en haut à gauche du clavier ↔️). C’est donc UN SEUL CARACTÈRE TABULATION qui est recommandé, plutôt que plusieurs caractères avec la touche espace.
Bon maintenant que toutes ces notions sont comprises, on va pouvoir exécuter le code suivant.
import j2l.pytactx.agent as pytactx
agent = pytactx.Agent(playerId="jusdeliens", username="monUserName", password="vousNeLeSaurezJamais!", arena="leNomDeVotreArene")
if ( agent.distance != 0 ):
agent.fire(True)
else:
agent.fire(False)
agent.update()
Sous repl.it, il ne vous reste plus qu’à cliquer sur le bouton « Run » pour démarrer votre programme.
Dans la console (fenêtre noire à droite), entrer les informations demandées puis entrer. Si la valeur par défaut est correcte, tapez simplement entrer.
🤔 Il ne se passe rien dans l’arène, je ne vois pas mon agent, c’est normal ?
C’est normal ! Nous avons oublié une dernière chose !
➿Les boucles
Si votre agent n’apparait pas, c’est parce le programme s’est terminé trop vite. L’interpréteur python a bien exécuté ligne par ligne le programme demandé, mais un fois arrivée à la ligne 13 le programme se termine.
🤔 Tu veux dire qu’on a oublié de lui dire de répéter nos instructions pour ne pas s’arrêter ?
Exactement ! Et pour ça, il nous faut maîtriser un dernier concept : les boucles !
« Répéter tant que », « répéter pour chaque valeur de 0 jusqu’à 10 », voici de nouveaux blocs qui nous permettront d’enrichir nos programmes !
On distingue 2 types de boucles : les bornées et les non bornées.
- les boucles bornées : répète des instructions pour un nombre d’itérations données. Par exemple : « répéter 10 fois »
- les boucles non-bornées : répète des instructions tant qu’une condition est vraie ou jusqu’à ce qu’une condition soit fausse. Par exemple : « répéter tant que mon agent est en vie »
Comme les structures conditionnelles, les boucles sont des blocs. En python, elle commence donc par un test suivi de ‘:’ puis chaque instruction du bloc est indentée d’une tabulation par rapport au bloc supérieur la contenant.
Parfait ! Maintenant, votre 1er programme fonctionnel !
import j2l.pytactx.agent as pytactx
agent = pytactx.Agent(playerId="jusdeliens", username="monUserName", password="vousNeLeSaurezJamais!")
while (agent.life> 0 ):
if ( agent.distance != 0 ):
agent.fire(True)
else:
agent.fire(False)
agent.update()
Vous devriez voir apparaître votre agent sur la grille à une position aléatoire. Premier constat, il ne fait pas grand chose … Normal, car il attend qu’un ennemi se présente devant lui pour tirer !
🎲 L’aléatoire comme stratégie de déplacement
Pour animer votre agent, je vous propose de le faire se déplacer de manière aléatoire sur la grille en utilisant le module random en python.
Comme le serveur de jeu contraint les déplacements aux cases adjacentes (c’est à dire que votre agent ne peut se déplacer que comme un roi sur un échiquier), il va falloir générer un x et y aléatoire en + ou – 1 autour de la position de votre agent.
Par exemple, si votre position (x,y) est (6,7) alors il faudrait générer un couple (x,y) aléatoire parmi les valeurs suivantes : (6,7) , (5,7) , (5,6) , (6,6) , (7,6) , (7,7) , (7,8) , (6,8) , (5,8).
Cela revient à générer 2 nombres aléatoire :
- dx = 1er nombre aléatoire compris entre -1 et +1 inclus.
- dy = 2e nombre aléatoire compris entre -1 et +1 inclus.
En python, on génère un nombre aléatoire à l’aide de la fonction randint du module random de la façon suivante. Cette fonction attend 2 paramètres : un minimum et un maximum. Elle renvoie ensuite un nombre entier aléatoire compris entre le min et le max inclus.
import random
dxAleatoire = random.randint(-1,1)
On fait de même pour changer l’orientation de manière aléatoire entre 0 (droite) et 3 (bas) et voici le résultat en python :
import j2l.pytactx.agent as pytactx
import random
# Création de l'agent et connexion à l'arène
agent = pytactx.Agent(playerId="jusdeliens", username="monUserName", password="vousNeLeSaurezJamais!")
# Répéter tant que votre agent est en vie
while agent.life > 0:
# Tirer si ennemie visible
if ( agent.distance != 0 ):
agent.fire(True)
else:
agent.fire(False)
# Déplacer et orienter de manière aléatoire
dx = random.randint(-1,1)
dy = random.randint(-1,1)
agent.move(dx, dy)
dir = random.randint(0,3)
agent.lookAt(dir)
# Envoyer les ordres au serveur
agent.update()
🛣️ Et après ?
Vous avez aimé ce tutoriel et vous en voulez d’autres ?
Faites le nous savoir en 👉 donnant vos avis et vos envies et nous nous empresserons de vous en rédigez d’autres 😉
C’est fini pour ce tutoriel ! A vous de jouer maintenant 😉