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

Caml Discussion :

Deux trois questions (notamment sur le module Graphics)


Sujet :

Caml

  1. #1
    Membre régulier
    Étudiant
    Inscrit en
    Juillet 2010
    Messages
    102
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2010
    Messages : 102
    Points : 110
    Points
    110
    Par défaut Deux trois questions (notamment sur le module Graphics)
    Bonjour,

    J'ai deux trois problèmes avec le module Graphics, notamment avec la fonction suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let fabriquer_matrice n p = 
      open_graph ""; resize_window (10 * n) (10 * p);
      let matrice = Array.make_matrix n p 0 and t = ref true in
      while !t do
        let evenement = wait_next_event [Button_down; Key_pressed] in
        if evenement.keypressed then t := false
        else 
          matrice.(n - 1 - (evenement.mouse_y / 10)).(evenement.mouse_x / 10) <- -1;
        afficher matrice
      done;
      matrice
    ;;
    Tout d'abord, bien qu'elle marche parfaitement sur Ubuntu avec la dernière version d'OCaml, elle ne marche pas sur Windows (avec la version d'OCaml proposée sur le site de l'INRIA). Les problèmes rencontrés sont :

    1. La fonction resize_window ne semble pas marcher. Enfin, elle fait un retour unit comme si tout c'était bien passé mais ne redimensionne pas du tout la fenêtre... Bon du coup c'est pas bien grave, j'ai fait ça (que d'ailleurs je n'avais pas fait du premier coup que par flemme) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    let fabriquer_matrice n p = 
      let lignes = string_of_int n and colonnes = string_of_int p in
      let str = " " ^ lignes ^ "x" ^ colonnes in
      open_graph str;
      let matrice = Array.make_matrix n p 0 and t = ref true in
      while !t do
        let evenement = wait_next_event [Button_down; Key_pressed] in
        if evenement.keypressed then t := false
        else 
          matrice.(n - 1 - (evenement.mouse_y / 10)).(evenement.mouse_x / 10) <- -1;
        afficher matrice
      done;
      matrice
    ;;
    2. Malgré ça, la fonction ne marche pas bien sur Windows. Effet, les cellules n'apparaissent pas exactement là où on clique. Je ne me souviens plus exactement mais il me semble qu'elles apparaissaient toujours soit une case plus haut (ou plus bas, c'est de ça que je ne me souviens plus) que prévu. En revanche, sur ma version d'OCaml, pas de problème.

    3. De temps en temps, il arrive que la fonction renvoie immédiatement la matrice n,p ne contenant que des 0. Ca c'est déjà un peu plus embêtant. Je pense que ça pourrait être dû à ça :

    Keypresses are queued, and dequeued one by one when the Key_pressed event is specified.
    mais je n'ai pas trouvé comment faire pour s'assurer qu'il n'y avait aucun keypress enqueued (n'y a-t-il pas un genre d'équivalent de flush ? Sinon je pourrais me contenter de "specifier Key_pressed" au début du programme, mais ça me semble être du bricolage...).

    Note : a priori ce problème ne se présente jamais si on se contente d'ouvrir le terminal, de copier le code et de lancer fabriquer_matrice. Mais à vrai dire je n'ai pas trop réussi à cerner quand le problème se présente.

    Sinon j'ai un problème d'ordre plus général avec mon programme (outre la complexité qui est affreuse, mais je vais changer ça lors des prochaines vacances ) : il me semble complètement illisible. Le fait que je n'ai pas encore mis de commentaire n'aide en rien, mais j'ai l'impression que c'est aussi dû au fait que mes fonctions prennent toutes 50 000 arguments. En même temps je peux pas les définir localement. Je pourrais utiliser des références mais je sais que c'est pas trop apprécié. J'ai aussi essayé de mettre des noms très explicites mais j'ai l'impression que ça alourdit plus qu'autre chose. Et enfin c'est très impératif comme style de programmation, mais en même temps comme je travaille avec des matrices je vois pas trop comment faire autrement simplement.

    Bref, si vous avez des remarques, plus sur la forme que sur le fond (puisque de toutes façons le fond est horrible : il ne s'agit que d'un brouillon de programme, d'ailleurs vous verrez qu'il y a plein de champs (comme la couleur ou l'indice des cellules) qui ne sont pas encore utilisés, mais c'est parce que normalement c'est fait pour faire cohabiter plusieurs types de cellules.), je suis preneur parce que là je patauge un peu (j'ai du mal à relire mes propres programmes)

    Je précise :
    - marques est une matrice qui contient des marqueurs : un nombre négatif correspond à - l'indice d'une cellule (mais ici on ne s'occupe pas encore de cas ou il y aurait plusieurs types de cellules, donc il n'y a que des -1), et un nombre positif quelconque à une case vide (j'ai essayé bricoler un truc avec des marqueurs pour pas me retrouver avec une complexité en O(n^4), mais c'est pas au point -> je prend les suggestions !)
    - cellules est la matrice contenant les cellules
    - nutriments est la matrice contenant les nutriments (pour l'instant il n'y a aucune distinction entre les divers nutriments et les autres trucs indispensables au bon fonctionnement d'une cellule)

    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    #load "graphics.cma";;
     
    open Graphics;;
     
    let afficher matrice =
      clear_graph ();
      let n = Array.length matrice and p = Array.length matrice.(0) in
      for i = 0 to n - 1 do
        for j = 0 to p - 1 do 
          if matrice.(i).(j) < 0 
          then fill_rect (10 * j) (size_y () - (10 * (i + 1))) 10 10 
        done
      done
    ;;
     
    let fabriquer_matrice n p = 
      open_graph ""; resize_window (10 * n) (10 * p);
      let matrice = Array.make_matrix n p 0 and t = ref true in
      while !t do
        let evenement = wait_next_event [Button_down; Key_pressed] in
        if evenement.keypressed then t := false
        else 
          matrice.(n - 1 - (evenement.mouse_y / 10)).(evenement.mouse_x / 10) <- -1;
        afficher matrice
      done;
      matrice
    ;;
     
    type cellule = 
      { indice : int;
        couleur : int;
        consommation : float;
        max : float;
        mutable reserves : float }
    ;;
     
    let cellule_fantome = 
      { indice = 1;
        couleur = white;
        consommation = 0.;
        max = 0.;
        reserves = 0. }
    ;;
     
    let initialiser_cellules marques =
      let n = Array.length marques and p = Array.length marques.(0) in
      let cellules = Array.make_matrix n p cellule_fantome
      in
      for i = 0 to n - 1 do
        for j = 0 to p - 1 do
          if marques.(i).(j) <> 0 then 
            cellules.(i).(j) <- { indice = 1;
                                  couleur = green;
                                  consommation = 1.;
                                  max = 10.;
                                  reserves = 5. }
          else cellules.(i).(j) <- { indice = 0;
                                     couleur = white;
                                     consommation = 0.;
                                     max = 0.;
                                     reserves = 0. }
        done
      done;
      cellules
    ;;
     
    let adjacents marques marqueur (x, y) =
      let n = Array.length marques and p = Array.length marques.(0)
      and accu = ref [] in
      marques.(x).(y) <- marqueur;
      for i = x - 1 to x + 1 do
        for j = y - 1 to y + 1 do
          if (0 <= i && i < n) && (0 <= j && j < p) then
            if marques.(i).(j) >= 0 && marques.(i).(j) <> marqueur then
              begin marques.(i).(j) <- marqueur; accu := (i, j) :: !accu end
        done
      done;
      !accu
    ;;
     
    let adjacents_sans_marquage marques (x, y) =
      let n = Array.length marques and p = Array.length marques.(0) in
      let accu = ref [] in
      for i = x - 1 to x + 1 do
        for j = y - 1 to y + 1 do
          if (0 <= i && i < n) && (0 <= j && j < p) && (x, y) <> (i, j) then
            if marques.(i).(j) >= 0 then accu := (i, j) :: !accu
        done
      done;
      !accu
    ;;
     
    let rec nb_connexes marques marqueur accu depart =
      match depart with
      | [] -> accu
      | _ -> let elargir depart = 
               List.flatten (List.rev_map (adjacents marques marqueur) depart) in
             nb_connexes marques marqueur 
               (accu + List.length depart) (elargir depart) 
    ;;
     
    let cardinaux_zones = ref [];;
     
    let marqueur = ref 1;;
     
    let marquer_zones_independantes marques =
      let n = Array.length marques and p = Array.length marques.(0) in
      for i = 0 to n - 1 do
        for j = 0 to p - 1 do
          if marques.(i).(j) = 0 then begin
            let couple_asso = 
              (!marqueur, nb_connexes marques !marqueur 0 [(i, j)]) in
              cardinaux_zones := couple_asso :: !cardinaux_zones;
              marqueur := !marqueur + 1 end
        done
      done
    ;;
     
    let marqueurs_bords marques =
      let n = Array.length marques and p = Array.length marques.(0) 
      and marqueurs = ref [] in
      let ajout_selectif n = 
        if (n >= 0) && not (List.mem n !marqueurs) then marqueurs := n :: !marqueurs
      in
      for j = 0 to p - 1 do
        ajout_selectif marques.(0).(j)
      done;
      for i = 1 to n - 1 do
        ajout_selectif marques.(i).(p - 1)
      done;
      for j = n - 2 downto 0 do
        ajout_selectif marques.(n - 1).(j)
      done;
      for i = p - 2 downto 1 do
        ajout_selectif marques.(i).(0)
      done;
      !marqueurs
    ;;
     
    let ajouter_nutriments marques nutriments concentration =
      let n = Array.length marques and p = Array.length marques.(0) in
      let reinitialiser_concentration marqueur =
        for i = 0 to n - 1 do
          for j = 0 to p - 1 do
            if marques.(i).(j) = marqueur then nutriments.(i).(j) <- concentration
          done
        done
      in
      List.iter reinitialiser_concentration (marqueurs_bords marques)
    ;;
     
    let melanger tableau = 
      let n = Array.length tableau in
      let echanger i j =
        let memo = tableau.(i) in
        tableau.(i) <- tableau.(j);
        tableau.(j) <- memo
      in
      for i = 0 to n - 1 do
        echanger i (i + Random.int (n - i))
      done;
      tableau
    ;;
     
    let ordre_aleatoire n =
      let tableau = Array.init n (fun x -> x) in
      melanger tableau
    ;;
     
    let enlever_nutriments marques cellules nutriments selection_marqueurs 
                                                          conso_zone (x, y) (i, j) =
      if (x, y) = (i, j) then  
        cellules.(x).(y).reserves <- cellules.(x).(y).reserves -. conso_zone
      else
        let n = Array.length marques and p = Array.length marques.(0)
        and m = marques.(i).(j) in
        if not (List.mem m selection_marqueurs) then
          for k = 0 to n - 1 do
            for l = 0 to p - 1 do
              if marques.(k).(l) = m then
                let difference = nutriments.(k).(l) -. conso_zone /. 
                                        float_of_int (List.assoc m !cardinaux_zones)
                in  
                if difference >= 0. then nutriments.(k).(l) <- difference
                else begin nutriments.(k).(l) <- 0.;
                           cellules.(x).(y).reserves <- cellules.(x).(y).reserves +.
                                                                      difference end     
            done
          done
    ;;
     
    let refaire_reserves marques cellules nutriments selection_marqueurs conso_zone 
                                                                     (x, y) (i, j) =
      if (x, y) <> (i, j) then
        let n = Array.length marques and p = Array.length marques.(0)
        and m = marques.(i).(j) 
        and nb_voisins = (cellules.(x).(y).consommation /.conso_zone)
        and manque =  min (cellules.(x).(y).max -. cellules.(x).(y).reserves) 1. in
        if List.mem m selection_marqueurs then
          cellules.(x).(y).reserves <- cellules.(x).(y).reserves +. 
                                                              (manque /. nb_voisins)
        else
          for k = 0 to n - 1 do
            for l = 0 to p - 1 do
              if marques.(k).(l) = m then
                let difference = nutriments.(k).(l) -. ((manque /. nb_voisins) /.
                                       float_of_int (List.assoc m !cardinaux_zones))
                in  
                if difference >= 0. then begin nutriments.(k).(l) <- difference;
                  cellules.(x).(y).reserves <- cellules.(x).(y).reserves +.
                                              (nutriments.(k).(l) -. difference) end  
     
                else begin cellules.(x).(y).reserves <- cellules.(x).(y).reserves +.
                                                                 nutriments.(k).(l);
                           nutriments.(k).(l) <- 0. end     
            done
          done
    ;; 
     
    let appliquer fonction marques cellules nutriments =
      let n = Array.length marques and p = Array.length marques.(0)
      and selection_marqueurs = marqueurs_bords marques in
      let ordre_lignes = ordre_aleatoire n and ordre_colonnes = ordre_aleatoire p in
      for k = 0 to n - 1 do
        for l = 0 to p - 1 do
          let i = ordre_lignes.(k) and j = ordre_colonnes.(l) in
          if marques.(i).(j) < 0 then 
            let adjacents = adjacents_sans_marquage marques (i, j) in
            if adjacents = [] then 
              let conso_zone = cellules.(i).(j).consommation in
              fonction marques cellules nutriments selection_marqueurs 
                                                            conso_zone (i, j) (i, j)
            else let conso_zone = cellules.(i).(j).consommation /. 
                                             float_of_int (List.length adjacents) in
             List.iter (fonction marques cellules nutriments selection_marqueurs 
                                                        conso_zone (i, j)) adjacents
        done
      done
    ;;
     
    let morts_mitoses marques cellules nutriments =
      let n = Array.length marques and p = Array.length marques.(0) in
      let ordre_lignes = ordre_aleatoire n and ordre_colonnes = ordre_aleatoire p in
      for k = 0 to n - 1 do
        for l = 0 to p - 1 do
          let i = ordre_lignes.(k) and j = ordre_colonnes.(l) in
          if marques.(i).(j) < 0 then 
            if cellules.(i).(j).reserves < 0. then marques.(i).(j) <- 0
            else if cellules.(i).(j).reserves >= cellules.(i).(j).max /. 2. then 
              let adjacents = adjacents_sans_marquage marques (i, j) in
              let nb_voisins = List.length adjacents in
              if nb_voisins > 0 then
                let nouvelle_cellule = List.nth adjacents (Random.int nb_voisins) in
                marques.(fst nouvelle_cellule).(snd nouvelle_cellule) <- -1;
                nutriments.(fst nouvelle_cellule).(snd nouvelle_cellule) <- 0.;
                cellules.(fst nouvelle_cellule).(snd nouvelle_cellule) <- 
                                     { indice = 1;
                                       couleur = green;
                                       consommation = 1.;
                                       max = 10.;
                                       reserves = cellules.(i).(j).reserves /. 2. };
                cellules.(i).(j).reserves <- cellules.(i).(j).reserves /. 2.
        done
      done
    ;;
     
    let jeu marques concentration =
      let cellules = initialiser_cellules marques
      and n = Array.length marques and p = Array.length marques.(0) in
      let nutriments = Array.make_matrix n p concentration in
      for i = 0 to n - 1 do
        for j = 0 to p - 1 do
          if marques.(i).(j) < 0 then nutriments.(i).(j) <- 0.
        done
      done;
      afficher marques;
      let t = ref true in 
      while !t do
        let evenement = wait_next_event [Key_pressed] in
        if evenement.key = '\027' then t := false
        else begin
          marquer_zones_independantes marques;
          ajouter_nutriments marques nutriments concentration;
          appliquer enlever_nutriments marques cellules nutriments;
          appliquer refaire_reserves marques cellules nutriments;
          morts_mitoses marques cellules nutriments;
          afficher marques end   
      done
    ;;
    Puisque j'ai appris qu'il y avait des biologistes sur le forum : surtout ne sursautez pas d'effrois devant le grand n'importe quoi de ce milieu de culture : Ce n'est pas censé être un truc sérieux bien sûr, c'est juste pour m'entraîner en info. (et en plus c'est pas fini )

    EDIT : Tiens c'est bizarre, je pensais avoir écrit mon code sur 80 colonnes, mais ça passe pas dans la balise "code"

  2. #2
    Membre éprouvé
    Avatar de Cacophrene
    Homme Profil pro
    Biologiste
    Inscrit en
    Janvier 2009
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Biologiste

    Informations forums :
    Inscription : Janvier 2009
    Messages : 535
    Points : 1 125
    Points
    1 125
    Par défaut
    Bonjour,

    Quelques pistes :


    • Pour le problème de la gestion des événements avec Graphics, de mémoire Poll est la solution.
    • Pour le problème d'open_graph, tu peux alléger les notations avec ksprintf. Par exemple ksprintf open_graph " %dx%d" n p. Regarde le module Printf.
    • Pour le code trop procédural, avec boucles et références, attention quand même : dans quelques cas c'est plus naturel ! Le problème c'est de savoir quand...

    Une fonction auxiliaire pour ton code, qui peut alléger certaines de tes fonctions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    let matrix_iteri f = Array.iteri (fun i -> (Array.iteri (f i)))
    Tu peux en écrire d'autres du même genre, comme pour l'initialisation de la matrice.

    Cordialement,
    Cacophrène

  3. #3
    Membre régulier
    Étudiant
    Inscrit en
    Juillet 2010
    Messages
    102
    Détails du profil
    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2010
    Messages : 102
    Points : 110
    Points
    110
    Par défaut
    Pour le problème de la gestion des événements avec Graphics, de mémoire Poll est la solution.
    Merci, effectivement j'ai l'impression que c'est le même problème ! C'est assez étrange quand même... Je vais essayer de voir dans quelles conditions ça se produit précisément, et si ça ne se produit pas au cours d'une utilisation normale du programme je laisserai ça. Sinon je passerai par Poll

    Pour le problème d'open_graph, tu peux alléger les notations avec ksprintf. Par exemple ksprintf open_graph " %dx%d" n p. Regarde le module Printf.
    Ah ouais, je connaissais pas cette fonction, pas bête ! Sinon moi chez moi ça marche bien, ce qui me gênait c'est que sur le Windows d'un pote à moi le resize_window marche pas. Enfin je vais sans doute changer mon code aussi, ça évitera d'avoir le truc stressant de la fenêtre qui s'ouvre et se redimensionne immédiatement

    Pour le code trop procédural, avec boucles et références, attention quand même : dans quelques cas c'est plus naturel ! Le problème c'est de savoir quand...
    Oui, c'est mon gros problème justement ! D'habitude j'essaie de faire le plus "purement fonctionnel" possible, mais là comme je travaille avec des matrices, j'ai forcément plein de boucles for... Et donc par paresse je rajoute des références, etc, et au final je me rend compte qu'il y en a un paquet.

    Une fonction auxiliaire pour ton code, qui peut alléger certaines de tes fonctions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    let matrix_iteri f = Array.iteri (fun i -> (Array.iteri (f i)))
    Merci, je connaissais pas non plus ! Ca va effectivement alléger le balayage de mes matrices.

    D'ailleurs j'ai l'impression que de manière globale mon code peut être énormément factorisé. J'ai commencé à essayer de le faire avec la fonction "appliquer", mais j'ai l'impression qu'on peut aller beauuucoup plus loin (par exemple j'ai deux fonctions déterminant les cases adjacents identiques à part qu'une effectue un marquage et l'autre non, je pourrais sans doute n'en définir qu'une seule sans marquage puis demander à la fonction connexes de marquer les cases au fur et a mesure qu'elles sont visitées...

    Encore merci pour ton aide !

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 27/09/2011, 15h26
  2. [quota] deux trois questions sur les quota sous Redhat
    Par pierrot10 dans le forum Administration système
    Réponses: 3
    Dernier message: 25/03/2009, 11h38
  3. question sur la classe graphic?
    Par Mickey.jet dans le forum Windows Forms
    Réponses: 3
    Dernier message: 29/07/2007, 03h22

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