Algorithme de fusion de tuiles 2048 jeu


J'essaie de recréer le jeu 2048 en C, mais je ne peux pas obtenir les algorithmes pour déplacer ou fusionner les tuiles ensemble pour fonctionner correctement. Dans le jeu original de 2048, vous déplaceriez des tuiles ensemble comme ceci:

 2 | 2 | 4 | 4                             4 | 8 |   |   
---+---+---+---  *swipes to the left* ->  ---+---+---+---
 8 |   | 8 |                               16|   |   |

Ainsi, deux tuiles identiques peuvent fusionner en une seule tuile deux fois plus grande. Ma version est presque la même, mais au lieu d'utiliser des nombres, j'utilise des caractères qui incrémentent d'un lorsqu'ils fusionnent, donc[A|A] fusionnerait en [B], etc. Je l'ai fait seulement pour ne pas avoir à traiter avec en variant la taille des tuiles.

Donc, ma carte est stockée sous forme de tableau de caractères 4*4 dans une structure que j'ai appelée grid (je sais probablement un peu redondant)

typedef struct grid {
    char tiles[4][4];
} Grid;

J'ai essayé de créer des algorithmes pour se déplacer et fusionner vers le haut, le bas, la gauche et la droite, mais ils ne fonctionnent pas correctement.

void pushLeft(Grid * grid)
{
    int i, j, k;
    for(i = 0; i < 4; i++) //Row number i
    {
        for(j = 1; j < 4; j++) //Column number j
        {
            if(grid->tiles[i][j] != ' ') //tile is not empty
            {
                int flag = 1; //flag to prevent merging more than one level at a time
                //Starting on column k, push tile as far to the left as possible
                for(k = j; k > 0; k--)
                {
                    if(grid->tiles[i][k-1] == ' ') //neighbor tile is empty
                    {
                        grid->tiles[i][k-1] = grid->tiles[i][k];
                        grid->tiles[i][k] = ' ';
                    }
                    else if(grid->tiles[i][k-1] == grid->tiles[i][k] && flag) //neighbor equals
                    {
                        grid->tiles[i][k-1]++;
                        grid->tiles[i][k] = ' ';
                        flag = 0;
                    }
                    else //Can't push or merge
                    {
                        flag = 1;
                        break;
                    }
                }
            }
        } // Done with row
    }
}

void pushRight(Grid * grid)
{
    int i, j, k;
    for(i = 0; i < 4; i++) //Row number i
    {
        for(j = 2; j >= 0; j--) //Column number j
        {
            if(grid->tiles[i][j] != ' ') //tile is not empty
            {
                int flag = 1; //flag to prevent merging more than one level at a time
                //Starting on column k, push tile as far to the right as possible
                for(k = j; k < 3; k++)
                {
                    if(grid->tiles[i][k+1] == ' ') //neighbor tile is empty
                    {
                        grid->tiles[i][k+1] = grid->tiles[i][k];
                        grid->tiles[i][k] = ' ';
                    }
                    else if(grid->tiles[i][k+1] == grid->tiles[i][k] && flag) //neighbor equals
                    {
                        grid->tiles[i][k+1]++;
                        grid->tiles[i][k] = ' ';
                        flag = 0;
                    }
                    else //Can't push or merge
                    {
                        flag = 1;
                        break;
                    }
                }
            }
        } // Done with row
    }
}

void pushUp(Grid * grid)
{
    int i, j, k;
    for(i = 0; i < 4; i++) //Column number i
    {
        for(j = 1; j < 4; j++) //Row number j
        {
            if(grid->tiles[j][i] != ' ') //tile is not empty
            {
                int flag = 1; //flag to prevent merging more than one level at a time
                //Starting on row k, push tile as far upwards as possible
                for(k = j; k > 0; k--)
                {
                    if(grid->tiles[k-1][i] == ' ') //neighbor tile is empty
                    {
                        grid->tiles[k-1][i] = grid->tiles[i][k];
                        grid->tiles[k][i] = ' ';
                    }
                    else if(grid->tiles[k-1][i] == grid->tiles[i][k] && flag) //neighbor equals
                    {
                        grid->tiles[k-1][i]++;
                        grid->tiles[k][i] = ' ';
                        flag = 0;
                    }
                    else //Can't push or merge
                    {
                        flag = 1;
                        break;
                    }
                }
            }
        } // Done with column
    }
}

void pushDown(Grid * grid)
{
    int i, j, k;
    for(i = 0; i < 4; i++) //Column number i
    {
        for(j = 2; j >= 0; j--) //Row number j
        {
            if(grid->tiles[j][i] != ' ') //tile is not empty
            {
                int flag = 1; //flag to prevent merging more than one level at a time
                //Starting on row k, push tile as far down as possible
                for(k = j; k < 3; k++)
                {
                    if(grid->tiles[k+1][i] == ' ') //neighbor tile is empty
                    {
                        grid->tiles[k+1][i] = grid->tiles[i][k];
                        grid->tiles[k][i] = ' ';
                    }
                    else if(grid->tiles[k+1][i] == grid->tiles[i][k] && flag) //neighbor equals
                    {
                        grid->tiles[k+1][i]++;
                        grid->tiles[k][i] = ' ';
                        flag = 0;
                    }
                    else //Can't push or merge
                    {
                        flag = 1;
                        break;
                    }
                }
            }
        } // Done with column
    }
}

J'ai testé ces algorithmes avec des données de test codées en dur. L'algorithme pour pousser les tuiles vers la gauche semble fonctionner correctement. pushRight fonctionne presque, mais il fusionne deux niveaux en même temps, donc [B|A|A] fusionne dans [C] mais devrait fusionner en [B|B].

PushUp semble être presque toujours juste essuyer la carte entière avec des tuiles vides (espaces). pushDows semble enlever certaines tuiles.

Quelqu'un voit-il le problème ou connaît-il un moyen de le faire? J'ai pensé à utiliser des algorithmes récursifs, mais je ne peux tout simplement pas enrouler ma tête autour de lui.

Author: i_am_jorf, 2014-12-12

2 answers

Personnellement, je diviserais le balayage en deux étapes car le balayage vers la gauche et le balayage vers la droite sont en fait fonctionnellement les mêmes en ce qui concerne la combinaison de tuiles. La seule différence est que les tuiles restantes sont groupées à gauche ou à droite selon la direction.

Voici un algorithme rapide pour remplacer deux tuiles par une nouvelle. Je scanne gauche- > droite et remplace la tuile gauche par la nouvelle tuile, met à zéro la tuile droite, puis assurez-vous d'exclure cette nouvelle tuile de comparaison:

typedef struct grid {
    char tiles[4][4];
} Grid;

void eliminateHoriz (Grid* g)
{
    int row, col, col2;
    for (row=0; row<4; row++)
    {
        for (col=0; col<4; col++)
        {
            if (g->tiles[row][col])
            {
                for (col2=col+1; col2<4; col2++)
                {
                    if (g->tiles[row][col2])
                    {
                        if (g->tiles[row][col] == g->tiles[row][col2])
                        {
                            g->tiles[row][col++] *= 2;
                            g->tiles[row][col2] = 0;
                        }
                        break;
                    }
                }
            }
        }
    }
}

void showGrid (Grid* g)
{
    int row, col;
    for (row=0; row<4; row++)
        for (col=0; col<4; col++)
            printf ("%4d%c",
                g->tiles[row][col],
                col == 3 ? '\n' : ' ');
    printf ("\n");
}

int main() 
{
    Grid g = {{2,2,4,4, 
               8,0,8,0,
               8,8,8,4, 
               2,2,2,2}};

    showGrid (&g);
    eliminateHoriz (&g);
    showGrid (&g);

    system ("pause");
    return 0;
}

Sortie de ceci:

   2    2    4    4
   8    0    8    0
   8    8    8    4
   2    2    2    2

   4    0    8    0
  16    0    0    0
  16    0    8    4
   4    0    4    0

Après cela, une simple étape de compactage pourrait être effectuée, ou sortir en temps réel dans un second tampon, ou qui jamais. Moins de dédoublements.

 0
Author: Chris, 2014-12-11 23:10:32

J'ai seulement fait le cas de pousser les lignes vers la gauche, mais c'est la même méthode pour chaque direction. J'ai pris le code de la réponse et l'ai modifié; jetez un oeil:

typedef struct grid {
    int tiles[4][4];
} Grid;

/* Functions prototypes */

void pushLeft(Grid* grid);
void showGrid (Grid* g);
void find_great_tile(Grid* grid);

/*  Main function   */

int main() 
{
    Grid g = {{4,2,2,8, 
               2,8,2,2,
               16,2,0,2, 
               128,128,64,64}};

    /*

    The sequence is:

    --> Show the grid
    --> PushLeft
    --> Find great tile
    --> PushLeft
    --> Show the grid

    */

    printf("\n\n\n\n");
    showGrid (&g);
    printf("\n\n\n\n");
    pushLeft(&g);
    showGrid (&g);
    printf("\n\n\n\n");
    find_great_tile(&g);
    showGrid(&g);
    printf("\n\n\n\n");
    pushLeft(&g);
    showGrid(&g);
    printf("\n\n\n\n");

    return 0;
}

/* Functions definitions */

void pushLeft(Grid* grid){

    int row, col, col2;

    for (row = 0; row < 4; row++)
    {
        for (col = 0; col < 4; col++)
        {
            if (!grid->tiles[row][col])
            {
                for (col2 = col+1; col2 < 4; col2++)
                {
                    if (grid->tiles[row][col2])
                    {

                        /*
                        if (grid->tiles[row][col] == grid->tiles[row][col2])
                        {
                            grid->tiles[row][col++] *= 2;
                            grid->tiles[row][col2] = 0;
                        }

                        break;
                        */

                        grid->tiles[row][col] = grid->tiles[row][col2];
                        grid->tiles[row][col2] = 0;

                        break;
                    }
                }
            }
        }
    }
}

void showGrid (Grid* grid){

    int row, col;

        for(row = 0; row < 4; row++){

            fprintf(stdout, "\t\t     |");

            for(col = 0; col < 4; col++)
            {

            /*
             In case there's any number in the matrix, it will print those numbers, otherwise, it'll print a space (it is the alternative of putting a 0)
             */

                if(grid->tiles[row][col])
                {
                    printf("%4d    |", grid->tiles[row][col]);
                }else
                    printf("%4c    |", ' ');
            }

            fprintf(stdout, "\n\n");
        }
}

void find_great_tile(Grid* grid){

    int row, col, col2;

    for(row = 0; row < 4; row++)
    {
        for(col = 0; col < 4; col++)
        {
            if(grid->tiles[row][col])
            {
                col2 = col+1;

                if(grid->tiles[row][col2])
                {
                    if(grid->tiles[row][col] == grid->tiles[row][col2])
                    {
                        grid->tiles[row][col++] *= 2;

                        grid->tiles[row][col2] = 0;
                    }
                }
            }
        }
    }
}

Sortie de ceci:

         |   4    |   2    |   2    |   8    |

         |   2    |   8    |   2    |   2    |

         |  16    |   2    |        |   2    |

         | 128    | 128    |  64    |  64    |





         |   4    |   2    |   2    |   8    |

         |   2    |   8    |   2    |   2    |

         |  16    |   2    |   2    |        |

         | 128    | 128    |  64    |  64    |





         |   4    |   4    |        |   8    |

         |   2    |   8    |   4    |        |

         |  16    |   4    |        |        |

         | 256    |        | 128    |        |





         |   4    |   4    |   8    |        |

         |   2    |   8    |   4    |        |

         |  16    |   4    |        |        |

         | 256    | 128    |        |        |

Bien sûr, vous pouvez compresser les étapes en faisant:

> > PushLeft

> > FindGreatTile

> > PushLeft

 0
Author: Missionpage, 2017-05-07 18:22:58