1. Avant de commencer
Pour les ateliers de programmation de ce parcours, vous allez créer une application Android "Dice Roller", qui génère un résultat aléatoire lorsque l'utilisateur lance le dé. Le résultat tient compte du nombre de faces des dés. Par exemple, un dé à six faces ne peut générer que des valeurs comprises entre 1 et 6.
Voici à quoi ressemblera l'application finale.
Pour vous aider à mieux vous concentrer sur les nouveaux concepts de programmation, vous utiliserez l'outil de programmation Kotlin sur navigateur pour créer les principales fonctionnalités de cette application. Le programme affichera vos résultats dans la console. Par la suite, vous implémenterez l'interface utilisateur dans Android Studio.
Dans ce premier atelier de programmation, vous allez créer un programme Kotlin qui simule un lancer de dé et génère un nombre aléatoire, comme le ferait un dé physique.
Conditions préalables
- Vous savez ouvrir, modifier et exécuter du code dans https://developer.android.com/training/kotlinplayground.
- Vous savez créer et exécuter un programme Kotlin qui utilise des variables et des fonctions, puis affiche un résultat dans la console.
- Vous savez mettre en forme les nombres dans un texte en utilisant un modèle de chaîne avec la notation
${variable}
.
Points abordés
- Comment programmer la génération de nombres aléatoires pour simuler des lancers de dés
- Comment structurer votre code en créant une classe
Dice
avec une variable et une méthode - Comment créer une instance d'objet d'une classe, modifier ses variables et appeler ses méthodes
Objectifs de l'atelier
- Créer un programme Kotlin à l'aide de l'outil de programmation Kotlin sur navigateur, qui permet de simuler des lancers de dés aux résultats aléatoires
Ce dont vous avez besoin
- Un ordinateur avec une connexion Internet
2. Générer des nombres aléatoires
Les jeux comportent souvent un élément aléatoire. Vous pouvez gagner une récompense au hasard ou avancer d'un nombre aléatoire d'étapes sur le plateau de jeu. Dans la vie de tous les jours, vous pouvez utiliser des chiffres et des lettres au hasard pour générer des mots de passe plus sûrs.
Au lieu de lancer de vrais dés, vous pouvez écrire un programme qui simule le processus. Chaque fois que vous lancez le dé, le résultat peut être n'importe quel nombre compris dans la plage de valeurs possibles. Heureusement, vous n'avez pas besoin de créer votre propre générateur de nombres aléatoires pour ce type de programme. La plupart des langages de programmation, y compris Kotlin, permettent de générer des nombres au hasard. Dans cette tâche, vous allez générer un nombre aléatoire à l'aide du code Kotlin.
Configurer votre code de démarrage
- Dans votre navigateur, ouvrez le site Web https://developer.android.com/training/kotlinplayground.
- Supprimez tout le code existant dans l'éditeur de code et remplacez-le par le code ci-dessous. Il s'agit de la fonction
main()
, avec laquelle vous avez travaillé dans de précédents ateliers de programmation.
fun main() {
}
Utiliser la fonction aléatoire
Pour lancer les dés, vous avez besoin d'un moyen de représenter toutes les valeurs valides. Pour les dés à six faces, les résultats possibles sont 1, 2, 3, 4, 5 et 6.
Précédemment, vous avez appris qu'il existe des types de données tels que Int
pour les nombres entiers et String
pour le texte. IntRange
est un autre type de données, qui représente une plage de nombres entiers comprise entre deux bornes. Le type de données IntRange
peut servir à représenter les valeurs possibles d'un lancer de dés.
- Dans votre fonction
main()
, définissez une variable en tant queval
et nommez-ladiceRange
. Affectez-la à une fonctionIntRange
de plage 1 à 6, qui représentera la plage d'entiers qu'un dé à six faces peut produire.
val diceRange = 1..6
Vous pouvez identifier 1..6
comme une plage Kotlin, car elle contient un numéro de début, deux points, suivi d'un numéro de fin (sans espace entre les deux). D'autres exemples de plages d'entiers seraient 2..5
, pour des nombres entre 2 et 5, ou 100..200
, pour des nombres entre 100 et 200.
De la même manière que l'appel de println()
indique au système d'afficher le texte donné, vous pouvez utiliser une fonction random()
pour générer et renvoyer un nombre aléatoire compris dans une plage donnée. Comme précédemment, vous pouvez stocker le résultat dans une variable.
- Dans
main()
, définissez une variable en tant queval
et nommez-larandomNumber
. - Définissez
randomNumber
sur la valeur du résultat de l'appel derandom()
dans la plagediceRange
, comme indiqué ci-dessous.
val randomNumber = diceRange.random()
Notez que vous appelez random()
dans la plage diceRange
à l'aide d'un point inséré entre la variable et l'appel de fonction. Vous pouvez interpréter ceci comme "générer un nombre aléatoire issu de diceRange
". Le résultat est ensuite stocké dans la variable randomNumber
.
- Pour afficher le nombre généré de façon aléatoire, utilisez la notation de mise en forme de chaîne (également appelée "modèle de chaîne")
${randomNumber}
, comme illustré ci-dessous.
println("Random number: ${randomNumber}")
Votre code, une fois terminé, doit se présenter comme suit :
fun main() {
val diceRange = 1..6
val randomNumber = diceRange.random()
println("Random number: ${randomNumber}")
}
- Exécutez votre code plusieurs fois. Chaque fois, la sortie doit s'afficher comme ci-dessous, avec des nombres aléatoires différents.
Random number: 4
3. Créer une classe Dice
Lorsque vous lancez un dé, il s'agit d'un objet physique que vous avez en main. Même si le code que vous venez d'écrire fonctionne parfaitement, il est difficile de faire le lien avec de véritables dés. Organiser un programme pour le rapprocher de ce qu'il représente facilite la compréhension. Ce serait bien de pouvoir "lancer" nos dés programmatiques !
Tous les dés fonctionnent essentiellement de la même manière. Ils ont les mêmes propriétés, comme leurs faces, et le même comportement, comme la capacité à être lancés. Dans Kotlin, vous pouvez créer un schéma programmatique pour refléter un dé avec des faces et la capacité de produire un nombre aléatoire. On appelle ce type de schéma une classe.
À partir de cette classe, vous pourrez créer des objets "dés", appelés instances d'objet. Par exemple, vous pouvez créer des dés à 4 ou 12 faces.
Définir une classe Dice
Dans les étapes suivantes, vous allez définir une nouvelle classe appelée Dice
(dé en anglais) pour représenter un dé "lançable".
- Pour repartir sur des bases saines, supprimez le code de la fonction
main()
afin d'obtenir le code présenté ci-dessous.
fun main() {
}
- Sous cette fonction
main()
, ajoutez une ligne vide, puis du code pour créer la classeDice
. Comme indiqué ci-dessous, commencez par le mot cléclass
, suivi du nom de la classe, puis d'accolades ouvrantes et fermantes. Laissez un espace entre les accolades pour insérer le code de la classe.
class Dice {
}
Dans la définition d'une classe, vous pouvez lui spécifier une ou plusieurs propriétés à l'aide de variables. Les dés physiques ont un nombre de faces, une couleur et un poids. Dans cette tâche, votre priorité sera la propriété du nombre de faces de vos dés.
- Dans la classe
Dice
, ajoutez unevar
appeléesides
correspondant au nombre de faces de vos dés. Définissezsides
sur 6.
class Dice {
var sides = 6
}
Et voilà ! Vous disposez désormais d'une classe très simple représentant votre dé.
Créer une instance de la classe Dice
Avec cette classe Dice
, vous disposez d'un schéma de construction pour votre dé. Pour intégrer un dé à votre programme, vous devez créer une instance d'objet Dice
. (Et si vous avez besoin de trois dés, vous devez créer trois de ces instances d'objets.)
- Pour créer une instance d'objet de
Dice
, dans la fonctionmain()
, créez uneval
appeléemyFirstDice
et initialisez-la en tant qu'instance de la classeDice
. Notez les parenthèses après le nom de la classe. Elles indiquent que vous créez une instance d'objet à partir de la classe.
fun main() {
val myFirstDice = Dice()
}
Maintenant que vous disposez d'un objet myFirstDice
, créé à partir du schéma, vous pouvez accéder à ses propriétés. La seule propriété de Dice
est sides
. Vous accédez à une propriété à l'aide de la "notation par points". Pour accéder à la propriété sides
de myFirstDice
, vous appelez myFirstDice.sides
(qui se prononce "myFirstDice
-dot-sides
", "dot" signifiant "point" en anglais).
- Sous la déclaration de
myFirstDice
, ajoutez une instructionprintln()
pour récupérer le nombre desides
demyFirstDice.
.
println(myFirstDice.sides)
Le code doit se présenter comme suit.
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
}
class Dice {
var sides = 6
}
- Exécutez votre programme. Il devrait générer le nombre de
sides
défini dans la classeDice
.
6
Vous disposez maintenant d'une classe Dice
et d'un myFirstDice
avec 6 sides
.
Il est de temps de le lancer le dé !
Lancer le dé
Vous avez précédemment utilisé une fonction pour effectuer une action : imprimer les étages d'un gâteau. L'action de lancer un dé peut aussi être implémentée en tant que fonction. Et comme tous les dés peuvent être lancés, vous pouvez ajouter une fonction pour cela dans votre classe Dice
. Une fonction définie dans une classe est également appelée méthode.
- Dans la classe
Dice
, sous la variablesides
, insérez une ligne vide, puis créez une fonction permettant de lancer votre dé. Commencez par le mot clé Kotlinfun
, suivi du nom de la méthode, suivi des parenthèses()
, puis des accolades{}
. Vous pouvez laisser une ligne vide entre les accolades pour laisser de l'espace à du code complémentaire, comme illustré ci-dessous. Votre classe devrait se présenter comme suit :
class Dice {
var sides = 6
fun roll() {
}
}
Lorsque vous lancez un dé à six faces, vous générez un nombre aléatoire compris entre 1 et 6.
- Dans la méthode
roll()
, créez uneval randomNumber
. Attribuez-lui un nombre aléatoire issu de la plage1..6
. Utilisez la notation par points pour appelerrandom()
sur la plage.
val randomNumber = (1..6).random()
- Une fois le nombre aléatoire généré, affichez-le dans la console. Votre méthode
roll()
terminée devrait se présenter comme suit.
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
- Pour lancer
myFirstDice
, dansmain()
, appelez la méthoderoll()
surmyFirstDice
. Les méthodes sont appelées à l'aide de la notation par points. Pour appeler la méthoderoll()
demyFirstDice
, saisissezmyFirstDice.roll()
(prononcé "myFirstDice
-dot-roll()
").
myFirstDice.roll()
Votre code, une fois terminé, doit se présenter comme suit.
fun main() {
val myFirstDice = Dice()
println(myFirstDice.sides)
myFirstDice.roll()
}
class Dice {
var sides = 6
fun roll() {
val randomNumber = (1..6).random()
println(randomNumber)
}
}
- Exécutez votre code ! Vous devriez obtenir le résultat aléatoire d'un lancer de dés sous le nombre de côtés. Exécutez votre code plusieurs fois. Notez que le nombre de côtés reste le même, mais que la valeur du résultat change.
6 4
Félicitations ! Vous avez défini une classe Dice
avec une variable sides
et une fonction roll()
. Dans la fonction main()
, vous avez créé une instance d'objet Dice
, puis vous avez appelé la méthode roll()
pour générer un nombre aléatoire.
4. Renvoyer la valeur de votre lancer de dé
Vous affichez actuellement la valeur de randomNumber
dans votre fonction roll()
, ce qui fonctionne très bien. Cependant, il est parfois plus utile de renvoyer le résultat d'une fonction vers l'élément qui l'a appelée. Par exemple, vous pouvez affecter le résultat de la méthode roll()
à une variable, puis faire avancer un joueur en fonction de ce montant. Voyons comment procéder.
- Dans
main()
, modifiez la lignemyFirstDice.roll()
. Créez uneval
appeléediceRoll
. Définissez-la sur la valeur renvoyée par la méthoderoll()
.
val diceRoll = myFirstDice.roll()
Cette opération n'a aucun résultat à ce stade, car roll()
ne renvoie rien pour l'instant. Pour que ce code fonctionne comme prévu, roll()
doit renvoyer un élément.
Dans les précédents ateliers de programmation, vous avez appris que vous devez spécifier un type de données pour les arguments d'entrée des fonctions. De même, vous devez spécifier un type pour les données renvoyées par une fonction.
- Modifiez la fonction
roll()
pour spécifier le type de données à renvoyer. Dans ce cas, le nombre aléatoire est un entier (Int
). Le type renvoyé est doncInt
. La syntaxe permettant de spécifier le type renvoyé est la suivante : après le nom de la fonction, après les parenthèses, ajoutez un signe deux-points, un espace, puis le mot cléInt
comme type de retour de la fonction. La définition de votre fonction doit ressembler à l'exemple de code ci-dessous.
fun roll(): Int {
- Exécutez ce code. Une erreur s'affiche dans la Problems View (Vue des problèmes). Le message indique :
A ‘return' expression required in a function with a block body (‘{...}')
Vous avez modifié la définition de la fonction pour qu'elle renvoie Int
, mais le système rapporte que votre code ne renvoie pas un nombre Int
. Les éléments "block body" ou "function body" (corps du bloc, ou de la fonction) désignent le code placé entre les accolades d'une fonction. Vous pouvez corriger cette erreur en renvoyant une valeur à partir d'une fonction à l'aide d'une instruction return
à la fin du corps de la fonction.
- Dans
roll()
, supprimez l'instructionprintln()
et remplacez-la par une instructionreturn
pourrandomNumber
. Votre fonctionroll()
devrait ressembler au code ci-dessous.
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
- Dans
main()
, supprimez l'instruction d'impression des faces du dé. - Ajoutez une instruction pour afficher la valeur de
sides
et dediceRoll
dans une phrase informative. Votre fonctionmain()
terminée devrait ressembler au code ci-dessous.
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
- Exécutez votre code pour obtenir le résultat suivant :
Your 6 sided dice rolled 4!
Voici l'ensemble de votre code à ce stade.
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..6).random()
return randomNumber
}
}
5. Modifier le nombre de faces de votre dé
Tous les dés n'ont pas six faces ! Il existe toutes sortes des dés : 4, 8 et même jusqu'à 120 faces !
- Dans la méthode
roll()
de votre classeDice
, modifiez la plage1..6
codée en dur pour utilisersides
à sa place. Ainsi, la plage (et donc, le nombre aléatoire généré), correspondra toujours au nombre de faces.
val randomNumber = (1..sides).random()
- Dans la fonction
main()
, en dessous et après l'impression du résultat du dé, remplacez la valeursides
demyFirstDice
par 20.
myFirstDice.sides = 20
- Copiez et collez l'instruction d'impression ci-dessous après avoir modifié le nombre de côtés.
- Remplacez l'impression de
diceRoll
par le résultat de l'appel de la méthoderoll()
surmyFirstDice
.
println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
Votre programme doit se présenter comme suit :
fun main() {
val myFirstDice = Dice()
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
myFirstDice.sides = 20
println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
}
class Dice {
var sides = 6
fun roll(): Int {
val randomNumber = (1..sides).random()
return randomNumber
}
}
- Exécutez votre programme. Vous devriez voir un message pour le dé à 6 faces et un autre pour le dé à 20 faces.
Your 6 sided dice rolled 3! Your 20 sided dice rolled 15!
6. Personnaliser vos dés
Le rôle d'une classe est de représenter une chose, souvent un objet physique du monde réel. Dans le cas présent, la classe Dice
représente un dé physique. Dans le monde réel, le nombre de faces d'un dé ne change pas. Si vous voulez un nombre différent de faces, vous devez utiliser un autre dé. En programmation, cela signifie qu'au lieu de modifier la propriété des faces d'une instance d'objet Dice
existante, vous devez créer une instance d'objet "dé" avec le nombre de faces dont vous avez besoin.
Dans cette tâche, vous allez modifier la classe Dice
afin de spécifier le nombre de faces lorsque vous créez une instance. Modifiez la définition de la classe Dice
afin de fournir le nombre de faces. Cette opération ressemble à la manière dont une fonction peut accepter des arguments en entrée.
- Modifiez la définition de la classe
Dice
afin d'accepter un entier appelénumSides
. Le code interne de votre classe ne change pas.
class Dice(val numSides: Int) {
// Code inside does not change.
}
- Dans la classe
Dice
, supprimez la variablesides
, puisque vous utiliserez désormaisnumSides
. - Corrigez également la plage de sorte à utiliser
numSides
.
Votre classe Dice
devrait se présenter comme suit :
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
Si vous exécutez ce code, vous verrez beaucoup d'erreurs, car vous devez mettre à jour main()
pour prendre en compte les modifications apportées à la classe Dice
.
- Dans
main()
, pour créermyFirstDice
avec six faces, vous devez désormais indiquer le nombre de côtés en tant qu'argument pour la classeDice
, comme indiqué ci-dessous.
val myFirstDice = Dice(6)
- Dans l'instruction d'impression, remplacez
sides
parnumSides
. - En dessous, supprimez le code qui fait passer
sides
à 20, car cette variable n'existe plus. - Supprimez également l'instruction
println
située en dessous.
Votre fonction main()
devrait ressembler à l'exemple de code ci-dessous, et ne générer aucune erreur lorsque vous l'exécutez.
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
}
- Après avoir imprimé le premier lancer de dé, ajoutez du code pour créer et imprimer un second objet
Dice
appelémySecondDice
, avec 20 faces.
val mySecondDice = Dice(20)
- Ajoutez une instruction d'impression qui génère et affiche la valeur renvoyée.
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
- Votre fonction
main()
terminée devrait se présenter comme suit.
fun main() {
val myFirstDice = Dice(6)
val diceRoll = myFirstDice.roll()
println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
val randomNumber = (1..numSides).random()
return randomNumber
}
}
- Exécutez votre programme terminé. Vous devriez obtenir le résultat suivant :
Your 6 sided dice rolled 5! Your 20 sided dice rolled 7!
7. Adopter les bonnes pratiques de codage
En programmation, la concision est une vertu. Vous pouvez vous débarrasser de la variable randomNumber
et renvoyer directement le nombre aléatoire.
- Modifiez l'instruction
return
de sorte à renvoyer directement le nombre aléatoire.
fun roll(): Int {
return (1..numSides).random()
}
Dans la deuxième instruction d'impression, placez l'appel afin d'obtenir le nombre aléatoire dans le modèle de chaîne. Vous pouvez vous débarrasser de la variable diceRoll
en procédant de la même manière dans la première instruction d'impression.
- Appelez
myFirstDice.roll()
dans le modèle de chaîne, puis supprimez la variablediceRoll
. Les deux premières lignes de votre codemain()
se présentent maintenant comme suit.
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
- Exécutez votre code. Le résultat ne devrait pas être différent.
Vous faites la même chose lorsque vous refactorisez votre code.
fun main() {
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
8. Code de solution
fun main() {
val myFirstDice = Dice(6)
println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
val mySecondDice = Dice(20)
println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}
class Dice (val numSides: Int) {
fun roll(): Int {
return (1..numSides).random()
}
}
9. Résumé
- Vous avez appelé la fonction
random()
sur une plageIntRange
pour générer un nombre aléatoire :(1..6).random()
- Les classes sont comme le schéma de construction d'un objet. Elles peuvent avoir des propriétés et des comportements, qui sont implémentés en tant que variables et fonctions.
- Une instance de classe représente un objet, souvent un objet physique, tel qu'un dé. Vous pouvez appeler les actions sur l'objet et en modifier les attributs.
- Vous pouvez fournir des valeurs à une classe lorsque vous créez une instance. Par exemple :
class Dice(val numSides: Int)
, puis créer une instance avecDice(6)
. - Les fonctions peuvent renvoyer un élément. Spécifiez le type de données à renvoyer dans la définition de la fonction, et utilisez une instruction
return
dans le corps de la fonction ("function body") pour renvoyer un élément. Exemple :fun example(): Int { return 5 }
10. En savoir plus
11. Pour s'entraîner
Action à effectuer :
- Donnez à votre classe
Dice
un autre attribut de couleur et créez plusieurs instances de dé avec un nombre différent de faces et différentes couleurs. - Créez une classe
Coin
(pièce), donnez-lui la possibilité de tomber sur l'un ou l'autre de ses côtés, créez une instance de la classe, puis lancez votre pièce ! Comment utiliseriez-vous la fonctionrandom()
avec une plage pour tirer à pile ou face ?