Entraînez-vous à coder en Java en écrivant un jeu
Écrire des jeux simples est une façon amusante d’apprendre un nouveau langage de programmation. Mettez ce principe en pratique pour démarrer avec Java.
Mon article sur l'apprentissage de différents langages de programmation répertorie cinq choses que vous devez comprendre lorsque vous démarrez un nouveau langage. Bien entendu, une partie importante de l’apprentissage d’une langue consiste à savoir ce que vous avez l’intention d’en faire.
J'ai découvert que les jeux simples sont à la fois amusants à écrire et utiles pour explorer les capacités d'une langue. Dans cet article, je montre comment créer un jeu de devinettes simple en Java.
Installer Java
Pour réaliser cet exercice, Java doit être installé. Si vous ne l'avez pas, consultez ces liens pour installer Java sur Linux, macOS ou Windows.
Après l'avoir installé, exécutez cette commande Java dans un terminal pour confirmer la version que vous avez installée :
$ java -version
Devinez le numéro
Ce programme « devinez le nombre » exerce plusieurs concepts dans les langages de programmation : comment attribuer des valeurs aux variables, comment écrire des instructions et comment effectuer une évaluation conditionnelle et des boucles. C'est une excellente expérience pratique pour apprendre un nouveau langage de programmation.
Voici mon implémentation Java :
package com.example.guess;
import java.util.Random;
import java.util.Scanner;
class Main {
private static final Random r = new Random();
private static final int NUMBER = r.nextInt(100) + 1;
private static int guess = 0;
public static void main(String[] args) {
Scanner player = new Scanner(System.in);
System.out.println("number is " + String.valueOf(NUMBER)); //DEBUG
while ( guess != NUMBER ) {
// prompt player for guess
System.out.println("Guess a number between 1 and 100");
guess = player.nextInt();
if ( guess > NUMBER ) {
System.out.println("Too high");
} else if ( guess < NUMBER ) {
System.out.println("Too low");
} else {
System.out.println("That's right!");
System.exit(0);
}
}
}
}
Cela représente environ 20 lignes de code, sans compter les espaces et les accolades finales. Structurellement, cependant, il se passe beaucoup de choses, que je vais détailler ici.
Déclaration du paquet
La première ligne, package com.example.guess
, n'est pas strictement nécessaire dans une simple application à un seul fichier comme celle-ci, mais c'est une bonne habitude à prendre. Java est un langage important et du nouveau Java est écrit chaque jour. Chaque projet Java doit donc avoir un identifiant unique pour aider les programmeurs à distinguer une bibliothèque d'une autre.
Lors de l'écriture de code Java, vous devez déclarer un package
auquel il appartient. Le format utilisé est généralement un nom de domaine inversé, tel que com.opensource.guess
ou org.slf4j.Logger
. Comme d'habitude en Java, cette ligne se termine par un point-virgule.
Importer des instructions
Les lignes suivantes du code sont des instructions d'importation, qui indiquent au compilateur Java quelles bibliothèques charger lors de la création de l'application exécutable. Les bibliothèques que j'utilise ici sont distribuées avec OpenJDK, vous n'avez donc pas besoin de les télécharger vous-même. Comme ils ne font pas strictement partie du langage principal, vous devez les répertorier pour le compilateur.
La bibliothèque Random donne accès à la génération de nombres pseudo-aléatoires et la bibliothèque Scanner vous permet de lire les entrées utilisateur dans un terminal.
Classe Java
La partie suivante crée une classe Java. Java est un langage de programmation orienté objet, sa construction par excellence est donc une classe. Un cours propose des idées de code très spécifiques, et si vous débutez en programmation, vous les maîtriserez avec la pratique. Pour l’instant, considérez une classe comme une boîte dans laquelle vous placez des variables et des instructions de code, presque comme si vous construisiez une machine. Les éléments que vous placez dans la classe sont uniques à cette classe et, comme ils sont contenus dans une boîte, ils ne peuvent pas être vus par les autres classes. Plus important encore, puisqu’il n’y a qu’une seule classe dans cet exemple de jeu, une classe est autosuffisante : elle contient tout ce dont elle a besoin pour accomplir sa tâche particulière. Dans ce cas, sa tâche est l'ensemble du jeu, mais dans les applications plus vastes, les classes travaillent souvent ensemble dans une sorte de chaîne pour produire des tâches complexes.
En Java, chaque fichier contient généralement une classe. La classe de ce fichier est appelée Main
pour signifier qu'elle est le point d'entrée de cette application. Dans une application à fichier unique comme celle-ci, l'importance d'une classe principale est difficile à apprécier, mais dans un projet Java plus vaste comportant des dizaines de classes et de fichiers sources, il est utile d'en marquer un Main
. Et de toute façon, il est facile de conditionner une application à distribuer avec une classe principale définie.
Champs Java
En Java, comme en C et C++, vous devez déclarer les variables avant de les utiliser. Vous pouvez définir des « champs » en haut d'une classe Java. Le mot « champ » n'est qu'un terme sophistiqué pour désigner une variable, mais il fait spécifiquement référence à une variable affectée à une classe plutôt qu'à une variable intégrée quelque part dans une fonction.
Ce jeu crée trois champs : deux pour générer un nombre pseudo-aléatoire et un pour établir une supposition initiale (et toujours incorrecte). La longue chaîne de mots-clés (private static final
) menant à chaque champ peut sembler déroutante (surtout lorsque vous débutez avec Java), mais utiliser un bon IDE comme Netbeans ou Eclipse peut vous aider à faire le meilleur choix. .
Il est également important de les comprendre. Un champ privé est un champ disponible uniquement pour sa propre classe. Si une autre classe tente d'accéder à un champ privé, le champ peut tout aussi bien ne pas exister. Dans une application à classe unique telle que celle-ci, il est logique d'utiliser des champs privés.
Un champ statique appartient à la classe elle-même et non à une instance de classe. Cela ne fait pas beaucoup de différence dans une petite application de démonstration comme celle-ci car une seule instance de la classe existe. Dans une application plus grande, vous pouvez avoir une raison de définir ou de redéfinir une variable chaque fois qu'une instance de classe est générée.
La valeur d'un champ final ne peut pas être modifiée. Cette application le démontre parfaitement : le nombre aléatoire ne change jamais pendant le jeu (une cible en mouvement ne serait pas très juste), tandis que la supposition du joueur doit changer sinon le jeu ne pourrait pas être gagné. Pour cette raison, le nombre aléatoire établi au début du jeu est définitif, mais la supposition ne l’est pas.
Nombres pseudo-aléatoires
Deux champs créent le nombre aléatoire qui sert de cible au joueur. Le premier crée une instance de la classe Random
. Il s’agit essentiellement d’une graine aléatoire à partir de laquelle vous pouvez tirer un nombre assez imprévisible. Pour ce faire, répertoriez la classe que vous invoquez suivie d'un nom de variable de votre choix, que vous définissez sur une nouvelle instance de la classe : Random r=new Random();
. Comme les autres instructions Java, celle-ci se termine par un point-virgule.
Pour dessiner un nombre, vous devez créer une autre variable en utilisant la méthode nextInt()
de Java. La syntaxe est un peu différente, mais elle est similaire : vous répertoriez le type de variable que vous créez, vous fournissez le nom de votre choix, puis vous le définissez sur les résultats d'une action : int NUMBER=r. nextInt(100) + 1;
. Vous pouvez (et devriez) consulter la documentation de méthodes spécifiques, comme nextInt()
, pour savoir comment elles fonctionnent, mais dans ce cas, l'entier tiré du r
les graines aléatoires sont limitées jusqu'à 100 (soit un maximum de 99). L'ajout de 1 au résultat garantit qu'un nombre n'est jamais 0 et que le maximum fonctionnel est de 100.
De toute évidence, la décision de disqualifier tout nombre en dehors de la plage de 1 à 100 est une décision de conception purement arbitraire, mais il est important de connaître ces contraintes avant de se lancer dans la programmation. Sans eux, il est difficile de savoir vers quoi vous codez. Si possible, travaillez avec une personne dont le travail consiste à définir l'application que vous codez. Si vous n'avez personne avec qui travailler, assurez-vous d'abord de lister vos cibles, puis de mettre votre « casquette de codeur ».
Méthode principale
Par défaut, Java recherche une méthode main
(ou « fonction », comme on les appelle dans de nombreux autres langages) à exécuter dans une classe. Toutes les classes n'ont pas besoin d'une méthode principale, mais cette application de démonstration n'a qu'une seule méthode, elle peut donc tout aussi bien être la méthode principale. Les méthodes, comme les champs, peuvent être rendues publiques ou privées et statiques ou non statiques, mais la méthode principale doit être publique et statique pour que le compilateur Java puisse la reconnaître et l'utiliser.
Logique applicative
Pour que cette application fonctionne comme un jeu, elle doit continuer à fonctionner pendant que le joueur devine un nombre pseudo-aléatoire secret. Si l'application s'arrêtait après chaque supposition, le joueur n'aurait qu'une seule supposition et gagnerait très rarement. Cela fait également partie de la conception du jeu que l'ordinateur fournisse des indices pour guider la prochaine supposition du joueur.
Une boucle while
avec des instructions if
intégrées atteint cet objectif de conception. Une boucle while
continue intrinsèquement à s'exécuter jusqu'à ce qu'une condition spécifique soit remplie. (Dans ce cas, la variable guess
doit être égale à la variable NUMBER
.) Chaque supposition peut être comparée au NUMBER
cible pour proposer des conseils utiles.
Syntaxe
La méthode principale commence par créer une nouvelle instance de Scanner
. C'est le même principe que l'instance Random
utilisée comme graine pseudo-aléatoire : vous citez la classe que vous souhaitez utiliser comme modèle, fournissez un nom de variable (j'utilise player
pour représenter la personne qui saisit les suppositions), puis définissez cette variable sur les résultats de l'exécution de la méthode principale de la classe. Encore une fois, si vous codiez cela vous-même, vous consulteriez la documentation de la classe pour obtenir la syntaxe lors de son utilisation.
Cet exemple de code inclut une instruction de débogage qui révèle la cible NUMBER
. Cela rend le jeu sans objet, mais il est utile de se prouver qu'il fonctionne correctement. Même cette petite instruction de débogage révèle quelques astuces Java importantes : System.out.println
est une instruction d'impression, et la méthode valueOf()
convertit l'entier NUMBER
en une chaîne pour l'imprimer dans le cadre d'une phrase plutôt que comme un élément mathématique.
L'instruction while
commence ensuite, avec la seule condition que la estimation
du joueur ne soit pas égale au NUMBER
cible. Il s'agit d'une boucle infinie qui ne peut se terminer que lorsqu'il est faux que devine
n'est pas égal à NUMBER
.
Dans cette boucle, le joueur est invité à saisir un numéro. L'objet Scanner, appelé player
, prend tout entier valide saisi par le joueur et met sa valeur dans le champ devinez
.
L'instruction if
compare guess
à NUMBER
et répond avec les instructions d'impression System.out.println
pour fournir des commentaires au joueur humain.
Si devine
n'est ni supérieur ni inférieur à NUMBER
, alors il doit lui être égal. À ce stade, le jeu imprime un message de félicitations et se termine. Comme d'habitude avec la conception d'applications POSIX, ce jeu se termine avec un statut 0 pour indiquer le succès.
Exécutez le jeu
Pour tester votre jeu, enregistrez l'exemple de code sous Guess.java
et utilisez la commande Java pour l'exécuter :
$ java ./Guess.java
number is 38
Guess a number between 1 and 100
1
Too low
Guess a number between 1 and 100
39
Too high
Guess a number between 1 and 100
38
That's right!
$
Comme prévu !
Emballer le jeu
Bien que ce ne soit pas aussi impressionnant sur une application à fichier unique comme celle-ci que sur un projet complexe, Java rend l'empaquetage très simple. Pour de meilleurs résultats, structurez votre répertoire de projet pour inclure un emplacement pour votre code source, un emplacement pour votre classe compilée et un fichier manifeste. En pratique, cela est quelque peu flexible et l’utilisation d’un IDE fait l’essentiel du travail à votre place. Il est cependant utile de le faire à la main de temps en temps.
Créez un dossier de projet si vous ne l'avez pas déjà fait. Créez ensuite un répertoire appelé src
pour contenir vos fichiers sources. Enregistrez l'exemple de code dans cet article sous src/Guess.java
:
$ mkdir src
$ mv sample.java src/Guess.java
Maintenant, créez une arborescence de répertoires qui reflète le nom de votre package Java, qui apparaît tout en haut de votre code :
$ head -n1 src/Guess.java
package com.example.guess;
$ mkdir -p com/example/guess
Créez un nouveau fichier appelé Manifest.txt
contenant une seule ligne de texte :
$ echo "Manifest-Version: 1.0" > Manifest.txt
Ensuite, compilez votre jeu dans une classe Java. Cela produit un fichier appelé Main.class
dans com/example/guess
:
$ javac src/Guess.java -d com/example/guess
$ ls com/example/guess/
Main.class
Vous êtes prêt à regrouper votre application dans un JAR (archive Java). La commande jar
ressemble beaucoup à la commande tar, donc de nombreuses options peuvent sembler familières :
$ jar cfme Guess.jar \
Manifest.txt \
com.example.guess.Main \
com/example/guess/Main.class
D'après la syntaxe de la commande, vous pouvez supposer qu'elle crée un nouveau fichier JAR appelé Guess.jar
avec ses données manifestes requises situées dans Manifest.txt
. Sa classe principale est définie comme une extension du nom du package, et la classe est com/example/guess/Main.class
.
Vous pouvez afficher le contenu du fichier JAR :
$ jar tvf Guess.jar
0 Wed Nov 25 10:33:10 NZDT 2020 META-INF/
96 Wed Nov 25 10:33:10 NZDT 2020 META-INF/MANIFEST.MF
1572 Wed Nov 25 09:42:08 NZDT 2020 com/example/guess/Main.class
Et vous pouvez même l'extraire avec les options xvf
.
Exécutez votre fichier JAR avec la commande java
:
$ java -jar Guess.jar
Copiez votre fichier JAR de Linux sur un ordinateur macOS ou Windows et essayez de l'exécuter. Sans recompilation, il fonctionne comme prévu. Cela peut sembler normal si votre base de comparaison est, par exemple, un simple script Python qui s'exécute n'importe où, mais imaginez un projet complexe avec plusieurs bibliothèques multimédias et autres dépendances. Avec Java, ces dépendances sont regroupées avec votre application, et toutes s'exécutent sur n'importe quelle plate-forme. Bienvenue dans le monde merveilleux de Java !