Repeat...while avec une fonction

bonsoir
Je ne comprends pas pourquoi la boucle ne fonctionne pas.
Merci pour votre aide

func demandeValeurs() {
let valeur: Int
print("Quelle est votre valeur ?")
valeur = Utilisateur.saisirEntier()
print("Votre valeur est \(valeur)")

}

repeat {

demandeValeurs()

} while Utilisateur.saisirEntier() != 0

Hello,

Et si tu mets ton repeat dans ta fonction demandeValeurs() ou alors dans le ViewDidLoad ?

func demandeValeurs() {
let valeur: Int
print("Quelle est votre valeur ?")
valeur = Utilisateur.saisirEntier()
print("Votre valeur est \(valeur)") 

repeat {
    demandeValeurs()
    } while Utilisateur.saisirEntier() != 0

}

J’avais essayé ça, mais à ce moment là, je n’ai pas de message d’erreur et rien ne se passe : la console ne demande pas d’entrer une valeur.

Ta fonction demandeValeurs() affiche un texte et demande une valeur qui ne sert à RIEN ! Elle n’est pas testée, ni stockée en mémoire, juste affichée une fois. C’est une variable LOCALE, elle est détruite quand le programme sort du corps de la fonction. Pas étonnant que la boucle ne fonctionne pas.

Pour chaque itération de la boucle, ton code consulte le clavier DEUX fois : dans le corps de la fonction demandeValeurs(), et après l’instruction while. Si la valeur 0 est saisie dans la demandeValeurs() l’information est DETRUITE sans être utilisée !

Pour que ton code marche, il faut que demandeValeurs() transmettre l’information au reste de l’application. Le plus simple c’est qu’elle retourne la valeur lue.

func demandeValeurs() -> Int {
  let valeur: Int 
  print("Quelle est votre valeur ?")
  valeur = Utilisateur.saisirEntier()
  print("Votre valeur est \(valeur)")
  return valeur
}

Dans ce cas, la boucle peut être écrite d’une manière très concise :

repeat {
} while demandeValeurs() != 0

Ou dans une version plus verbeuse :

var choix:Int
repeat {
   choix = demandeValeurs()
} while choix != 0

J’ai testé, cela fonctionne. Enfin disons plutôt que j’ai “simulé” la saisie utilisateur. J’ai horreur de playgrounds qui me rappelle mes cauchemars d’enfance avec la ligne de commande de MS-DOS.

Je fait mes petits bricolages avec du vrai code, dans du vrai Xcode. J’ai remplacé la saisie clavier avec une petite routine retournant une valeur aléatoire compris entre 0 et 10.

Voici le code réel que j’ai testé, dans une micro-application iOS :

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        print ("***Début de la boucle")
        
        var choix:Int
        repeat {
            choix = demandeValeur()
        } while choix != 0
        
        print ("***Fin de la boucle")
    }

    // SimulationSaisieUtilisateur
    // Nombre aléatoire compris entre 0 et 9
    func utilisateurSaisieEntier() -> Int {
        return Int(arc4random_uniform(10))
    }

    func demandeValeur() -> Int {
        let valeur:Int
        print ("Quelle est votre valeur ? ")
        valeur = utilisateurSaisieEntier()
        print ("Votre valeur est : ", valeur)
        return valeur
    }
    
}

Exemple de log :

***Début de la boucle
Quelle est votre valeur ? 
Votre valeur est :  3
Quelle est votre valeur ? 
Votre valeur est :  4
Quelle est votre valeur ? 
Votre valeur est :  8
Quelle est votre valeur ? 
Votre valeur est :  0
***Fin de la boucle

Encore une question : je pensais qu’il fallait définir les fonctions en début de code. Or, tu les places après la boucle. Ne serait-il pas plus logique de commencer par définir la fonction demandeValeur() avant de l’utiliser ?
merci

La suite de l’exercice : à la fin de la boucle, il faut afficher le nombre de valeurs divisibles par un nombre donné par l’utilisateur au départ.
J’ai pompé sur Draken pour finir l’exercice, grand merci à lui :+1:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    
    print ("***Début de la boucle")
    
    func demandeValeur() -> Int {
        let valeur:Int
        print ("Quelle est votre valeur ? ")
        valeur = utilisateurSaisieEntier()
        print ("Votre valeur est : ", valeur)
        return valeur
    }
    
    func demandeDiviseur() -> Int {
        let diviseur:Int
        print("Quel est le diviseur ?")
        diviseur = utilisateurSaisieDiviseur()
        print("Votre diviseur est ", diviseur)
    return diviseur
    }
    
    
    // SimulationSaisieDiviseur à tester
    // Nombre aléatoire compris entre 0 et 10
    func utilisateurSaisieDiviseur() -> Int {
        return Int(arc4random_uniform(11))
    }
    
    var choix:Int
    var compteur:Int = 0
    var compteurDiviseur:Int = 0
    var diviseur:Int
    
    diviseur = demandeDiviseur()
    
    repeat {
        choix = demandeValeur()
            if choix % diviseur == 0 {
            compteurDiviseur += 1
        }
        compteur += 1
    } while choix != 0
    
    compteur -= 1
    compteurDiviseur -= 1
    
    print("Tu as entré \(compteur) valeurs.")
    print("Il y avait \(compteurDiviseur) nombres divisibles par \(diviseur).")
    print ("***Fin de la boucle")
}

// SimulationSaisieUtilisateur
// Nombre aléatoire compris entre 0 et 100
func utilisateurSaisieEntier() -> Int {
    return Int(arc4random_uniform(100))
}

}

Dans ta présentation sur CocoaCafé tu as dit que tu étais instituteur. T’aimes bien les math, non ? Et les choses bien ordonnées comme commencer par traiter l’étape 1, avant de passer à l’étape 2, etc …

Dans la nuit des temps, il était nécessaire de définir les fonction dans un ordre précis avant de les utiliser. C’était l’époque des compilateurs mono-passes (comme le Turbo Pascal, un vénérable ancêtre qui a marqué son époque).

On commençait par les primitives, puis les fonctions plus évolués, pour finir par le plus complexe, l’interface avec l’utilisateur. Mais ça c’était avant… Et surtout avant l’apparition des langages objets qui ont complètement chamboulé la manière de programmer.

De nos jours, la position d’une fonction au sein du code n’a aucune importance, d’un point de vue technique. Le compilateur se débrouille pour la retrouver partout. C’est d’autant plus vraie que la « bonne manière » de travailler aujourd’hui c’est d’éclater le code en une multitude de fichiers secondaires. Normalement chaque classe d’une application doit être définie dans son propre fichier.

Ce qui est important c’est d’écrire un code bien structuré où il est facile de retrouver les choses. Et de suivre quelques conventions comme le nommage des variables et des classes, et de placer l’initialisation d’une classe en haut du code. C’est ce que j’ai fait dans ma micro-application de tests, le viewDidLoad() d’un ViewController doit se trouver en haut du code.

Quand tu auras une application réelle dépassant les 1.000 lignes, avec plusieurs dizaines de classes différentes, tu verras que la position d’une méthode par rapport à une autre dans le code sera le cadet de tes soucis.

Ho le vilain copieur … :grin:

Un petit détail, qui peut avoir son importance, dans certains calculs :

// SimulationSaisieUtilisateur
// Nombre aléatoire compris entre 0 et 100
func utilisateurSaisieEntier() -> Int {
    return Int(arc4random_uniform(100))
}

La fonction arc4random_uniform(n) retourne un entier compris entre 0 et n-1. Les informaticiens aiment bien numéroter les choses à partir de 0. Tu as probablement remarqué que les tableaux commencent à l’indice 0, et non 1 comme dans la vraie vie.

arc4random_uniform(100) retourne bien 100 valeurs différentes, mais numérotées de 0 à 99. Si pour une raison quelconque ton code attend la valeur 100, elle ne viendra JAMAIS !

Ce qui compte c’est le moment : lafonction doit être définie au moment où elle est appelée, ce qui n’est pas forcément en rapport avec la hauteur dans le code du programme où sa définition est située ? Je me trompe ?

1 « J'aime »

Oui, c’est bien ça. Une fonction a besoin d’être définie pour taper du code y faisant appel. Mais elle peut se trouver n’importe où dans le corps du programme, y compris dans d’autres fichiers.