Classes et instances d'objet en langage Kotlin

Pour les ateliers de programmation de ce parcours, vous allez créer une application Android Jeu de dés. Lorsque l'utilisateur lance les dés, un résultat aléatoire est généré. Le résultat tient compte du nombre de dés. Par exemple, seules les valeurs comprises entre 1 et 6 peuvent être lancées depuis un dé à six côtés.

Voici à quoi ressemblera l'application finale.

Afin de vous concentrer sur les nouveaux concepts de programmation pour cette application, vous allez utiliser l'outil de programmation Kotlin basé sur un navigateur pour créer les principales fonctionnalités de l'application. Le programme affiche vos résultats dans la console. Vous implémenterez l'interface utilisateur dans Android Studio plus tard.

Dans ce premier atelier de programmation, vous allez créer un programme Kotlin qui simule un lancer de dés et génère un nombre aléatoire, comme un dés.

Prerequisites

  • Ouvrir, modifier et exécuter du code sur la page https://try.kotlinlang.org/
  • Créez et exécutez un programme Kotlin qui utilise des variables et des fonctions, puis affiche un résultat dans la console.
  • Mettez en forme les nombres dans le texte à l'aide d'un modèle de chaîne avec la notation ${variable}.

Points abordés

  • Comment générer des nombres aléatoires pour simuler des rouleaux de dés ?
  • Structurer votre code en créant une classe Dice avec une variable et une méthode
  • Créer une instance d'objet d'une classe, modifier ses variables et appeler ses méthodes

Ce que vous allez faire

  • Programme Kotlin dans l'outil de programmation Kotlin basé sur un navigateur capable d'effectuer un lancer de dés aléatoire.

Ce dont vous avez besoin

  • Un ordinateur avec connexion Internet

Les jeux présentent souvent un élément aléatoire. Vous pouvez gagner un prix au hasard ou progresser un nombre de pas aléatoire sur le plateau de jeu. Dans la vie de tous les jours, les mots de passe aléatoires permettent de générer des mots de passe plus sûrs.

Au lieu de lancer les dés, vous pouvez écrire un programme qui simule les lancers dés. Chaque fois que vous lancez les dés, le résultat peut être n'importe quel nombre compris dans l'intervalle de valeurs possibles. Heureusement, vous n'avez pas à 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, intègrent une fonctionnalité permettant de générer des nombres aléatoires. Dans cette tâche, vous allez utiliser le code Kotlin pour générer un nombre aléatoire.

Configurer votre code de démarrage

  1. Dans un navigateur, ouvrez le site Web https://try.kotlinlang.org/.
  2. Supprimez l'intégralité du 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 les ateliers de programmation précédents (voir Écrire votre premier programme Kotlin).
fun main() {

}

Utiliser la fonction aléatoire

Pour lancer un dé, vous devez représenter toutes les valeurs possibles. Pour un dé à 6 côtés, les dés lancers peuvent être les suivants: 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 et représente une plage de nombres entiers allant d'un point de départ à un point de terminaison. IntRange est un type de données adapté pour représenter les valeurs possibles d'un dés.

  1. Dans votre fonction main(), définissez une variable sous forme de val appelée diceRange. Attribuez-le à un IntRange de 1 à 6, qui représente la plage d'entiers qu'un dé à six côtés peut lancer.
val diceRange = 1..6

Vous pouvez dire que 1..6 est une plage Kotlin, car elle comporte un numéro de début, deux points, suivis d'un numéro de fin (sans espaces entre les deux). Autres exemples de plages d'entiers : 2..5 pour les nombres compris entre 2 et 5, et 100..200 pour les nombres compris entre 100 et 200.

De la même manière que l'appel de println() indique au système d'imprimer le texte donné, vous pouvez utiliser une fonction appelée random() pour générer et renvoyer un nombre aléatoire pour une plage donnée. Comme auparavant, vous pouvez stocker le résultat dans une variable.

  1. Dans main(), définissez une variable sous forme de val appelée randomNumber.
  2. Utilisez randomNumber comme valeur du résultat d'appel de random() sur la plage diceRange, comme illustré ci-dessous.
 val randomNumber = diceRange.random()

Notez que vous appelez random() sur diceRange à l'aide d'un point ou d'un point, entre la variable et l'appel de fonction. Vous pouvez lire ceci en : générant un nombre aléatoire à partir de diceRange&. Le résultat est ensuite stocké dans la variable randomNumber.

  1. Pour connaître votre nombre généré de manière aléatoire, utilisez le format de chaîne de chaîne (également appelé &modèle de chaîne${randomNumber}) afin de l'imprimer, comme illustré ci-dessous.
println("Random number: ${randomNumber}")

Votre code, une fois fini, doit ressembler à ceci.

fun main() {
    val diceRange = 1..6
    val randomNumber = diceRange.random()
    println("Random number: ${randomNumber}")
}
  1. Exécutez votre code plusieurs fois. Chaque fois, vous devez obtenir le résultat suivant, avec des nombres aléatoires différents.
Random number: 4

Lorsque vous lancez des dés, ils sont de véritables objets entre vos mains. Le code que vous venez d'écrire fonctionne parfaitement, mais il est difficile de le comprendre. Pour simplifier la compréhension d'un programme, vous devez ressembler à ce qu'il représente. Il serait donc intéressant de pouvoir lancer ce programme.

Les dés fonctionnent de la même manière. Ils ont les mêmes propriétés (des côtés, par exemple) et ont le même comportement (par exemple, ils peuvent être roulés). En langage Kotlin, vous pouvez créer un plan programmatique d'un dé indiquant qu'il y a des côtés et qu'il peut lancer un nombre aléatoire. Ce plan est appelé classe.

Depuis cette classe, vous pouvez ensuite créer des objets de dés, appelés instances d'objet. Par exemple, vous pouvez créer un dé à 12 côtés ou 4 côtés.

Définir une classe de dés

Dans les étapes suivantes, vous allez définir une nouvelle classe appelée Dice pour représenter un dé roulable.

  1. Pour recommencer, effacez le code de la fonction main() pour obtenir le code comme indiqué ci-dessous.
fun main() {

}
  1. Sous cette fonction main(), ajoutez une ligne vide, puis ajoutez du code pour créer la classe Dice. Comme indiqué ci-dessous, commencez par le mot clé class, suivi du nom de la classe, puis d'une accolade ouvrante ou fermante. Laissez l'espace entre les accolades pour insérer votre code pour la classe.
class Dice {

}

Dans une définition de classe, vous pouvez spécifier une ou plusieurs propriétés pour la classe à l'aide de variables. Les dés peuvent avoir plusieurs côtés, une couleur ou un poids. Dans cette tâche, vous allez vous concentrer sur la propriété du nombre de côtés des dés.

  1. Dans la classe Dice, ajoutez un var appelé sides pour le nombre de côtés qu'il y aura. Définissez sides sur 6.
class Dice {
    var sides = 6
}

Et voilà ! Vous disposez à présent d'une classe très simple représentant les dés.

Créer une instance de la classe "Dés"

Avec cette classe Dice, vous disposez d'un plan sur les dés. Pour inclure un dé dans 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 instances d'objet).

  1. Pour créer une instance d'objet Dice, utilisez la fonction main(), créez un val appelé myFirstDice et initialisez-le en tant qu'instance de la classe Dice. Notez les parenthèses après le nom de la classe, qui indique que vous créez une instance d'objet à partir de cette classe.
fun main() {
    val myFirstDice = Dice()
}

Maintenant que vous disposez d'un objet myFirstDice, créé à partir du plan, vous pouvez accéder à ses propriétés. La seule propriété de Dice est sa sides. Pour accéder à une propriété, utilisez la notation &dott. Par conséquent, pour accéder à la propriété sides de myFirstDice, vous appelez myFirstDice.sides, qui est prononcé myFirstDice, point sides.

  1. Sous la déclaration de myFirstDice, ajoutez une instruction println() pour générer le nombre de sides de myFirstDice.
println(myFirstDice.sides)

Votre code doit se présenter comme suit :

fun main() {
    val myFirstDice = Dice()
    println(myFirstDice.sides)
}

class Dice {
    var sides = 6
}
  1. Exécutez votre programme. Le nombre de valeurs sides défini dans la classe Dice doit être généré.
6

Vous disposez à présent d'une classe Dice et d'un dé réel myFirstDice avec 6 sides.

C'est l'heure de lancer les dés !

Lancer de dés

Vous avez déjà utilisé une fonction pour effectuer l'impression des calques de gâteaux. Le lancer de dés est également une action qui peut être implémentée en tant que fonction. Étant donné que tous les dés peuvent être lancés, vous pouvez ajouter une fonction pour cette classe dans la classe Dice. Une fonction définie dans une classe est également appelée méthode.

  1. Dans la classe Dice, sous la variable sides, insérez une ligne vide, puis créez une fonction pour lancer les dés. Commencez par le mot clé Kotlin fun, suivi du nom de la méthode, suivi des parenthèses (), puis des accolades ouvrantes et fermantes de {}. Vous pouvez insérer une ligne entre les accolades pour laisser plus de place pour le code, comme illustré ci-dessous. Votre classe doit se présenter comme suit :
class Dice {
    var sides = 6

    fun roll() {

    }
}

Lorsque vous lancez un dé six côtés, un nombre aléatoire compris entre 1 et 6 est généré.

  1. Dans la méthode roll(), créez un val randomNumber. Attribuez-lui un nombre aléatoire dans la plage 1..6. Utilisez la notation à points pour appeler random() sur la plage.
val randomNumber = (1..6).random()
  1. Une fois le nombre aléatoire généré, imprimez-le dans la console. Votre méthode roll() terminée devrait ressembler à l'exemple de code ci-dessous.
fun roll() {
     val randomNumber = (1..6).random()
     println(randomNumber)
}
  1. Pour lancer myFirstDice, dans main(), appelez la méthode roll() sur myFirstDice. Vous appelez une méthode à l'aide de la notation &dott. Par conséquent, pour appeler la méthode roll() de myFirstDice, vous allez saisir myFirstDice.roll(), qui est prononcé "myFirstDice point, roll().
myFirstDice.roll()

Votre code final 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)
    }
}
  1. Exécutez votre code ! Vous devriez voir un résultat indiquant un dés aléatoire sous le nombre de côtés. Exécutez votre code plusieurs fois et notez que le nombre de ses côtés reste le même, et que la valeur du dé 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() sur celle-ci pour générer un nombre aléatoire.

Vous imprimez actuellement la valeur de randomNumber dans votre fonction roll(), et cela fonctionne très bien. Toutefois, il est parfois plus utile de renvoyer le résultat d'une fonction à ce que l'on appelle la fonction. Par exemple, vous pouvez attribuer le résultat de la méthode roll() à une variable, puis déplacer un joueur de cette valeur. Voyons comment cela s'est produit.

  1. Dans main(), modifiez la ligne myFirstDice.roll(). Créez un val appelé diceRoll. Définissez-la sur la valeur renvoyée par la méthode roll().
val diceRoll = myFirstDice.roll()

Cette opération n'a encore rien fait, car roll() ne renvoie rien pour le moment. 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 deviez spécifier un type de données pour les arguments d'entrée des fonctions. De la même manière, vous devez spécifier un type de données pour chaque fonction renvoyée.

  1. Modifiez la fonction roll() pour spécifier le type de données à afficher. Dans ce cas, le nombre aléatoire est Int. Le type renvoyé est donc Int. 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 pour le type renvoyé. La définition de la fonction doit ressembler à ce qui suit.
fun roll(): Int {
  1. Exécutez ce code. Une erreur s'affiche dans la vue des problèmes. Son contenu:
A ‘return'  expression is required in a function with a block body. 

Vous avez modifié la définition de la fonction pour qu'elle renvoie une erreur Int, mais le système se plaint que

ne renvoie pas de Int. "Bloquer le corps" ou "corps de la fonction" désigne le code entre les accolades d'une fonction. Vous pouvez corriger cette erreur en renvoyant une valeur d'une fonction à l'aide d'une instruction return à la fin du corps de la fonction.

  1. Dans roll(), supprimez l'instruction println() et remplacez-la par une instruction return pour randomNumber. Votre fonction roll() devrait se présenter comme suit :
fun roll(): Int {
     val randomNumber = (1..6).random()
     return randomNumber
}
  1. Dans main(), retirez la déclaration d'impression pour les côtés des dés.
  2. Ajoutez une instruction pour imprimer la valeur de sides et diceRoll dans une phrase informative. Votre fonction main() terminée devrait ressembler à ce qui suit.
fun main() {
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
  1. Exécutez votre code pour obtenir le résultat suivant :
Your 6 sided dice rolled 4!

Voici l'intégralité de votre code jusqu'à présent.

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
    }
}

Tous les dé n'ont pas six côtés ! Il existe des formes et des tailles de dés différentes: 4 côtés, 8 côtés et 120 côtés !

  1. Dans votre classe Dice, dans votre méthode roll(), modifiez la valeur 1..6 codée en dur pour utiliser sides, de sorte que la plage, et donc le nombre aléatoire roulé, soit toujours adaptée au nombre de côtés.
val randomNumber = (1..sides).random()
  1. Dans la fonction main(), en dessous et après l'impression des dés, remplacez sides par FirstDice sur 20.
myFirstDice.sides = 20
  1. Copiez et collez la déclaration d'impression existante ci-dessous après avoir modifié le nombre de côtés.
  2. Remplacez l'impression de diceRoll par l'impression du résultat de l'appel de la méthode roll() sur myFirstDice.
println("Your ${myFirstDice.sides} sided dice has rolled a ${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
    }
}
  1. Exécutez votre programme, et un message concernant les dés à 6 côtés s'affichera, puis un deuxième pour les 20 côtés.
Your 6 sided dice rolled 3!
Your 20 sided dice rolled 15!

L'idée d'une classe est de représenter une chose, souvent quelque chose de physique, dans le monde réel. Dans ce cas, une classe Dice représente un dé physique. En réalité, les dés ne peuvent pas changer le nombre de côtés. Si vous voulez un nombre différent de côtés, vous devez obtenir un dé. Par programmation, cela signifie qu'au lieu de modifier la propriété"sides"d'une instance d'objet Dice existante, vous devez créer une instance d'objet de dés avec le nombre de côtés dont vous avez besoin.

Dans cette tâche, vous allez modifier la classe Dice pour pouvoir spécifier le nombre de côtés lorsque vous créez une instance. Modifiez la définition de la classe Dice pour accepter un argument pour le nombre de côtés. Cette fonction est semblable à celle permettant à une fonction d'accepter des arguments en entrée.

  1. Modifiez la définition de la classe Dice pour accepter un argument entier appelé numSides. Le code intégré à votre classe ne change pas.
class Dice(val numSides: Int) {
   // Code inside does not change.
}
  1. Dans la classe Dice, supprimez la variable sides, car vous pouvez désormais utiliser numSides.
  2. Corrigez également la plage pour 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, de nombreuses erreurs s'affichent, car vous devez mettre à jour main() pour appliquer les modifications à la classe Dice.

  1. Dans main(), pour créer myFirstDice avec six côtés, vous devez désormais transmettre le nombre de côtés en tant qu'argument à la classe Dice, comme indiqué ci-dessous.
    val myFirstDice = Dice(6)
  1. Dans le relevé d'impression, remplacez sides par numSides.
  2. En dessous, supprimez le code qui remplace sides par 20, car cette variable n'existe plus.
  3. Supprimez également l'instruction println située en dessous.

Votre fonction main() devrait se présenter comme suit : si vous l'exécutez, aucune erreur ne doit apparaître.

fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
}
  1. Après avoir imprimé le premier lancer de dés, ajoutez du code pour créer et imprimer un second objet Dice appelé mySecondDice avec 20 côtés.
    val mySecondDice = Dice(20)
  1. Ajoutez une instruction d'impression qui roule et imprime la valeur renvoyée.
println("Your ${mySecondDice.numSides} sided dice rolled  ${mySecondDice.roll()}!")
  1. Votre fonction main() terminée devrait ressembler à ceci.
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
    }
}
  1. Exécutez votre programme terminé, et vous devriez obtenir le résultat suivant :
Your 6 sided dice rolled 5!
Your 20 sided dice rolled 7!

Il est préférable de rédiger un code concis. Vous pouvez supprimer la variable randomNumber et renvoyer le nombre aléatoire directement.

  1. Modifiez l'instruction return pour qu'elle renvoie directement le nombre aléatoire.
    fun roll(): Int {
        return (1..numSides).random()
    }

Dans la deuxième instruction d'impression, vous placez l'appel pour 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.

  1. Appelez myFirstDice.roll() dans le modèle de chaîne et supprimez la variable diceRoll. Les deux premières lignes de votre code "main()" se présentent maintenant comme suit :
    val myFirstDice = Dice(6)
    println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
  1. Exécutez votre code. Le résultat ne devrait pas être différent.

Il s'agit de votre code final après refactorisation .

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()
    }
}
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 {
        return (1..numSides).random()
    }
}
  • Appelez la fonction random() sur un IntRange pour générer un nombre aléatoire : (1..6).random()
  • Les classes sont comme les plans d'un objet. Des propriétés et des comportements peuvent être implémentés en tant que variables et fonctions.
  • Une instance d'une classe représente un objet, souvent un objet physique, tel qu'un dé. Vous pouvez appeler les actions sur l'objet et modifier ses attributs.
  • Vous pouvez transmettre une entrée à une classe lorsque vous créez une instance en spécifiant un argument pour la définition de classe. Par exemple, class Dice(val numSides: Int), puis créer une instance avec Dice(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 pour renvoyer un élément. Par exemple : fun example(): Int { return 5 }

Procédez comme suit :

  • Donnez à votre classe Dice un autre attribut de couleur et créez plusieurs dés avec différents nombres de côtés et de couleurs différents.
  • Créez une classe Coin, donnez-lui la possibilité de retourner de la pièce, créez une instance de la classe et gagnez des pièces. Comment utiliser la fonction aléatoire() avec une plage pour effectuer un tirage au sort ?