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

Shell et commandes GNU Discussion :

Jeu de la vie en bash


Sujet :

Shell et commandes GNU

  1. #21
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut reculer une cellule d'une case quand elle atteint le bord
    Bonjour !

    Je viens faire un petit point concernant mon jeu de la vie en bash !

    Les fonctions de bases fonctionnent, cette fois les cellules bougent correctement !

    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
    #!/bin/bash
     
    Generation=0
    num_lines=0
    num_columns=0
    CELL=0
     
    declare -A tab
    declare -A tabfutur #Tempory array that will receive the future stat of each cell.
     
     
    ####################### HEADER #########################
     
    # This function displays the header.
     
    header_function()
    {
    echo ""
    echo " ═══════════════════ Conway's Game of Life ═══════════════════ "
    echo ""
    }
     
     
    #################### ARRAY FUNCTION #####################
     
    # This function initalizes the array and fill it with randomly 0 and 1 or with nothing.
     
    init_array_function()
    {
    for ((x=1;x<=num_lines;x++))
    do
            for ((y=1;y<=num_columns;y++)) 
            do 
     	 if [[ $CELL == 'a' ]]
     	 then	 
     	 	 tab[$x,$y]=$((RANDOM %2))
     	 else
     	 	 tab[$x,$y]=
     	 fi
            done 
    done
    }
     
    #################### DISPLAY FUNCTION ####################
     
    # This function displays the array.
     
     
    display_function()
    {
    #header_function
    clear
    echo ""
    f1="%$((${#num_lines}+1))s"
    f2="%3s"
    printf "$f1"
    for ((x=1;x<=num_lines-1;x++))
    do
           printf "$f2" "$x"  #Comment this line to delete the display of the abscissa.  
           #toto=1 #This line is only here to avoid errors in the for loop when the abscissa is disabled.   
    done
    echo
     
    for ((y=1;y<=num_columns-1;y++))
    do
     
            printf "$f1" $y #Comment this line to delete the display of the ordinate. 
                    for ((x=1;x<=num_lines-1;x++)) 
                    do 
                                    printf "$f2" "${tab[$x,$y]}"  
     	 done
                    echo 
    done
    echo ""
    echo " > Génération : $generation "
    ((generation++))
    }
     
    #################### ASK COORDINATES ####################
     
    # This function asks the user to enter the coordinates of the cell ad type 's' to run the game.
     
    coord_function()
    {
    echo ""
    echo ""
    while [ "$coord" != "s" ]
    do
      	 echo -n " + Place your cell using the array coordinates ( like '1,1' ) or press 's' to start : "
     	 read coord
     
                    if [[ "$coord" =~ ^[0-9]+,[0-9]+$ ]] ; then  x=${coord%, *} ;  y=${coord#*, } ; 
                    tab[$coord]="${CELL}" 
     	 display_function
                    echo "" 
                    elif [[ "$coord" == "s" ]] 
     	 then
     	 	 start_function
     	 fi
     	 done
    }
     
    ################################ ARRAY ANALIZE ################################
     
    # This function analyze the array and calculates the different neighbours.
     
    array_analyze_function()
    {
    tput civis
    while true
    do
     for ((x=1;x<=num_lines;x++)) 
     do
    	 for ((y=1;y<=num_columns;y++)) 
    	 do 
     
     	 Counter=0
     
     	 # Neighbour (x-1,y-1)
     	 [[ "${tab[$(($x-1)),$(($y-1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x,y-1) 
     	 [[ "${tab[$(($x)),$(($y-1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x+1,y-1)
     	 [[ "${tab[$(($x+1)),$(($y-1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x-1,y)
     	 [[ "${tab[$(($x-1)),$(($y))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x+1,y)
     	 [[ "${tab[$(($x+1)),$(($y))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x-1,y+1)
     	 [[ "${tab[$(($x-1)),$(($y+1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x,y+1)
     	 [[ "${tab[$(($x)),$(($y+1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # Neighbour (x+1,y+1)
     	 [[ "${tab[$(($x+1)),$(($y+1))]}" == $CELL ]] && ((Counter++)) 
     
     	 # If the cell is alive and with two neighbours, she survives.
                    [[ ${Counter} -eq 2 ]] && tabfutur[${x},${y}]=${tab[$x,$y]} 
     
    	 # If the cell has 3 neighbours, either it survives or a celle is born. 
    	 [[ ${Counter} -eq 3 ]] && tabfutur[${x},${y}]=$CELL 
     
     	 # If th cell is alive with maximum one neighbourd, she dies.
     	 [[ ${Counter} -le 1 ]] && tabfutur[${x},${y}]=""
     
    	 # If a cell has between four and eight neighbours, she dies. 
    	 [[ ${Counter} -ge 4 ]] && [[ ${Counter} -le 8 ]] && tabfutur[${x},${y}]="" 
     
     	 done
     done
     
     	 for ((x=1;x<=num_lines-1;x++)) 
     	 do
    	 	 for ((y=1;y<=num_columns-1;y++)) 
    	 	 do 
     	 	 	 tab[$x,$y]=${tabfutur[$x,$y]}
     	 	 done
     	 done
     display_function
     array_analyze_function
    done
     
    }
     
    #################### HOMEPAGE ####################
     
    # This function asks the user to enter the numbers of lines, of columns, the form of the cell or type 'a' to fill in the array randomly.
     
    homepage_function()
    {
    header_function
    echo " How many lines ? "
    echo -n " > "
    read Lines
     
            until [[ $Lines =~ ^[0-9]+$ ]] 
            do 
                    echo -e "\033[91m > Error ! Retry ! <\033[0m " 
                    echo "" 
                    echo " How many lines ? " 
                    echo -n " > " 
                    read -r Lines 
     
            done 
     
    echo ""
     
    echo " How many columns ? "
    echo -n " > "
    read Columns
     
            until [[ $Columns =~ ^[0-9]+$ ]] 
            do 
                    echo -e "\033[91m > Error ! Retry ! <\033[0m " 
                    echo "" 
                    echo " How many Columns ? " 
                    echo -n " > " 
                    read -r Columns 
            done 
    echo ""
    echo " Put the cell's form or press 'a' to fill randomly the array "
    echo -n " > "
    read -r CELL
     
    while [ -z "$CELL" ] 
    do
            echo -e "\033[91m > Error ! Retry ! <\033[0m " 
            echo "" 
            echo " Cell's form ? " 
            echo -n " > " 
            read -r CELL 
    done	 
     
     
    Generation=0
    num_lines=$Lines
    num_columns=$Columns
    CELL=$CELL
    }
     
    #################### RUN & START FUNCTION ####################
     
    # This function starts the analysis of the array.
     
    start_function()
    {
    while true
    do
    array_analyze_function
    done
    }
     
     
    # This function is the basic function. It allows you tu launch all the other functions.
     
    run()
    {
    homepage_function
    init_array_function
    display_function
    coord_function
    }
     
    ################################ MAIN ################################
    clear
    echo ""
    echo "╔═══════════════════════ Conway's Game of Life ═══════════════════════╗"
    echo "║                                                                       ║" 
    echo "║    This is the Bash script version of John Conway's Game of Life.     ║" 
    echo "║       Life is a simple implementation of cellular automata.           ║" 
    echo "║                                                                       ║"                       
    echo "╠═══════════════════════════════════════════════════════════════════════╣"
    echo "║                                                                       ║" 
    echo "║                                 Rules :                               ║" 
    echo "║                                                                       ║" 
    echo "║ [1] A living cell with either 2 or 3 living neighbors remains alive. ║"
    echo "║                                                                       ║" 
    echo "║         [2] A dead cell with 3 living neighbors comes alive.          ║" 
    echo "║                                                                       ║" 
    echo "║ [2] All other cases result in a dead cell for the next generation. ║"
    echo "║                                                                       ║" 
    echo "╚═══════════════════════════════════════════════════════════════════════╝"
    echo ""
    echo ""
     
    read -p "> Press any key to continue ... "
    clear
    run



    EDIT : Certains caractères ne passent pas... Vous pouvez trouver mon script sur mon gitlab => https://gitlab.com/Ezzmazz/game-of-life-in-bash

    Il faut prendre le V2.


    Pour ceux qui veulent tester :

    - Exemple d'un planeur, les coordonnées sont 10,10, 11,11, 11,12, 10,12 et 9,12
    - Exemple d'un clignotant, les coordonnées sont 10,10, 11,10 et 12,10.



    Maintenant, je dois réussir à prendre en compte le les bordures et là j'avoue que je bloque ! Dans l'idée :

    - Soit on fait en sorte qu'une cellule arrivant à la limite du tableau ressorte de l'autre côté du tableau ( un peu comme pacman ).
    - Soit je fais en sorte que quand une cellule arrive sur une bordure, elle rebondit dessus.



    J'ai décidé de choisir la deuxième option ( elle me semblait être plus simple ) et voici ce que je propose :

    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
    # Si la cellule "monte" et qu'elle atteint la limite verticale supérieure, elle doit se mettre à descendre
     
    if [[ "${tabfutur[$(($x)),$(($y+1))]}" == $CELL ]] && [[ "${tabfutur[$(($y))]}" == $num_columns ]]
    then
    $CELL="${tabfutur[$(($x)),$(($y-1))]}"
    fi
     
    # Si la cellule "descend" et qu'elle atteint la limite verticale inférieure, elle doit se mettre à monter
     
    if [[ "${tabfutur[$(($x)),$(($y-1))]}" == $CELL ]] && [[ "${tabfutur[$(($y))]}" == $num_columns ]]
    then
    $CELL="${tabfutur[$(($x)),$(($y+1))]}"
    fi
     
     
    # Si la cellule se déplace vers la droite et qu'elle atteint la limite horizontale à droite, elle doit partir vers la gauche
     
    if [[ "${tabfutur[$(($x+1)),$(($y))]}" == $CELL ]] && [[ "${tabfutur[$(($y))]}" == $num_lines ]]
    then
    $CELL="${tabfutur[$(($x-1)),$((y))]}"
    fi
     
     
    # Si la cellule se déplace vers la gauche et qu'elle atteint la limite horizontale à gauche, elle doit partir vers la droite
     
    if [[ "${tabfutur[$(($x-1)),$(($y))]}" == $CELL ]] && [[ "${tabfutur[$(($y))]}" == $num_lines ]]
    then
    $CELL="${tabfutur[$(($x+1)),$((y))]}"
    fi



    Vous comprendrez que ce que je cherche à faire ici, c'est de décaler une cellule d'une case en arrière à chaque fois qu'elle atteint une bordure. Le problème, c'est que... Ça ne fonctionne pas !


    Auriez-vous une idée ?



    Merci encore !

  2. #22
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 103
    Par défaut
    Citation Envoyé par Ezzmazz Voir le message
    Maintenant, je dois réussir à prendre en compte le les bordures et là j'avoue que je bloque ! Dans l'idée :

    - Soit on fait en sorte qu'une cellule arrivant à la limite du tableau ressorte de l'autre côté du tableau ( un peu comme pacman ).
    Remarque: lorsque les bords parallèles d'un rectangle se rejoignent, on appelle ça un tore.
    L'avantage est que le modèle est simple: tout se passe comme si le bas du tableau était "prolongé" par son haut.
    Ou, autrement dit, le calcul du nombre de voisins d'une case du bas intègre les cases du haut (et réciproquement).

    - Soit je fais en sorte que quand une cellule arrive sur une bordure, elle rebondit dessus.
    Là, le modèle me semble moins clair.

    La notion de "une cellule arrive sur le bord" ne fait pas partie du modèle du jeu de la vie.

    Les règles du jeu de la vie indiquent que, pour une case donnée, il peut arriver que:
    • s'il y a une cellule sur la case:
      • la cellule survit
      • la cellule ne survit pas (elle meurt)
    • s'il n'y a pas de cellule sur la case:
      • une cellule nait
      • une cellule ne nait pas


    Il n'y a pas de notion de "déplacement" de cellule, même si la vision des générations successives d'un glider donne cette impression!

    Bref, il me semble important que les spécifications soient aussi claires que possible.

    Donc, qu'entends-tu précisément par "une cellule arrive sur une bordure"?
    Veux-tu dire (avec le vocabulaire du jeu de la vie) "lorsqu'une cellule naît sur le bord"?
    Ou bien "lorsqu'une cellule survit ou naît sur le bord"?

    Et aussi, qu'entends-tu précisément par rebond?
    Veux-tu dire que, par exemple, le bord du haut se prolonge virtuellement par une version réfléchie (symétrie le long de la ligne du haut) du tableau?
    Si c'est le cas, compte-tenu de la "portée" du voisinage dans le jeu de la vie (limité à une distance de 1 case dans les 8 directions), c'est comme si la ligne du haut était simplement dupliquée, non?

    La version torique me semble plus simple à mettre en place.

    Sinon il existe (au moins) une 3ème option, c'est un tableau effectivement limité en taille.
    Concrètement, les cellule de la ligne du haut n'ont aucun voisin au-dessus.

    Une autre option, très proche de la précédente, consiste à utiliser un tableau limité en taille comme le précédent, mais un peu plus grand (1, 2 ou 3? lignes en plus sur chaque bord), mais clippé à la taille précédente.

  3. #23
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Merci pour toutes ces informations, corrections et précisions.


    Citation Envoyé par jack-ft Voir le message
    Donc, qu'entends-tu précisément par "une cellule arrive sur une bordure"?
    Veux-tu dire (avec le vocabulaire du jeu de la vie) "lorsqu'une cellule naît sur le bord"?
    Ou bien "lorsqu'une cellule survit ou naît sur le bord"?

    Et aussi, qu'entends-tu précisément par rebond?
    Veux-tu dire que, par exemple, le bord du haut se prolonge virtuellement par une version réfléchie (symétrie le long de la ligne du haut) du tableau?
    Si c'est le cas, compte-tenu de la "portée" du voisinage dans le jeu de la vie (limité à une distance de 1 case dans les 8 directions), c'est comme si la ligne du haut était simplement dupliquée, non? .
    Je voulais dire par là, que dès qu'une des deux coordonnées, donc x ou y, atteint la valeur de $num_columns ou $num_lines, elle revient en arrière. Visuellement, j'ai imaginé celà comme étant un rebond.


    Mais il semblerait que la version torique soit la plus répandue, donc je vais m'orienter dans cette direction. Et si j'ai bien compris, le but c'est de faire en sorte que les côtés du tableau soient comme " cousu " entre eux. Donc :

    1. Si $x est supérieur à $num_columns, alors $x est égal au négatif de $num_columns ( donc si $num_columns = 30, ce serait -30 )
    2. Si $x est inférieur au négatif de $num_columns, alors $x sera égal à $num_columns.
    3. Si $y est supérieur à $num_lines, alors $y est égal au négatif de $num_lines.
    4. Si $y est inférieur au négatif dde $num_lines, alors $y sera égal à $num_lines.




    Donc un truc du genre :

    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
    if [[ $x > $num_columns ]]
    then
       x=$(( 0 - $num_columns ))
    fi
     
    if [[ $x < $(( 0 - $num_columns )) ]]
    then
       x=$num_columns
    fi
     
    if [[ $y > $num_lines ]]
    then
       y=$(( 0 - $num_lines ))
    fi
     
    if [[ $y < $(( 0 - $num_lines )) ]]
    then
       y=$num_lines
    fi

    Le tout ajouté dans ma fonction array_analyze_function ?


    Merci encore pour votre aide !

  4. #24
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 103
    Par défaut
    Je vois que ton code commence à prendre forme! Bravo!

    Citation Envoyé par Ezzmazz Voir le message
    Je voulais dire par là, que dès qu'une des deux coordonnées, donc x ou y, atteint la valeur de $num_columns ou $num_lines, elle revient en arrière. Visuellement, j'ai imaginé celà comme étant un rebond.
    Aïe!

    x et y sont les coordonnées des cases où tu calcules la génération suivante (que tu stockes dans tabfutur).
    Ce ne sont PAS les coordonnées d'une cellule... car, comme expliqué plus haut, il n'y a pas d'entité cellule. Il y a juste l'occupation d'une case par une cellule.

    Lorsque tu calcules la génération suivante, cela revient à regarder pour chaque case de tout le tableau s'il y a ou non une cellule dans cette case pour la génération suivante.
    De ce fait, tu dois vraiment explorer toutes les cases du tableau, c'est ce que tu fais avec tes 2 boucles imbriquées en x et en y.
    Donc tu fais bien varier x de 1 à $num_columns pour explorer toutes les colonnes. Lorsque ta boucle explore pour x la valeur $num_columns, tu ne peux pas changer la valeur de x. Ça n'a pas de sens!

    Mais il semblerait que la version torique soit la plus répandue, donc je vais m'orienter dans cette direction. Et si j'ai bien compris, le but c'est de faire en sorte que les côtés du tableau soient comme " cousu " entre eux.
    Oui. Je pense que tu as compris cela.

    Donc :

    1. Si $x est supérieur à $num_columns, alors $x est égal au négatif de $num_columns ( donc si $num_columns = 30, ce serait -30 )
    2. Si $x est inférieur au négatif de $num_columns, alors $x sera égal à $num_columns.
    3. Si $y est supérieur à $num_lines, alors $y est égal au négatif de $num_lines.
    4. Si $y est inférieur au négatif dde $num_lines, alors $y sera égal à $num_lines.
    Non non non! (voir plus haut (ou plus bas))

    Donc un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if [[ $x > $num_columns ]]
    then
       x=$(( 0 - $num_columns ))
    fi
    Non! (voir plus haut) On ne modifie jamais la valeur de x dans une boucle.
    D'ailleurs certains langages de programmation "évolués" ont une structure de boucle "structurée" telle que le compilateur n'autorise pas la modification de l'énumérateur (autrement que par l'énumération elle-même).

    Pour revenir à la version torique, par exemple, les modifications que tu dois faire peuvent se situer dans la fonction "array_analyze_function()".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     	 # Neighbour (x-1,y)
     	 [[ "${tab[$(($x-1)),$(($y))]}" == $CELL ]] && ((Counter++))
    où il faudrait dire, par exemple, que lorsque le parcours de boucle passe par la valeur 1 pour x (c'est-à-dire lorsque x==1) alors le voisin de gauche de la case courante (x, y) (qui est en l'occurrence (1, y)) n'est pas (x-1, y), qui est "en dehors" du tableau, mais plutôt (N, y) qui est à l'autre bout (cousu) du tableau (où N est $numcolumns).

    Cependant, je crois que cela alourdit considérablement le code.

    Àmha, il est beaucoup plus simple de prendre un tableau légèrement plus grand de 2 colonnes et 2 lignes et, au bon moment, de recopier le contenu de la colonne N en colonne 0, recopier le contenu de la colonne 1 en colonne N+1 (et pareil pour les lignes).
    De cette manière, le test sur les cases du bord est exactement identique au test des cases intérieures.

  5. #25
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Merci pour vos réponses !


    Citation Envoyé par jack-ft Voir le message
    Je vois que ton code commence à prendre forme! Bravo!
    Oui ! Petit à petit ! La version sans les bords cousus fonctionne bien mais même si dans la forme, mon code pourrait être beaucoup plus clean que ça ! Mais pour un début, ça ira ! Je le modifierai avec le temps, à force d'apprendre de nouvelles choses !


    Citation Envoyé par jack-ft Voir le message
    Aïe!

    x et y sont les coordonnées des cases où tu calcules la génération suivante (que tu stockes dans tabfutur).
    Ce ne sont PAS les coordonnées d'une cellule... car, comme expliqué plus haut, il n'y a pas d'entité cellule. Il y a juste l'occupation d'une case par une cellule.

    Lorsque tu calcules la génération suivante, cela revient à regarder pour chaque case de tout le tableau s'il y a ou non une cellule dans cette case pour la génération suivante.
    De ce fait, tu dois vraiment explorer toutes les cases du tableau, c'est ce que tu fais avec tes 2 boucles imbriquées en x et en y.
    Donc tu fais bien varier x de 1 à $num_columns pour explorer toutes les colonnes. Lorsque ta boucle explore pour x la valeur $num_columns, tu ne peux pas changer la valeur de x. Ça n'a pas de sens!
    Hum, d'accord ! Je comprends la différence !



    Citation Envoyé par jack-ft Voir le message
    Non! (voir plus haut) On ne modifie jamais la valeur de x dans une boucle.
    D'ailleurs certains langages de programmation "évolués" ont une structure de boucle "structurée" telle que le compilateur n'autorise pas la modification de l'énumérateur (autrement que par l'énumération elle-même).

    Pour revenir à la version torique, par exemple, les modifications que tu dois faire peuvent se situer dans la fonction "array_analyze_function()".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     	 # Neighbour (x-1,y)
     	 [[ "${tab[$(($x-1)),$(($y))]}" == $CELL ]] && ((Counter++))
    où il faudrait dire, par exemple, que lorsque le parcours de boucle passe par la valeur 1 pour x (c'est-à-dire lorsque x==1) alors le voisin de gauche de la case courante (x, y) (qui est en l'occurrence (1, y)) n'est pas (x-1, y), qui est "en dehors" du tableau, mais plutôt (N, y) qui est à l'autre bout (cousu) du tableau (où N est $numcolumns).

    Cependant, je crois que cela alourdit considérablement le code.

    Que cela alourdisse le code, ce n'est pas trop grave. Le but pour le moment c'est que ça fonctionne, le code sera amélioré au fur et à mesure de mon apprentissage ( je pense notamment à ajouter le fait de pouvoir placer des cellules avec les flèches du clavier, afin de bouger le curseur là où on le souhaite ).

    J'avoue avoir un peu de mal à comprendre ce système de bord cousu...


    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
    if [[ $x == 1 ]]
                    then
                            tab[$(($x-1)),$(($y))]=$tab[$(($x-$num_columns)),$(($y))]          
                    fi
     
                    if [[ $x == $num_columns ]]
                    then
                            tab[$(($x-$num_columns)),$(($y))]=$tab[$(($x-1)),$(($y))]
                    fi
     
                    if [[ $y == 1 ]]
                    then
                            tab[$(($x)),$(($y-1))]=$tab[$(($x)),$(($y-$num_lines))]
                    fi
     
                    if [[ $y == $num_lines ]]
                    then
                            tabf[$(($x)),$(($y-$num_lines))]=$tab[$(($x)),$(($y-1))]
     
                    fi

    J'ai mis ce bout de code juste au au-dessus de mon calcul de cellules voisines, dans ma fonction array_analyze_function.

    Bon évidemment, ça ne fonctionne pas

    Citation Envoyé par jack-ft Voir le message
    Àmha, il est beaucoup plus simple de prendre un tableau légèrement plus grand de 2 colonnes et 2 lignes et, au bon moment, de recopier le contenu de la colonne N en colonne 0, recopier le contenu de la colonne 1 en colonne N+1 (et pareil pour les lignes).
    De cette manière, le test sur les cases du bord est exactement identique au test des cases intérieures.
    Je testerai cette solution si jamais je n'arrive pas avec le modèle torique.



    Merci encore pour votre aide !

  6. #26
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 299
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 299
    Par défaut
    Citation Envoyé par Ezzmazz Voir le message
    J'avoue avoir un peu de mal à comprendre ce système de bord cousu...
    C'est le concept des espaces finis sans bords.
    Exemples d'espace fini avec un bord : un coffre fort, la pièce où tu te trouves, un tupperware, etc
    Exemples d'espace infini sans bord : l'univers tel qu'on l'imagine ? Le temps ? L'écriture de π; et de tout nombre, d'ailleurs; toute écriture de nombre, vers la gauche ou vers la droite est infinie.

    Mais existe-t-il des espaces finis sans bords ?
    Oui !
    • La surface de la terre
      Si un être humain parcours la surface de la terre, il peut continuer tout droit sans jamais s'arrêter. Il ne tombe pas dans le vide intersidéral après avoir atteint le bord !
    • Le jeu Asteroïd
      Quand le petit vaisseau disparaît sur le bord droit, il réapparaît sur le bord gauche.
      Et inversement.
      Et pareil dans l'autre sens.
      Donc il peut avancer à l'infini sans jamais atteindre le bord.
      Pourtant, l'espace est fini puisque nous l'avons entier sous les yeux : c'est l'écran !


    Un rectangle est un espace à 2 dimensions.
    Si on cherche le volume en 3 dimensions qui donnent une surface 2D fini sans bords, comme la planète terre (un patatoïde) donne la surface de la terre, alors, c'est là qu'on obtient un tore.
    Le rectangle 2D donne le tore 3D.


    Concrètement, pour le calcul de coordonnées, ça se règle très bien avec des modulos. ℤ\nℤ.

    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
    $ x=0;for ((i=0;i<48;i++)); do echo -n "x : $x -> ";x=$(( (x+1)%24 ));echo -e "$x\ti: $i -> $((i%24))";done
    x : 0 -> 1      i: 0 -> 0
    x : 1 -> 2      i: 1 -> 1
    x : 2 -> 3      i: 2 -> 2
    x : 3 -> 4      i: 3 -> 3
    x : 4 -> 5      i: 4 -> 4
    x : 5 -> 6      i: 5 -> 5
    x : 6 -> 7      i: 6 -> 6
    x : 7 -> 8      i: 7 -> 7
    x : 8 -> 9      i: 8 -> 8
    x : 9 -> 10     i: 9 -> 9
    x : 10 -> 11    i: 10 -> 10
    x : 11 -> 12    i: 11 -> 11
    x : 12 -> 13    i: 12 -> 12
    x : 13 -> 14    i: 13 -> 13
    x : 14 -> 15    i: 14 -> 14
    x : 15 -> 16    i: 15 -> 15
    x : 16 -> 17    i: 16 -> 16
    x : 17 -> 18    i: 17 -> 17
    x : 18 -> 19    i: 18 -> 18
    x : 19 -> 20    i: 19 -> 19
    x : 20 -> 21    i: 20 -> 20
    x : 21 -> 22    i: 21 -> 21
    x : 22 -> 23    i: 22 -> 22
    x : 23 -> 0     i: 23 -> 23
    x : 0 -> 1      i: 24 -> 0
    x : 1 -> 2      i: 25 -> 1
    x : 2 -> 3      i: 26 -> 2
    x : 3 -> 4      i: 27 -> 3
    x : 4 -> 5      i: 28 -> 4
    x : 5 -> 6      i: 29 -> 5
    x : 6 -> 7      i: 30 -> 6
    x : 7 -> 8      i: 31 -> 7
    x : 8 -> 9      i: 32 -> 8
    x : 9 -> 10     i: 33 -> 9
    x : 10 -> 11    i: 34 -> 10
    x : 11 -> 12    i: 35 -> 11
    x : 12 -> 13    i: 36 -> 12
    x : 13 -> 14    i: 37 -> 13
    x : 14 -> 15    i: 38 -> 14
    x : 15 -> 16    i: 39 -> 15
    x : 16 -> 17    i: 40 -> 16
    x : 17 -> 18    i: 41 -> 17
    x : 18 -> 19    i: 42 -> 18
    x : 19 -> 20    i: 43 -> 19
    x : 20 -> 21    i: 44 -> 20
    x : 21 -> 22    i: 45 -> 21
    x : 22 -> 23    i: 46 -> 22
    x : 23 -> 0     i: 47 -> 23
    Si tu es entre 0 et 23, tu incrémentes puis tu fais modulo 24. x=(x+1)%24
    Si tu es entre 1 et 24, tu fais modulo 24 puis tu incrémentes. x=(x%24)+1

    if [[ $x == 1 ]]
    Pourquoi des doubles crochets ? Des simples suffisent.
    $(($y))
    Pourquoi une évaluation arithmétique ? Aucun calcul n'est demandé.

    $(($x-1))
    Le dollar devant la variable dans un contexte d'évaluation arithmétique est inutile.

  7. #27
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    C'est le concept des espaces finis sans bords.
    Exemples d'espace fini avec un bord : un coffre fort, la pièce où tu te trouves, un tupperware, etc
    Exemples d'espace infini sans bord : l'univers tel qu'on l'imagine ? Le temps ? L'écriture de π; et de tout nombre, d'ailleurs; toute écriture de nombre, vers la gauche ou vers la droite est infinie.

    Mais existe-t-il des espaces finis sans bords ?
    Oui !
    • La surface de la terre
      Si un être humain parcours la surface de la terre, il peut continuer tout droit sans jamais s'arrêter. Il ne tombe pas dans le vide intersidéral après avoir atteint le bord !
    • Le jeu Asteroïd
      Quand le petit vaisseau disparaît sur le bord droit, il réapparaît sur le bord gauche.
      Et inversement.
      Et pareil dans l'autre sens.
      Donc il peut avancer à l'infini sans jamais atteindre le bord.
      Pourtant, l'espace est fini puisque nous l'avons entier sous les yeux : c'est l'écran !


    Un rectangle est un espace à 2 dimensions.
    Si on cherche le volume en 3 dimensions qui donnent une surface 2D fini sans bords, comme la planète terre (un patatoïde) donne la surface de la terre, alors, c'est là qu'on obtient un tore.
    Le rectangle 2D donne le tore 3D.

    Merci pour les explications ! Le principe en lui même je le comprends ! En revanche, je n'arrive pas à imaginer ce système en bash et de l'appliquer à mon code.


    Citation Envoyé par Flodelarab Voir le message
    Concrètement, pour le calcul de coordonnées, ça se règle très bien avec des modulos. ℤ\nℤ.

    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
    $ x=0;for ((i=0;i<48;i++)); do echo -n "x : $x -> ";x=$(( (x+1)%24 ));echo -e "$x\ti: $i -> $((i%24))";done
    x : 0 -> 1      i: 0 -> 0
    x : 1 -> 2      i: 1 -> 1
    x : 2 -> 3      i: 2 -> 2
    x : 3 -> 4      i: 3 -> 3
    x : 4 -> 5      i: 4 -> 4
    x : 5 -> 6      i: 5 -> 5
    x : 6 -> 7      i: 6 -> 6
    x : 7 -> 8      i: 7 -> 7
    x : 8 -> 9      i: 8 -> 8
    x : 9 -> 10     i: 9 -> 9
    x : 10 -> 11    i: 10 -> 10
    x : 11 -> 12    i: 11 -> 11
    x : 12 -> 13    i: 12 -> 12
    x : 13 -> 14    i: 13 -> 13
    x : 14 -> 15    i: 14 -> 14
    x : 15 -> 16    i: 15 -> 15
    x : 16 -> 17    i: 16 -> 16
    x : 17 -> 18    i: 17 -> 17
    x : 18 -> 19    i: 18 -> 18
    x : 19 -> 20    i: 19 -> 19
    x : 20 -> 21    i: 20 -> 20
    x : 21 -> 22    i: 21 -> 21
    x : 22 -> 23    i: 22 -> 22
    x : 23 -> 0     i: 23 -> 23
    x : 0 -> 1      i: 24 -> 0
    x : 1 -> 2      i: 25 -> 1
    x : 2 -> 3      i: 26 -> 2
    x : 3 -> 4      i: 27 -> 3
    x : 4 -> 5      i: 28 -> 4
    x : 5 -> 6      i: 29 -> 5
    x : 6 -> 7      i: 30 -> 6
    x : 7 -> 8      i: 31 -> 7
    x : 8 -> 9      i: 32 -> 8
    x : 9 -> 10     i: 33 -> 9
    x : 10 -> 11    i: 34 -> 10
    x : 11 -> 12    i: 35 -> 11
    x : 12 -> 13    i: 36 -> 12
    x : 13 -> 14    i: 37 -> 13
    x : 14 -> 15    i: 38 -> 14
    x : 15 -> 16    i: 39 -> 15
    x : 16 -> 17    i: 40 -> 16
    x : 17 -> 18    i: 41 -> 17
    x : 18 -> 19    i: 42 -> 18
    x : 19 -> 20    i: 43 -> 19
    x : 20 -> 21    i: 44 -> 20
    x : 21 -> 22    i: 45 -> 21
    x : 22 -> 23    i: 46 -> 22
    x : 23 -> 0     i: 47 -> 23
    Si tu es entre 0 et 23, tu incrémentes puis tu fais modulo 24. x=(x+1)%24
    Si tu es entre 1 et 24, tu fais modulo 24 puis tu incrémentes. x=(x%24)+1

    C'est un autre moyen de calculer les coordonnées ? Ou est-ce un exemple de prise en compte des bordures ? J'avoue qu'à force je m'y perds un peu, j'ai du mal à comprendre comment votre boucle pourrait être intégré à mon code. ( Je regarderai plus en détails un peu plus tard, tout comme votre système avec la possibilité de placer les cellules avec les flèches du clavier que vous m'aviez donné quelques postes avant. Pour le moment je reste concentré sur les bordures ).


    Cependant, j'aimerai que vous m’éclaircissiez quelques points tout de même :

    • Comment fonctionne le modulo ? Je sais que pour un calcul, il donne le reste d'une division euclidienne mais dans votre exemple, que fait-il ?
    • Ce qui, actuellement, est compliqué pour moi : c'est de comprendre comment fonctionne ce système de bordure. Je m'explique : si je reprends ce que jack-ft m'a indiqué :

      où il faudrait dire, par exemple, que lorsque le parcours de boucle passe par la valeur 1 pour x (c'est-à-dire lorsque x==1) alors le voisin de gauche de la case courante (x, y) (qui est en l'occurrence (1, y)) n'est pas (x-1, y), qui est "en dehors" du tableau, mais plutôt (N, y) qui est à l'autre bout (cousu) du tableau (où N est $numcolumns).
      1. Il faut donc commencer par si x à la valeur 1 donc if [ x == 1 ]
      2. Le voisin de la case courante (x,y) n'est pas ( x-1,y ) mais (N,y), N étant le maximum de ma variables $num_columns. Comment dois-je écrire cela ? then ($num_columns,y ) ? Et donc au final, pour (x+1,y) c'est la même chose non ? Sauf que cette fois ce serait if [ x == $num_columns ] ?
      3. Et de ce fait, je fait la même chose en remplaçant x par y et $num_columns et $num_lines ? Ça tiendrait en 4 lignes ?
      4. Il suffit ensuite de placer ces lignes de codes juste avant les calculs des voisins, du coup ?





    Citation Envoyé par Flodelarab Voir le message
    Pourquoi des doubles crochets ? Des simples suffisent.
    Pourquoi une évaluation arithmétique ? Aucun calcul n'est demandé.

    Le dollar devant la variable dans un contexte d'évaluation arithmétique est inutile.
    Merci pour ces indications ! J'ai corrigé !



    Excusez-moi d'être un peu long à la détente !

  8. #28
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 103
    Par défaut
    Citation Envoyé par Ezzmazz Voir le message
    J'avoue avoir un peu de mal à comprendre ce système de bord cousu...
    Je vais essayer d'être clair...

    Tu prends une feuille de papier à petits carreaux.
    Au milieu tu traces un rectangle, par exemple de 10 cases de large sur 5 cases de hauteur.
    Ce rectangle contient donc 5 lignes de 10 carrés (et également 10 colonnes de 5 carrés).
    À gauche de la 1ère colonne, tu numérotes les lignes de haut en bas de 1 à 5 (respect des conventions informatiques et non mathématiques).
    Au-dessus de la 1ère ligne tu numérotes les colonnes de 1 à 10 (de gauche à droite, à tant faire...).

    Après tu peux faire comme ma fille qui suit la mode de faire des dessins pixelisés, qui consiste à colorier certaines cases.

    Ensuite, pour suivre les spécifications du jeu de la vie, on s'intéresse aux voisins immédiats d'une case quelconque.

    Pour la case (x=6, y=3), les 8 voisins sont:
    - juste au dessus: (x, y-1) = (6, 2)
    - au-dessus à gauche: (x-1, y-1) = (5, 2)
    - au-dessus à droite: (x+1, y-1) = (7, 2)
    - juste à gauche: (x-1, y) = (5, 3)
    etc.

    Maintenant, pour une case sur l'un des bords, les voisins "immédiats" (du moins, à prendre en compte sur un tore) peuvent sembler plus "éloignés"!
    Pour la case (x=1, y=3), en ce qui concerne y, rien ne change (au-dessus: y-1; au-dessous: y+1), mais, pour x, comme il est égal à la valeur minimale, il faut faire attention. <la colonne voisine à droite correspond à x+1, mais la colonne voisine à gauche ne correspond pas à x-1, car il n'y a pas de colonne 0, mais à la colonne 10.
    Les voisins de la case (x=1, y=3) sont donc:

    - juste au dessus: (x, y-1) = (1, 2)
    - au-dessus à gauche: (N, y-1) = (10, 2)
    - au-dessus à droite: (x+1, y-1) = (2, 2)
    - juste à gauche: (N, y) = (10, 3)
    etc.

    En fait, le tore se voit mieux lorsqu'on se déplace dessus, de case en case (ce qui ne correspond pas au principe du jeu de la vie).
    Comme tu le disais, quand un pacman se déplace de case en case vers la droite, au moment où il franchit la dernière colonne, il se retrouve sur la 1ère colonne.

    Une autre manière de visualiser le tore: tu prends une chambre à air sur laquelle tu écris (disons dans le sens de la longueur...):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ABCD
    EFGH
    IJKL
    MNOP
    où B est voisin de C, où F a comme voisins ABCEGIJK, etc.
    puis tu découpes (le long d'un petit cercle) en une ligne qui sépare B de C, F de G, J de K et N de O.
    Tu obtiens un tuyau. Ensuite tu découpes dans le sens de la longueur (le long d'un grand cercle) de manière à séparer E F de I J et G H de K L.
    Tu obtiens alors un rectangle, avec ces coins-ci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    KL ..... IJ
    OP ..... MN
    ...........
    CD ..... AB
    GH ..... EF
    Si tu fais 3 photocopies de ce rectangle original (en gras) et que tu les places correctement (en translation sans rotation) autour du coin F (en bas à droite) de l'original, tu constates alors avec plaisir que les voisins de F sont toujours ABCEGIJK, comme lorsque le rectangle était "cousu" en forme de tore!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    KL ..... IJKL ..... IJ
    OP ..... MNOP ..... MN
    ......................
    CD ..... ABCD ..... AB
    GH ..... EFGH ..... EF
    KL ..... IJKL ..... IJ
    OP ..... MNOP ..... MN
    .....................
    CD ..... ABCD ..... AB
    GH ..... EFGH ..... EF

    Que cela alourdisse le code, ce n'est pas trop grave. Le but pour le moment c'est que ça fonctionne, le code sera amélioré au fur et à mesure de mon apprentissage ( je pense notamment à ajouter le fait de pouvoir placer des cellules avec les flèches du clavier, afin de bouger le curseur là où on le souhaite ).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if [[ $x == 1 ]]
                    then
                            tab[$(($x-1)),$(($y))]=$tab[$(($x-$num_columns)),$(($y))]          
                    fi

    J'ai mis ce bout de code juste au au-dessus de mon calcul de cellules voisines, dans ma fonction array_analyze_function.

    Bon évidemment, ça ne fonctionne pas
    Ben évidemment!
    Tu es en train de changer le contenu du tableau (ce qui va le sens de ma dernière préconisation de mon post précédent), mais, si tu regardes d'assez près, lorsque x est égal à 1 tu remplis la case (x-1, y), c'est-à-dire (0, y), qui ne fait PAS partie du tableau (lequel va de 1 à numcolumns) avec la valeur que l'on trouve dans la case (x-N, y). Or, comme x vaut 1, c'est la case (-9, y) (si l'on considère un tableau à N=10 colonnes), laquelle case est encore plus en dehors du tableau!?!

    Ma 1ère proposition consiste à modifier les tests. En gros, dans "array_analyze_function", à la place de:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     	 # Neighbour (x-1,y-1)
     	 [[ "${tab[$(($x-1)),$(($y-1))]}" == $CELL ]] && ((Counter++))
    il faudrait écrire quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     	 # Neighbour (x-1,y-1)
     	 if test $x -eq 1; then
     	     if test $y -eq 1; then
     	  	 [[ "${tab[$(($numcolumns)),$(($numcolumns))]}" == $CELL ]] && ((Counter++))
     	     else
     	  	 [[ "${tab[$(($numcolumns)),$(($y-1))]}" == $CELL ]] && ((Counter++))
     	     fi
     	 else
     	     if test $y -eq 1; then
     	  	 [[ "${tab[$(($x-1)),$(($numcolumns))]}" == $CELL ]] && ((Counter++))
     	     else
     	  	 [[ "${tab[$(($x-1)),$(($y-1))]}" == $CELL ]] && ((Counter++))
     	     fi
     	 fi
    C'est extrêmement lourd... Si je choisissais cette voie, je choisirais plutôt d'ajouter des variables xg, xd, yh, yb (pour gauche droite haut bas) que je calculerais ainsi (en adaptant quelque peu la syntaxe):
    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
    array_analyze_function()
    {
    tput civis
    while true
    do
      for ((x=1;x<=num_lines;x++)) 
      do
        xg = x-1; xd = x+1; # avec la bonne syntaxe...
        if test x = 1; then xg = N; elif test x = N; then xd = 1; fi
        for ((y=1;y<=num_columns;y++)) 
        do 
          if test y = 1; then yh = N; elif test y = N; then yb = 1; fi
     
          Counter=0
     
          # et que j'utiliserais ainsi:
     
          # Neighbour (xg,yh)
          [[ "${tab[$(($xg)),$(($yh))]}" == $CELL ]] && ((Counter++))
    ce qui est quand même plus léger!

    Je testerai cette solution si jamais je n'arrive pas avec le modèle torique.
    Euh... mon autre proposition est aussi basée sur le modèle torique...

    [EDIT] Laaaargement grillé...

  9. #29
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 299
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 299
    Par défaut
    Je sais que pour un calcul, il donne le reste d'une division euclidienne mais dans votre exemple, que fait-il ?
    Tu vas pas le croire : Il donne le reste de la division euclidienne aussi.

    Tu as répondu trop vite pour avoir pris le temps de comprendre.
    Regarde bien la console que j'ai postée et surtout le passage de 23 à 0 ou 0 à 23.

    Il faut donc commencer par si x à la valeur 1 donc if [ x == 1 ]
    • l'utilisation des modulos évite de s'embêter avec des conditions.
    • Ta première colonne est 1 ? Alors relis la remarque de mon message précédent.
      Si tu es entre 1 et 24, tu fais modulo 24 puis tu incrémentes. x=(x%24)+1

  10. #30
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Merci à vous pour vos explications !

    Je vais relire tout ça correctement, je reviendrai vers vous plus tard en espérant avoir réussi !


    Merci encore !

  11. #31
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Et voilà ! Un grand merci à vous deux pour avoir pris temps de m'expliquer les choses, ça fonctionne parfaitement !

    Voici ce que j'ai ajouté dans ma fonction array_analyze_function :


    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
     if [ $x -eq 1 ]
                            then
                                    xg=$num_columns
                            else
                                    xg=$(($x-1))
                            fi
     
                            if [ $x -eq $num_columns ]
                            then
                                    xd=1
                           else
                                    xd=$(($x+1))
     
                            fi
     
     
                            if [ $y -eq 1 ]
                            then
                                    yh=$num_lines
                            else
                                    yh=$(($y-1))
                            fi
     
                            if  [ $y -eq $num_lines ]
                            then
                                    yb=1
                            else
                                    yb=$(($y+1))
                            fi

    Il y avait cependant une erreur dans mon code qui faisait que ces conditions ne fonctionnaient pas correctement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    for ((x=1;x<=num_lines-1;x++)) 
     	 do
    	 	 for ((y=1;y<=num_columns-1;y++)) 
    	 	 do 
     	 	 	 tab[$x,$y]=${tabfutur[$x,$y]}
     	 	 done
     	 done


    Il suffitsait d'enlever le -1 à $num_lines et à $num_columns !
    Du coup voici le code dans son intégralité :


    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
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    #!/bin/bash
     
    Generation=0
    num_lines=0
    num_columns=0
    CELL=0
     
    declare -A tab
    declare -A tabfutur #Tempory array that will receive the future stat of each cell.
     
     
    ####################### HEADER #########################
     
    # This function displays the header.
     
    header_function()
    {
    echo ""
    echo " ═══════════════════ Conway's Game of Life ═══════════════════ "
    echo ""
    }
     
    #################### ARRAY FUNCTION #####################
     
    # This function initalizes the array and fill it with randomly 0 and 1 or with nothing.
     
    init_array_function()
    {
    for ((x=1;x<=num_lines;x++))
    do
            for ((y=1;y<=num_columns;y++)) 
            do 
     	 if [ $cell == 'a' ]
     	 then
     	 	 tab[$x,$y]=$((RANDOM %2))
     	 else
     	 	 tab[$x,$y]=
     	 fi
            done 
    done
    }
     
    #################### DISPLAY FUNCTION ####################
     
    # This function displays the array.
     
    display_function()
    {
    #header_function
    clear
    echo ""
    f1="%$((${#num_lines}+1))s"
    f2="%3s"
    printf "$f1"
     
    for ((x=1;x<=num_columns;x++)) # -1
    do
           #printf "$f2" "$x"  #Comment this line to delete the display of the abscissa.  
           toto=1 #This line is only here to avoid errors in the for loop when the abscissa is disabled.   
    done
    echo
     
    for ((y=1;y<=num_lines;y++))
    do
     
    	 #printf "$f1" $y #Comment this line to delete the display of the ordinate. 
                    for ((x=1;x<=num_columns;x++)) 
                    do 
                                    printf "$f2" "${tab[$x,$y]}"  
     	 done
                    echo 
    done
    echo ""
    echo " > Génération : $generation "
    ((generation++))
    }
     
    #################### ASK COORDINATES ####################
     
    # This function asks the user to enter the coordinates of the cell ad type 's' to run the game.
     
    coord_function()
    {
    echo ""
    echo ""
    while [ "$coord" != "s" ]
    do
      	 echo -n " + Place your cell using the array coordinates ( like '1,1' ) or press 's' to start : "
     	 read coord
     
                    if [[ "$coord" =~ ^[0-9]+,[0-9]+$ ]] ; then  x=${coord%, *} ;  y=${coord#*, } ; #2 crochets 
                    tab[$coord]="${CELL}" 
     	 display_function
                    echo "" 
     	 fi
    done
     	 start_function
    }
     
    ################################ ARRAY ANALIZE ################################
     
    # This function analyze the array and calculates the different neighbours.
     
    array_analyze_function()
    {
    tput civis
     
     for ((x=1;x<=num_columns;x++)) 
     do
     
     	 for ((y=1;y<=num_lines;y++))
    	 do 
     
    	 if [ $x -eq 1 ] 
    	 then 
    	 xg=$num_columns 
     #               	 	 echo "$xg" 
     	 	 else
    	 xg=$(($x-1))	  
    #	 	 	 	 echo "$xg"
    	 fi 
     
    	 if [ $x -eq $num_columns ] 
    	 then 
    	 xd=1 
    #	 	 	 	 echo "$xd"
    	 else 
    	 xd=$(($x+1)) 
    #	 	 	 	 echo "$xd"
    	 fi 
     
     
     	 	 if [ $y -eq 1 ]
     	 	 then 
     	 	 	 yh=$num_lines
    #	 	 	 	 echo "$yh"
     	 	 else
     	 	 	 yh=$(($y-1))
    #	 	 	 	 echo "$yh"
     	 	 	 fi
     
     	 	 if [ $y -eq $num_lines ]
     	 	 then
     	 	 	 yb=1
    #	 	 	 	 echo "$yb"
     	 	 else
     	 	 	 yb=$(($y+1))
    #	 	 	 	 echo "$yb"
     	 	 fi
     
     	 Counter=0
     
     
     	 # Neighbour (xg,yb)
     	 [[ "${tab[$((xg)),$((yb))]}" == $CELL ]] && ((Counter++)) #(x-1),(y-1)
     
     	 # Neighbour (x, yb)
     	 [[ "${tab[$((x)),$((yb))]}" == $CELL ]] && ((Counter++)) #(x),(y-1)
     
     	 # Neighbour (xd,yb)
     	 [[ "${tab[$((xd)),$((yb))]}" == $CELL ]] && ((Counter++)) # (x+1), (y-1)
     
     	 # Neighbour (xg,y)
     	 [[ "${tab[$((xg)),$((y))]}" == $CELL ]] && ((Counter++)) # (x-1), (y)
     
     	 # Neighbour (xd,y)
     	 [[ "${tab[$((xd)),$((y))]}" == $CELL ]] && ((Counter++)) # (x+1), (y)
     
     	 # Neighbour (xg,yb)
     	 [[ "${tab[$((xg)),$((yh))]}" == $CELL ]] && ((Counter++)) # (x-1), (y+1)
     
     	 # Neighbour (x,yh)
     	 [[ "${tab[$((x)),$((yh))]}" == $CELL ]] && ((Counter++)) # (x), (y+1)
     
     	 # Neighbour (xd,yh)
     	 [[ "${tab[$((xd)),$((yh))]}" == $CELL ]] && ((Counter++)) # (x+1), (y+1)
     
     	 # If the cell is alive and with two neighbours, she survives.
                    [ ${Counter} -eq 2 ] && tabfutur[${x},${y}]=${tab[$x,$y]} 
     
    	 # If the cell has 3 neighbours, either it survives or a cell is born. 
    	 [ ${Counter} -eq 3 ] && tabfutur[${x},${y}]=$CELL 
     
     	 # If th cell is alive with maximum one neighbourd, she dies.
     	 if [ $cell == 'a' ]
     	 then
     	 	 [ ${Counter} -le 1 ] && tabfutur[${x},${y}]=" "
     	 else
     	 	 [ ${Counter} -le 1 ] && tabfutur[${x},${y}]=""
     	 fi
     
    	 # If a cell has between four and eight neighbours, she dies. 
    	 if [ $cell == 'a' ] 
     	 then
     	 	 [ ${Counter} -ge 4 ] && [ ${Counter} -le 8 ] && tabfutur[${x},${y}]=" "
     	 else
     	 	 [ ${Counter} -ge 4 ] && [ ${Counter} -le 8 ] && tabfutur[${x},${y}]=""
     	 fi
     
     
     	 ######################### TEST BORDER #########################	 
     
     
     	 ################################################################
     
     	 done
     done
     	 for ((x=1;x<=num_lines;x++)) 
     	 do
    	 	 for ((y=1;y<=num_columns;y++)) 
    	 	 do 
     	 	 	 tab[$x,$y]=${tabfutur[$x,$y]}
     
     	 	 done
     	 done
    }
     
    #################### HOMEPAGE ####################
     
    # This function asks the user to enter the numbers of lines, of columns, the form of the cell or type 'a' to fill in the array randomly.
     
    homepage_function()
    {
    header_function
    echo " How many lines ? "
    echo -n " > "
    read Lines
     
            until [[ $Lines =~ ^[0-9]+$ ]] 
            do 
                    echo -e "\033[91m > Error ! Retry ! <\033[0m " 
                    echo "" 
                    echo " How many lines ? " 
                    echo -n " > " 
                    read -r Lines 
     
            done 
     
    echo ""
     
    echo " How many columns ? "
    echo -n " > "
    read Columns
     
            until [[ $Columns =~ ^[0-9]+$ ]] 
            do 
                    echo -e "\033[91m > Error ! Retry ! <\033[0m " 
                    echo "" 
                    echo " How many Columns ? " 
                    echo -n " > " 
                    read -r Columns 
            done 
    echo ""
    echo " Put the cell's form or press 'a' to fill randomly the array "
    echo -n " > "
    read -r cell
     
    while [ -z "$cell" ] 
    do
            echo -e "\033[91m > Error ! Retry ! <\033[0m " 
            echo "" 
            echo " Cell's form ? " 
            echo -n " > " 
            read -r cell 
    done	 
     
     
    Generation=0
    num_lines=$Lines
    num_columns=$Columns
    CELL=$CELL
    }
     
    #################### RUN & START FUNCTION ####################
     
    # This function starts the analysis of the array.
     
    start_function()
    {
    while true
    do
    display_function
    array_analyze_function
    done
    }
     
     
    # This function is the basic function. It allows you to launch all the other functions.
     
    run()
    {
    homepage_function
    init_array_function
    display_function
    coord_function
    }
     
    ################################ MAIN ################################
     
    clear
    echo ""
    echo "╔═══════════════════════ Conway's Game of Life ═══════════════════════╗"
    echo "║                                                                       ║" 
    echo "║    This is the Bash script version of John Conway's Game of Life.     ║" 
    echo "║       Life is a simple implementation of cellular automata.           ║" 
    echo "║                                                                       ║"                       
    echo "╠═══════════════════════════════════════════════════════════════════════╣"
    echo "║                                                                       ║" 
    echo "║                                 Rules :                               ║" 
    echo "║                                                                       ║" 
    echo "║ [1] A living cell with either 2 or 3 living neighbors remains alive. ║"
    echo "║                                                                       ║" 
    echo "║         [2] A dead cell with 3 living neighbors comes alive.          ║" 
    echo "║                                                                       ║" 
    echo "║ [2] All other cases result in a dead cell for the next generation. ║"
    echo "║                                                                       ║" 
    echo "╚═══════════════════════════════════════════════════════════════════════╝"
    echo ""
    echo ""
     
    read -p "> Press any key to continue ... "
    clear
    run



    Merci encore à vous !!

  12. #32
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 103
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 103
    Par défaut
    Bravo! (j'ai pas testé, mais je te fais confiance)

    J'ai remarqué que tu testes la valeur de "x" (pour affecter "xg" et "xd") à chaque fois que "y" change de valeur.

    Or, dans ma proposition, j'avais sorti les tests sur "x" de la boucle sur "y" car ils ne dépendent que de "x".

    Mais j'avoue que ce n'est que de la triviale optimisation!

    Et je te rappelle que l'on peut écrire xg=$((x-1)) à la place de xg=$(($x-1)), comme te l'a indiqué Flodelarab.

    Et, pendant que tu y es, tu peux remplacer [[ "${tab[$((xg)),$((yb))]}" == $CELL ]] && ((Counter++)) #(x-1),(y-1) par [[ "${tab[$xg, $yb]}" == $CELL ]] && ((Counter++)) #(x-1),(y-1) ou, si tu préfères, [[ "${tab[${xg}, ${yb}]}" == $CELL ]] && ((Counter++)) #(x-1),(y-1).

  13. #33
    Membre actif
    Profil pro
    Futur administrateur systèmes
    Inscrit en
    Décembre 2010
    Messages
    57
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Futur administrateur systèmes

    Informations forums :
    Inscription : Décembre 2010
    Messages : 57
    Par défaut
    Merci pour ces précisions ! Je vais corriger tout ça !

    Merci encore pour votre aide, je passe mon sujet en résolu de ce fait !

  14. #34
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 299
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 299
    Par défaut
    Tu demandes des conseils que tu n'appliques pas.


    Voici une petite animation d'une flèche dans un cadre fini sans bord.
    Tu peux copier/coller pour voir le comportement.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    declare -A tab;for ((i=0;i<5;i++));do for ((j=0;j<=5;j++)); do tab[$i,$j]=" ";done;done; tab[0,2]="o";tab[1,3]="o";tab[2,4]="o";tab[2,3]="o";tab[2,2]="o";tab[2,1]="o";tab[3,3]="o";tab[4,2]="o";offset=3;
    echo;echo;echo;echo;echo;echo -ne "\033[6n" && read -s -d\[ g && read -s -d R c && { offset=3;a=${c##*;};o=${c%%;*};for ((tour=0;tour<31;tour++));do let offset=offset+1; for ((lr=0;lr<5;lr++));do for ((cr=0;cr<5;cr++));do printf "\033[$((lr+o-5));$(( (cr+offset)%5+1  ))H";printf "${tab[${lr},${cr}]}";done;done;echo;sleep 0.15;done; }
    La première ligne est préparatoire et la seconde est exécutoire
    Le code à regarder particulièrement est celui-ci :
    Pas de if, et personne sans voisin... si tu vois ce que je veux dire.

  15. #35
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 408
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 408
    Par défaut
    Bonjour,

    Juste une petite remarque concernant le code par lui même, étant donné que tu te destines à l'administration système, c'est que tu utilises beaucoup de fonction mais par contre, la plupart ne fonctionneraient pas si on les exécutait en dehors du programme car elles dépendent de variables initialisées ailleurs.

    En principe, dans les bonnes pratiques, les variables qui ne sont utilisées que par la fonction, on les déclare localement à celle-ci et si on a besoin de valeurs extérieurs à la fonction, dans ce cas, on passe la/les valeurs en paramètres à celle-ci.

    Le seul cas à discussion, c'est le besoin d'une variable qui sera initialisée/modifiée par plusieurs fonctions qui ne s'appellent pas entre elles mais qui ont besoin de partager de l'information. Dans ce cas, on admet encore l'utilisation de variables globales, même si on préférera quand le shell utilisé le permet, de faire du passage par référence (ce qui est le cas en bash).

    De plus, ceci est l'une des bonnes pratiques aussi en python,perl,java,...

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Problème jeu de la vie de Wolfram
    Par romromp dans le forum Pascal
    Réponses: 14
    Dernier message: 11/03/2007, 20h58
  2. algorithme d'évolution du "jeu de la vie" en caml
    Par nono88 dans le forum Algorithmes et structures de données
    Réponses: 6
    Dernier message: 13/12/2006, 01h56
  3. Conway's life (jeu de la vie) pour images
    Par O( N ) dans le forum C
    Réponses: 1
    Dernier message: 26/09/2006, 03h13
  4. [Conception] Jeu de la vie
    Par deuscapser dans le forum Général Java
    Réponses: 16
    Dernier message: 09/03/2006, 13h47
  5. [VB] projet à réaliser: Jeu de la vie
    Par mauriiice dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 02/12/2005, 21h06

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