TP : recopier un mot afficher dans un label

Bon alors voilà. Je voulais tenter un truc qui me semblait tout simple :
1- soit une liste de mots dans un tableau
2- on en prend un au hasard que l’on affiche dans un label
3- l’utilisateur le recopie dans un textField : si ok…
5- … on prend un autre mot au hasard dans le tableau

Dans un playground, ca donne un truc comme ca :

//: Playground - noun: a place where people can play

import UIKit

let liste1 = [« boire », « ou », « conduire », « il », « faut », « choisir »]

var motUtilisateur = « boire »

let motAuHasard = liste1[Int(arc4random_uniform(UInt32(liste1.count)))] //renvoie un mot au hasard du tableau liste 1

print(motAuHasard)

if motUtilisateur == motAuHasard {
print(« Bravo ! »)
} else {
print(« Non ! recommence »)
}

Mais lorsque je je veux l’intégrer dans un projet, ca plante :frowning:
L’idée, c’est qu’au chargement l’appli affiche un premier mot prit au hasard. puis l’utilisateur le recopie…

Mmh je dirai que comme tu as déclarer ta variable “motAuHasard” dans le viewDidLoad(), elle n’existe que dans le viewDidLoad() (portée des variables), donc, dans la fonction “validationBouton”, il ne connait pas cette variable (d’où le “Use of unresolved identifier”).

Pour rectifier cela, il faudrait que tu déclares ta variables “motAuHasard” en dehors du viewDidLoad().

Par exemple:

var motAuHasard:String = ""

override func viewDidLoad() {
    // ...
    motAuHasard = liste1[Int(arc4random_uniform(UInt32(liste1.count)))]
    // ...
}

et à partir de ce moment là, tu pourras utiliser ta variable dans ta fonction validationBouton.

1 « J'aime »

Je suis du même avis qu’Alexandre. Cela ne risque pas de fonctionner, si tu n’archives pas ton mot aléatoire dans une variable commune à toutes les fonctions du ViewController.

Tu devrais écrire une fonction générique pour simplifier ton code.

func motAuHasard(_ liste:[String]) -> String {
        return liste[Int(arc4random_uniform(UInt32(liste.count)))]
}

Cela « isole » ton code utilisateur de la partie compliqué (la génération du mot aléatoire), et permet d’utiliser plusieurs listes facilement.

let motHasard = motAuHasard(liste1)
let autreMot = motAuHasard(liste2)

1 « J'aime »

@Alexandre
J’avais d’abord mis les lignes de code pour générer le mot au hasard juste sous la ligne

class ViewController: UIViewController {

en me disant effectivement qu’ainsi motAuHasard serait reconnu partout. Mais j’avais tout de même une erreur sur motAuHasard dans validationBouton

Est-ce que tu sais nous dire quelle erreur tu avais? Que l’on puisse essayer de t’aider? :slight_smile:

Soit j’ai une « expected » …

soit un « cannot use instance… »

@Draken
J’essaie aussi avec la fonction :wink:

EDIT
Si je détermine le mot au hasard sous la fonction ce la ne fonctionne pas, mais si je le fais dans la func validationButton, c’est ok.
Problème, à ce moment là, le contenu entré par l’utilisateur ne correspondra jamais au mot affiché au hasard (d’ou la nécessité d’avoir déjà un mot affiché avant que l’utilisateur n’appuie sur « valider ») puisque celui-ci change avec l’appui sur le bouton « valider » donc on a la séquence :
1- un mot affiché
2- l’utilisateur le recopie
3- appui sur valider
4- le mot affiché change
5- le prg compare le mot affiché avec le mot entré par l’utilisateur
6- les 2 ne correspondent donc pas

Ton erreur Expected declaration vient du fait que tu as tapé du code dans un endroit où il ne doit y avoir que des déclarations de variables. Les lignes de code ne peuvent se trouver quand dans une fonction !

On peut quand même utiliser du code à l’extérieur, mais uniquement pour initialiser une variable, comme ça :

class ViewController: UIViewController {

// DECLARATION DE VARIABLES
let liste = ["L'hiver", "arrive", "les", "Marcheurs", "Blancs", "ont", "passés", "le", "Mur" ]
var motAuHasard = liste[Int(arc4random_uniform(UInt32(liste.count)))]

// Initialisation du ViewController
override func viewDidLoad() {
    super.viewDidLoad()
} 

}

Alors que ça, non :

class ViewController: UIViewController {
    
    // DECLARATION DE VARIABLES
    let liste = ["L'hiver", "arrive", "les", "Marcheurs", "Blancs", "ont", "passés", "le", "Mur" ]
    var motAuHasard = ""
    // Cette ligne est du code, Xcode refuse de l'exécuter à cet endroit
    motAuHasard = liste[Int(arc4random_uniform(UInt32(liste.count)))]

    // Initialisation du ViewController
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

Moi j’aurais écrit :

class ViewController: UIViewController {
    
    // DECLARATION DE VARIABLES
    let liste = ["L'hiver", "arrive", "les", "Marcheurs", "Blancs", "ont", "passés", "le", "Mur" ]
    var motAuHasard = ""

    // Initialisation du ViewController
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // LIGNE DE CODE (UNIQUEMENT DANS LE CORPS D'UNE FONCTION)
        motAuHasard = tirerMotAuHasard(liste)
    }
    
    // Fonction utilitaire
    func tirerMotAuHasard(_ liste:[String]) -> String {
        return liste[Int(arc4random_uniform(UInt32(liste.count)))]
    }

}
1 « J'aime »

Tu continues à avoir de mauvaises habitudes hérités de Playground.

LES LIGNES DE CODES DOIVENT TOUJOURS SE TROUVER DANS UNE FONCTION !

let motHasard = motAuHasard(liste1)
randomWorlLabel.text = motAuHasard

Ces deux lignes doivent êtres placées dans le corps de la fonction ViewDidLoad(), pas se balader dans le vide.

EDIT : Je n’ai pas le temps maintenant, je te donne un exemple opérationnel ce soir.

1 « J'aime »

Merci pour ton aide.
Le code qui fonctionne :

Par contre : ca c’est ok

func tirerMotAuHasard(_ liste:[String]) -> String {
        return liste[Int(arc4random_uniform(UInt32(liste.count)))]
    }
    
    motAuHasard = tirerMotAuHasard(liste)

    randomWordLabel.text = motAuHasard

Mais ca, ca plante :

motAuHasard = tirerMotAuHasard(liste)

    randomWordLabel.text = motAuHasard
    
    func tirerMotAuHasard(_ liste:[String]) -> String {
        return liste[Int(arc4random_uniform(UInt32(liste.count)))]
    }

J’avais cru comprendre que l’emplacement de la fonction importait peu, que le programme allait la retrouver, peu importe sa position dans le code…

Oui, si tu mets ta fonction “tirerMotAuHasard()” en dehors de ton viewDidLoad() comme ça:

override func viewDidLoad() {
     motAuHasard = tirerMotAuHasard(liste)
     randomWordLabel.text = motAuHasard
}

func tirerMotAuHasard(_ liste:[String]) -> String {
    return liste[Int(arc4random_uniform(UInt32(liste.count)))]
}

Oui, j’ai bien fait attention, et il y a une erreur avec tirerMotAuHasard.
Enfin, c’est pas grave, je remets la fonction avant et ca marche.

Afin que le mot de la liste ne soit plus proposé, je souhaite le retirer du tableau :
1- soit en utilisant son index avec la syntaxe : liste.remove(at : index)

Mais comment retrouver l’index à partir de la fonction ?

func tirerMotAuHasard(_ liste:[String]) -> String {
        return liste[Int(arc4random_uniform(UInt32(liste.count)))]
    }

2- soit peut être en utilisant directement la valeur liste. Mais avec quelle syntaxe ?

D’autres le confirmeront, mais je ne pense pas que mettre une fonction dans le viewDidLoad() soit une bonne idée.

Dans ta fonction:

func tirerMotAuHasard(_ liste:[String]) -> String {
    return liste[Int(arc4random_uniform(UInt32(liste.count)))]
}

“Int(arc4random_uniform(UInt32(liste.count)))” retourne un nombre aléatoire: celui qui choisira le mot dans ta liste, donc en faisant:

func tirerMotAuHasard(_ liste:[String]) -> String {
    let index:Int = Int(arc4random_uniform(UInt32(liste.count)))  // L'index de ton mot
    return liste[index]
}

Aïe !

Avec la dernière capture d’écran que tu as envoyé, tu as toujours la fonction “tirerMotAuHasard” dans ton viewDidLoad() et en plus, tu l’as ajouté dans ton action “validationButton”

Au lieu de ne la mettre qu’une seule fois, en dehors de toute fonction.

Lorsqu’un mot à été correctement recopié, il doit en proposer un autre.
Donc j’appelle la fonction. Mais si elle n’y est pas, j’ai l’erreur “Use of unresolved identifier ‘tirerMotAuHasard’”. C’est pourquoi je l’ai remise

Idem pour la fonction dans le viewDidLoad…

Je ne sais pas comment faire

Essaye comme ça:

@IBOutlet weak var validationButton (_sender: Any) {
    // Ton traitement, en retirant la fonction "tirerMotAuHasard"
}

override func viewDidLoad() {
    // Ton traitement, en retirant la fonction "tirerMotAuHasard"
}

func tirerMotAuHasard(_ liste:[String]) -> String {
    // Ton traitement
}

Ca devrait fonctionner

1 « J'aime »

Effectivement, ca fonctionne, merci beaucoup.

Donc une fonction peut se mettre dans le viewController avec les variables. (si je la mets tout en haut, ca fonctionne tout pareil.)

Je dirai même: il FAUT la mettre au même niveau que les déclarations de tes variables, ainsi, la fonction est disponible dans tout ton viewController, et pas uniquement dans ton viewDidLoad ou autre :slight_smile: