Dictionnaire : je m'embrouille


#1

J’ai cette fonction qui me permet d’obtenir une clé au hasard du dictionnaire level :

func afficherImage() {
    
        if let elementAuHasardDuDictionnaire = level.randomElement()?.key {
            
            elementAffiche = level[elementAuHasardDuDictionnaire]!

            produitImageView.image = UIImage(named : elementAuHasardDuDictionnaire)
         
        }

Mais je n’arrive pas à sortir cette clé de cette fonction pour la réutiliser dans cette autre fonction :

 func verifierReponse() {
    if let reponse = reponseTextField.text {
        
        let reponseAttendue = String(elementAffiche)
        
        if reponse == reponseAttendue {
        //code permettant de retirer la bonne réponse du tableau
            
        //level = level.filter {$0.key != String(reponseAttendue)}
            
            level = level.filter {$0.value != Int(reponseAttendue)}

Merci pour votre aide.


#2

Je crois qu’il faut reprendre le problème à la base, sans penser “technologie et codage”.

Si je comprend bien tu veux réaliser un Quizz avec des questions aléatoires venant d’une liste. Chaque question posée doit être retiré de la liste.

Une question contient juste un nom d’image et un chiffre. Pas de texte ?

Si c’est bien le cas, l’utilisation d’un dictionnaire n’est pas utile. Un simple tableau peut faire l’affaire, de manière plus efficace.

Je te fais un brouillon technique demain.


#3

Oui pas de texte, une image et un nombre.


#4

Première étape : créer une classe pour gérer les questions

class UneQuestion {
    var image = ""
    var numero = 0
    
    init(numero:Int, image:String) {
        self.image = image
        self.numero = numero
    }
    
}

Ensuite une classe pour gérer une liste de questions, encapsulant un tableau. J’appelle cela un Sac, parce que cela fonctionne exactement comme un sac de billes.

On peut :

  • ajouter une question

  • retirer une question aléatoire (elle est automatiquement effacée du sac)

  • connaître l’état du sac (plein ou vide)

  • connaître le nombre de questions disponibles

      enum EtatSacQuestions {
          case vide
          case plein
      }
    
      class SacDeQuestions {
          private var tableau = [UneQuestion]()
          
          // Lecture du nombre de questions disponibles
          func nombreDeQuestions() -> Int {
              return tableau.count
          }
          
          func etatDuSac() -> EtatSacQuestions {
              if tableau.count == 0 {
                  return .vide
              }
              return .plein
          }
          
          // Ajouter une question dans le sac
          func ajouter(question:UneQuestion) {
              tableau.append(question)
          }
          
          // Retirer une question du sac
          func retirerQuestion() -> UneQuestion? {
              
              // Vérification du nombre de questions disponibles
              let nbQuestions = nombreDeQuestions()
              // Si le sac est vide, on retourne nil
              if nbQuestions == 0 {
                  return nil
              }
              
              // Tirage index aléatoire
              let index = Int.random(in: 0...nbQuestions-1)
              // Lecture question
              let question = tableau[index]
              // On l'efface du Sac
              tableau.remove(at: index)
              
              return question
          }
      }
    

Exemple d’utilisation :

class ViewController: UIViewController {
    
    let sac = SacDeQuestions()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        creerQuestions()
        
        // affichage
        while sac.etatDuSac() == .plein {
            if let question = sac.retirerQuestion() {
                let numero = question.numero
                let image = question.image
                print ("numéro : ", numero, " image : ", image)
            }
        }
        print ("Fin des questions..")
        
    }

    func creerQuestions() {
        sac.ajouter(question: UneQuestion(numero: 12, image: "IMG1"))
        sac.ajouter(question: UneQuestion(numero: 7,  image: "IMG2"))
        sac.ajouter(question: UneQuestion(numero: 5,  image: "IMG3"))
        sac.ajouter(question: UneQuestion(numero: 18, image: "IMG4"))
    }

}

Test :

numéro : 7 image : IMG2

numéro : 18 image : IMG4

numéro : 12 image : IMG1

numéro : 5 image : IMG3

Fin des questions…

Tu peux créer plusieurs sacs pour les différents niveaux de difficulté.

Des questions ?


#5

Merci beaucoup pour cette version experte et merci pour les commentaires intégrés.

Mais je suis loin de tout comprendre, je dois revoir les cours, ceux qui correspondent aux class notaM.

Les questions et les images correspondantes, elles sont stockées dans quelle partie du code ? dans la func creerQuestions() ?

Dans cette fonction, que veut dire le point dans .vide ? .plein ?

func etatDuSac() -> EtatSacQuestions {
      if tableau.count == 0 {
          return .vide
      }
      return .plein
  }

#6

La nature des informations que l’on peut stocker dans une variable dépend de son type : des chaines pour une String, des nombres complexes dans un flottant, une information binaire (oui/non, true/false) dans une BOOL, etc …

L’opérateur enum (comme énumération) permet de créer un type de variable spécialisée ne pouvant contenir qu’un petit nombre d’informations.

C’est très pratique pour mémoriser l’état d’un système ou d’un objet. Exemple pour un objet voiture pouvant prendre 3 états différents :

  enum EtatVoiture {
      case auGarage
      case enPanne
      case surLaRoute
  }

Il suffit de créer une variable de type EtatVoiture pour stocker l’information.

var etatVehiculePapa:EtatVoiture = .auGarage

Cela permet d’écrire un code très lisible, comme :

if etatVehiculePapa == .enPanne {
}

On peut aussi utiliser des entiers pour mémoriser l’état d’un système, mais c’est loin d’être aussi lisible.

// La signification de ce test ne saute pas aux yeux
// à la différence du précédent
if etatVehiculePapa == 1 {
}

De plus, les types de variables personnalisés sont sécurisés, toujours la même obsession des créateurs de Swift. On ne peut y écrire dedans que les valeurs prévues à l’origine, à la différence des entiers qui peuvent contenir n’importe quoi.

Pour en revenir au Sac à questions, j’ai créé un type de variable pour décrire son état.

  enum EtatSacQuestions {
      case vide
      case plein
  }

Je trouve ça plus parlant qu’un true/false classique.

  func etatDuSac() -> EtatSacQuestions {
      if tableau.count == 0 {
          return .vide
      }
      return .plein
  }

La fonction etatDuSac() retourne la valeur .vide si le Sac est vide, et .plein s’il reste encore des questions.

En fait, l’écriture .vide est une abréviation de EtatDuSac.vide. Les premières versions de Swift nécessitaient d’écrire TypeDeVariable.valeur en entier. Heureusement, on peut maintenant se contenter de .valeur, Xcode analysant le contexte pour déterminer le type à prendre en compte.

.


#7

Je ne comprend pas trop ta question. Les questions (numéro et nom des images) sont stockées dans des objets de type UneQuestion, qui sont eux-mêmes stockés dans un objet SacDeQuestion.

La fonction creerQuestions() sert à définir la valeur des paramètres des questions, mais c’est juste un exemple tapé à la vas-vite. On peut utiliser des tas de manières différentes pour définir les questions : une liste de tupple, un fichier de texte, un fichier XML, un outil graphique spécialisé, etc …

C’est clair. C’est la base. Tu codes selon la vieille méthode de grand-mère : la programmation structurée. C’était bien dans les années 70-80. Mais l’émergence de la programmation objet a tout changé. Il faut penser différemment, avec des objets communiquant les uns avec les autres, et non de simples lignes de code.

Ce n’est pas si simple que ça. Moi qui suis un autodidacte n’ayant jamais suivis de cours d’informatique, j’ai eu quelques difficultés à “penser objet”, même si maintenant je serais incapable de faire autrement.


#8

Citation Je ne comprend pas trop ta question. Les questions (numéro et nom des images) sont stockées dans des objets de type UneQuestion , qui sont eux-mêmes stockés dans un objet SacDeQuestion .

Dans ma version basique, le nom des images et les réponses (les questions et leur réponse) sont enregistrées au préalable dans un dictionnaire :

Dans cette version experte, où sont -elles stockées ? où les met-on ?


#9

Oui, dans la fonction creerQuestions(). Les fonctions trop longues sont illisibles et difficiles à comprendre/modifier. Il est préférable de diviser le code en une série de petites fonctions, remplissant chacune une tache bien précise.