Я пытаюсь воссоздать игру 2048 в C, но я не могу заставить алгоритмы перемещать или объединять плитки вместе, чтобы нормально функционировать. В оригинальной игре 2048 вы бы переместить плитки вместе, как это:Алгоритм слияния плитки 2048 игра
2 | 2 | 4 | 4 4 | 8 | |
---+---+---+--- *swipes to the left* -> ---+---+---+---
8 | | 8 | 16| | |
So две плитки, которые являются такими же, можно объединить в одну плитку, которая в два раза больше. Моя версия почти то же самое, но вместо использования чисел я использую символы, которые увеличиваются на единицу при слиянии, поэтому [A|A]
будет сливаться с [B]
и т. Д. Я сделал это, чтобы не иметь дело с плитами различного размера.
Так что мой совет хранится как массив символов 4 * 4 внутри структуры я назвал сетку (вероятно, я знаю немного избыточен)
typedef struct grid {
char tiles[4][4];
} Grid;
Я попытался сделать алгоритмы для перемещения и слияния вверх, вниз , слева и справа, но они не работают должным образом.
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
}
}
Я протестировал эти алгоритмы с помощью некоторых hardcoded testdata. Алгоритм, чтобы нажимать плитки слева, кажется, работает правильно. pushRight почти работает, но он объединяет два уровня одновременно, поэтому [B|A|A]
сливается в [C]
, но должен сливаться в [B|B]
.
pushUp похоже почти всегда просто вытирает всю доску пустым черепицей (пробелы). pushDows, кажется, удаляет некоторые плитки.
Кто-нибудь видит проблему или знает способ сделать это? Я думал об использовании рекурсивных алгоритмов, но я просто не могу обернуть вокруг себя.
A плитка не может быть объединена дважды за один ход, поэтому следует учитывать маркировку плитки, которая является результатом слияния как такового. Затем вы должны проверить, что до слияния, а также отмеченные таким образом плитки не могут быть слиты во время этого перемещения. –
Спасибо за комментарий. Я попытался реализовать его, используя флаг в самом внутреннем цикле, который идет false, если текущая черепица слита. Теперь я вижу, что этого недостаточно, поскольку следующая плитка, которая толкается, может слиться с ранее вдавленной плиткой. – larso