IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Scheme Discussion :

Structurer son 1er programme Scheme


Sujet :

Scheme

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2013
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 18
    Par défaut Structurer son 1er programme Scheme
    Hello,
    Je débute en Scheme, et pour mon premier programme -un 'MasterMind'- je n'arrive pas à trouver la bonne structure, le bon découpage - aussi au niveau de l'indentation.
    J'ai essayé plein de commandes mais je suis à peu près que se sont les moins pertinents .
    Je n'arrive pas non plus à comprendre la différence entre 'and' et 'and?', alors que se sont tous les 2 des prédicats, je crois ?
    Et de même pour 'not' et 'not?' ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #lang racket
    ;; Master Mind ;;
    (define nC 8)
    (define lType [list nC nC nC nC])
    (define nMyst (map (lambda (n) (random n)) lType))
    (define (ask)
       (let* ([i (read [current-input-port])])
         (if (and (integer? i)
                  (>= i 0)
                  (< i nC)) i (begin [printf "You must write a number between 0 and ~a\n" (- nC 1)]
                                     (ask)))
        )
       )
    (define (L L1)
      (let* ([ans (list (ask) (ask) (ask) (ask))])
        (list
         (map [lambda (a b) (if (equal? a b) 'T [if [ormap equal? (list a a a a) L1] 'B 'F])] ans L1)
         ans)
        )
      )
    (do ([nT 0 (+ nT 1)]
         [iList (L nMyst) (append (L nMyst) iList)])
      ((equal? (second iList) nMyst) (printf "You win: ~a !!" nMyst))
      (begin
        (printf "Round n°~a, \nF => False \nB => Bad Position \nT => True \nIt is incorrect: \n" nT)
        (for-each (lambda (arg) (printf "~a\n" arg)) iList)
        )
      )
    Merci pour votre aide !

  2. #2
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2013
    Messages : 153
    Par défaut
    Ce programme, qu'est-ce qu'il doit faire exactement ? Quel est l'objectif ?

    Pour indenter le code, le plus important c'est d'utiliser le bon éditeur. DrRacket n'est très avancé, mais au moins il indente proprement. Il ne faut pas laisser une seule parenthèse dans une ligne. Il est plus facile de lire un if si l'on commence une nouvelle ligne pour chaque branche. Il vaut la peine commencer une nouvelle ligne après les macros comme begin aussi, ainsi
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     (begin
       (printf ...)
       ...)
    and? et not? ne font pas partie de la Scheme ordinaire, est-ce que tu es sûr que tu en as besoin ?

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2013
    Messages : 153
    Par défaut
    C'est un bon guide à l'indentation (en anglais) :
    http://dept-info.labri.fr/~strandh/T...dentation.html
    Il s'agit de Common Lisp, mais ce n'est pas important.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2013
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 18
    Par défaut
    Merci d'avoir répondu si vite et 2x qui plus est .

    En fait, le programme choisi 4 chiffres 'Mystères' puis on rentre 4 chiffres, et il compare ces chiffres rentrés aux chiffres 'mystères' puis dit pour chaque chiffres entrés s'il est à la bonne ou mauvaise position ou inexistant par rapport aux chiffres 'mystères'. Et continue ainsi tant que les bons chiffres n'ont pas étés trouvés.
    L'objectif était de tester le langage.

    Comment choisir entre utiliser une boucle 'do' ou une fonction récursive ?

    J'ai ré-indenté conformément -j'espère?- au document:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    #lang racket
    ;; Master Mind ;;
    (define nC 8)
    (define lType [list nC nC nC nC])
    (define nMyst (map (lambda (n) (random n)) lType))
    (define (ask)
      (begin
        [printf "You must write a number between 0 and ~a:\n" (- nC 1)]
        (let* ([i (read [current-input-port])])
          (if (and (integer? i) (>= i 0) (< i nC))
              i
              (ask)))))
    (define (L L1)
      (let* ([ans (list (ask) (ask) (ask) (ask))])
        (list
         (map [lambda (a b) (if (equal? a b) 'T [if [ormap equal? (list a a a a) L1] 'B 'F])] ans L1)
         ans)))
    (do ([nT 0 (+ nT 1)]
         [iList (L nMyst) (append (L nMyst) iList)])
      ((equal? (second iList) nMyst) (printf "You win: ~a !!" nMyst))
      (begin
        (printf "Round n°~a, \nF => False \nB => Bad Position \nT => True \nIt is incorrect: \n" nT)
        (for-each (lambda (arg) (printf "~a\n" arg)) iList)))
    Si j'ai bien compris les prédicats, se sont des fonctions qui retournent un boolean et qui sont différenciées avec '?' à la fin, et donc pourquoi 'not' et 'and' n'ont pas de '?' à leur fins ?

    Je dérive un peu, mais est-il possible d'utiliser différent 'langage' racket dans un même programme ?

  5. #5
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mai 2013
    Messages
    153
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Mai 2013
    Messages : 153
    Par défaut
    Je suppose qu'il est possible d'utiliser langages differents dans modules, mais je ne connais racket bien, il faut voire la documentation.

    Le corps d'une fonction peut être constitué par plusieures formes, alors ce n'est pas indispensable de l'envelopper dans un begin.

    Quant'au do, il n'est presque jamais utilisé en Scheme. On préfère la récursion, souvent en forme d'un « let nommé ».

    On préfère let au let* si l'on n'ont pas besoin de définitions séquentielles.

    L'essence du jeu peut être décomposée en trois parties: 1) la préparation (la génération d'une liste aléatoire), 2) l'entrée d'une réponse; 3) la comparaison de la réponse avec le clé. Ces parties sont indépendentes, alors il vaut la peine de les réaliser d'une façon indépendente.

    C'est la comparaison qui est le noyau du jeu. Etant données deux listes, c'est un algorithme déterministe. Donc, il peut être réalisé comme une fonction pure, c'est-à-dire, une fonction en sens mathématique. C'est bien parce qu'il est plus facile d'écrire telles fonctions et de les tester aussi.

    Je suppose que ta fonction L fait la comparaison. Son défaut principale est le fait qu'elle combine la comparaison avec l'entrée des données et avec l'interface de l'utilisateur.

    C'est une bonne idée d'utiliser un map. Au lieux d'un if intérieur il vaut mieux employer un cond. Cet ormap équivaut à la fonction member. Pour comparer les nombres, on utilise =. Alors, on peut écrire cette fonction comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    (define (compare answer key)
      (map (lambda (a k)
             (cond ((= a k) 't)
                   ((member a key) 'b)
                   (else 'f)))
           answer
           key))
    Maintenant on peut charger cette fonction en lisp et la tester dans le REPL.

    Pour générer le clé aléatoire, on peut utiliser une fonction qui accepte le nombre totale des chiffres et la limite supérieure. C'est raisonnable de définir les paramètres du jeu comme variables globales, mais cette fonction sera plus simple se elle ne les accédera. Il est plus facile de gérer une définition que trois en même temps.

    C'est un peu différente de ce que tu as proposé, mais ton (list nC nC nC nC) ne me dit pas du tout.

    On peut définir cette fonction de cette façon simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    (define (random-list length limit)
      (if (zero? length)
          '()
          (cons (random limit) (random-list (- length 1)))))
    Mais ce n'est pas efficace, parse que la récursion n'est pas terminale. Voici la récursion terminale avec un « let nommé »:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    (define (random-list length limit)
      (let loop ((i 0)
                 (res '()))
        (if (= i length)
            res
            (loop (+ i 1) (cons (random limit) res)))))
    Ça ressemble bien a une boucle.

    Ta ask est une fonction qui valide l'entrée. Je pense qu'il est plus naturel de lui fournir la limite et même le méssage comme arguments, alors on obtient une fonction get-number assez générale. (current-input-port) c'est le port par défaut pour read, alors il ne vaut pas la peine l'indiquer.

    Pour obtenir une réponse de l'utilisateur, on peut écrire une fonction get-answer en se servant de random-list comme modèle.

    Le squelette de la fonction game est comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    (define (game)
      (let ((key (random-list game-length game-limit)))
        (let game-loop ((round 1))
          (report-round round)
          (let* ((answer (get-answer game-length game-limit))
                 (result (compare (get-answer game-length game-limit) key))
            (cond ((win? result) (display "Congrats!"))
                  (else (report-result answer result)
                        (game-loop (+ round 1)))))))))
    Lorsque tout ça fonctionne, on pouvait évoquer la fonction game dans le fichier :
    Mais ce doit être possible avoir un fichier de définitions et d'évoquer la fonction d'autre façon : par exemple, en indiquant la forme à évaluer à l'intérpreteur.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2013
    Messages
    18
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 18
    Par défaut
    Merci beaucoup, j'ai entièrement refait le code selon le bon découpage et je suis vraiment content du résultat !

    Le système de récurrence et plutôt dur à appréhender pour un débutant, mais à force, ça rentre.

    Une question -la dernière, c'est promis - j'ai vu dans les différents testes qu’apparemment, le racket serait un langage très lent, par rapport aux autres langages, et même par rapport aux autres lisp, vérité ?, est-ce que tout les lisp sont lent ?, existe-t-il un lisp avec un ide abordable d'une bonne rapidité ?

    Le jeu refait avec le bon format et le bon découpage:
    (Il persiste juste un tout petit problème à la fin, quand on gagne le jeu, il y a un bug, il semblerait que le retour de la fonction principale soit incorrect ?!?)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #lang racket
    (define (random-list length limit)
      (let loop ((i 0)
                 (res '()))
        (if (= i length)
            res
            (loop (+ i 1) (cons (random limit) res)))))
    
    (define (compare answer key)
      (map (lambda (a k)
             (cond ((= a k) 'T)
                   ((member a key) 'B)
                   (else 'F)))
           answer
           key))
    
    (define (get-answer length limit)
      (let loop ((n 1))
        (begin
          (printf "You must write a number between 0 and ~a:\n" (- limit 1))
          (let* ([i (read)])
            (if (and (integer? i) (>= i 0) (< i limit))
                (cons i (if (= n length)
                            '()
                            (loop (+ n 1))))
                (loop n))))))
    
    (define (report-result historique)
      (map (lambda (a) (printf "~a\n" a))
           historique))
    
    (define (game game-length game-limit)
      (let* ((key (random-list game-length game-limit)))
        (let game-loop ((round 1)
                        (historique '("Résultats:")))
          (begin
            (printf "Tour n°~a:\n" round)
            (let* ((answer (get-answer game-length game-limit))
                   (result (compare answer key))
                   (historique (append historique (list result answer))))
              (if (equal? answer key)
                  (printf "Congrats: ~a !" key)
                  ((report-result historique)
                   (game-loop (+ round 1)
                              historique))))))))
    
    (game 4 8)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 30/12/2010, 22h28
  2. mieux structurer son programme C++ ?
    Par Sceener dans le forum C++
    Réponses: 12
    Dernier message: 01/07/2007, 13h53
  3. [debutant] structure d'un programme
    Par poukill dans le forum Débuter
    Réponses: 17
    Dernier message: 19/05/2006, 15h33
  4. Debutant en JAVA, problème avec 1er programme
    Par Gymerus dans le forum Entrée/Sortie
    Réponses: 13
    Dernier message: 07/09/2005, 12h10
  5. Enregistrement du son par programme
    Par Invité dans le forum C++Builder
    Réponses: 3
    Dernier message: 10/06/2003, 23h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo