#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
int best = 0 ;
// 定义2048游戏的结构体
typedef struct {
int martix[16]; // 当前4*4矩阵的数字
int martixPrior[16]; // 上一步的4*4矩阵的数字
int emptyIndex[16]; // 空位置的索引值
int emptyCount; // 空位置的数量
int score; // 当前的分数
int step; // 记录操作步数
}Game;
int solve_best(int best){
FILE *file;
file = fopen("C:/Users/Redmi/Desktop/a.txt", "w"); // 以写入方式打开文件,如果文件不存在则创建
if (file == NULL) {
perror("Error opening file");
return -1;
}
// 向文件中写入内容
fprintf(file, "%d", best);
fclose(file); // 关闭文件
}
int get_best(){
FILE *file;
// 打开文件以读取原有数字
file = fopen("C:/Users/Redmi/Desktop/a.txt", "r");
if (file == NULL) {
perror("Error opening file for reading");
return -1;
}
int num = 0 ;
// 读取原有数字
int originalNumber;
if (fscanf(file, "%d", &num) != 1) {
perror("Error reading original number from file");
fclose(file);
return -1;
}
fclose(file); // 关闭文件
return num ;
}
// 生成[min, max]的随机整数
int RandomInt(int min, int max) {
srand((unsigned)time(NULL) + rand()); //以时间为随机种子
return min + rand() % (max - min + 1);
}
// 结构体的初始化
void gameInit(Game *game) {
int i;
game->score = 0;
game->step = 0;
game->emptyCount = 16;
for(i = 0; i < 16; i++) {
game->martix[i] = 0;
game->martixPrior[i] = 0;
game->emptyIndex[i] = -1;
}
}
// 空位检测
void emptyDetect(Game *game) {
int i = 0, j = 0;
game->emptyCount = 0;
for(i = 0; i < 16; i++) { game->emptyIndex[i] = -1; }
for(i = 0; i < 16; i++) {
if (game->martix[i] == 0) {
game->emptyIndex[j++] = i;
game->emptyCount++;
}
}
}
// 在随机空位生成数字
void numberGenerate(Game *game) {
int pos, numberIs4;
numberIs4 = RandomInt(0, 3); // 生成数字4的概率,这里为 1/4
pos = game->emptyIndex[RandomInt(0, game->emptyCount - 1)];
if (numberIs4 == 0) { game->martix[pos] = 4; } else { game->martix[pos] = 2; }
}
// 获取某行或某列
int *getLine(int *martix, int row, int col) {
int i, *array;
array = (int *)malloc(sizeof(int)*4);
for (i = 0; i < 4; i++) {
if (col != -1) { *(array+i) = *(martix + col+(i*4)); }
if (row != -1) { *(array+i) = *(martix + row*4+i); }
}
return array;
}
// 数字边缘对齐
int *numberAlign(int *array, int reverse) {
// reverse : 0: 向左对齐、向上对齐; 1: 向右对齐,向下对齐
// 0 0 2 0 --> 2 0 0 0
// 2 0 2 0 --> 2 2 0 0
int i, j;
int *newArray;
newArray = (int *)malloc(sizeof(int)*4);
for(j = 0; j < 4; j++) { *(newArray + j) = 0; }
if (reverse == 0) {
j = 0;
for(i = 0; i < 4; i++) {
if (*(array + i) != 0) {
*(newArray + j) = *(array + i);
j++;
}
}
}
if (reverse == 1) {
j = 3;
for(i = 3; i >= 0; i--) {
if (*(array + i) != 0) {
*(newArray + j) = *(array + i);
j--;
}
}
}
return newArray;
}
// 相邻数字相加
int *numberMerge(Game *game, int *array, int reverse) {
int i, j, num1, num2;
int *newArray;
newArray = (int *)malloc(sizeof(int)*4);
if (reverse == 0) {
j = 0;
for (i = 0; i < 4; i++) {
num1 = *(array + i);
num2 = 0;
if (i != 3) { num2 = *(array + i + 1); }
if (num1 == num2 && num1 > 0 && num2 > 0) {
*(newArray + j) = num1 + num2;
*(array + i + 1) = 0;
game->score += (num1 + num2);
} else {
*(newArray + j) = *(array + i);
}
j++;
}
}
if (reverse == 1) {
j = 3;
for (i = 3; i >= 0; i--) {
num1 = *(array + i);
num2 = 0;
if (i != 0) { num2 = *(array + i - 1); }
if (num1 == num2 && num1 > 0 && num2 > 0) {
*(newArray + j) = num1 + num2;
*(array + i - 1) = 0;
game->score += (num1 + num2);
} else {
*(newArray + j) = *(array + i);
}
j--;
}
}
return newArray;
}
// 数字移动
void numberMoving(Game *game, int direction) {
int *line[4];
int i, j;
switch(direction) {
case 1:
for (i = 0; i < 4; i++) {
line[0] = getLine(game->martix, i, -1);
line[1] = numberAlign(line[0], 0);
line[2] = numberMerge(game, line[1], 0);
line[3] = numberAlign(line[2], 0);
for (j = 0; j < 4; j++) {
game->martix[i*4+j] = *(line[3] + j);
game->martixPrior[i*4+j] = *(line[0] + j);
}
}
break;
case 2:
for(i = 0; i < 4; i++) {
line[0] = getLine(game->martix, i, -1);
line[1] = numberAlign(line[0], 1);
line[2] = numberMerge(game, line[1], 1);
line[3] = numberAlign(line[2], 1);
for (j = 0; j < 4; j++) {
game->martix[i*4+j] = *(line[3] + j);
game->martixPrior[i*4+j] = *(line[0] + j);
}
}
break;
case 3:
for(i = 0; i < 4; i++) {
line[0] = getLine(game->martix, -1, i);
line[1] = numberAlign(line[0], 0);
line[2] = numberMerge(game, line[1], 0);
line[3] = numberAlign(line[2], 0);
for (j = 0; j < 4; j++) {
game->martix[i+4*j] = *(line[3] + j);
game->martixPrior[i+4*j] = *(line[0] + j);
}
}
break;
case 4:
for(i = 0; i < 4; i++) {
line[0] = getLine(game->martix, -1, i);
line[1] = numberAlign(line[0], 1);
line[2] = numberMerge(game, line[1], 1);
line[3] = numberAlign(line[2], 1);
for (j = 0; j < 4; j++) {
game->martix[i+4*j] = *(line[3] + j);
game->martixPrior[i+4*j] = *(line[0] + j);
}
}
break;
}
for (j = 0; j < 4; j++) { free(line[j]); }
}
// 游戏结束判定
int gameOverDetect(Game *game) {
// 当判定为输时返回 1
int i, j, row, col;
if (game->emptyCount > 0) { return 0; }
for (i = 0; i < 16; i++) {
int numberBeside[4] = {0, 0, 0, 0}; // 相邻上下左右四个位置的数字
row = i / 4;
col = i % 4;
if (row - 1 >= 0) { numberBeside[0] = game->martix[(row-1)*4+col]; } // 获取上面的数字
if (row + 1 < 4) { numberBeside[1] = game->martix[(row+1)*4+col]; } // 获取下面的数字
if (col - 1 >= 0) { numberBeside[2] = game->martix[row*4+(col-1)]; } // 获取左边的数字
if (col + 1 < 4) { numberBeside[3] = game->martix[row*4+(col+1)]; } // 获取右边的数字
for(j = 0; j < 4; j++) {
if (game->martix[i] == numberBeside[j]) { return 0; }
}
}
return 1;
}
// 键盘操作
int keyboardPress() {
// 返回值: 0: 无效操作; 1、2、3、4: 左右上下;
int charAscii;
charAscii = _getch();
if (charAscii == 65 || charAscii == 97) { return 1; } // A, 左
if (charAscii == 68 || charAscii == 100) { return 2; } // D, 右
if (charAscii == 87 || charAscii == 119) { return 3; } // W, 上
if (charAscii == 83 || charAscii == 115) { return 4; } // S, 下
return 0;
}
// 检查数字是否移动过
int checkNumberMove(Game *game) {
// 返回值: 0: 数字没有移动过; 1: 数字移动过
int i;
for(i = 0; i < 16; i++) {
if (game->martix[i] != game->martixPrior[i]) { return 1; }
}
return 0;
}
// 游戏开始时随机生成2个数字
void gameStart(Game *game) {
int i;
gameInit(game);
emptyDetect(game);
numberGenerate(game);
emptyDetect(game);
numberGenerate(game);
emptyDetect(game);
}
// 绘制画面
void drawGame(Game *game) {
int row;
system("cls");
printf("\n GAME : 2 0 4 8 BEST : %d \n",best);
printf("\n按键说明: W:上 A:左 S:下 D:右\n\n");
for(row = 0; row < 4; row++) {
if (row == 0) { printf("---------------------------------\n"); }
printf("|\t|\t|\t|\t|\n");
if (game->martix[row*4] != 0) { printf("|%7d", game->martix[row*4]); } else { printf("|\t"); }
if (game->martix[row*4+1] != 0) { printf("|%7d", game->martix[row*4+1]); } else { printf("|\t"); }
if (game->martix[row*4+2] != 0) { printf("|%7d", game->martix[row*4+2]); } else { printf("|\t"); }
if (game->martix[row*4+3] != 0) { printf("|%7d|\n", game->martix[row*4+3]); } else { printf("|\t|\n"); }
printf("|\t|\t|\t|\t|\n");
printf("---------------------------------\n");
}
printf("步数: %d\n分数: %d\n\n", game->step, game->score);
}
// 主程序
int main() {
Game *gamePtr;
int key;
best = get_best() ;
gamePtr = (Game *)malloc(sizeof(Game));
gameInit(gamePtr);
gameStart(gamePtr);
drawGame(gamePtr);
while(gameOverDetect(gamePtr) != 1) {
key = keyboardPress();
// 移动数字后生成数字
if (key != 0) {
numberMoving(gamePtr, key);
if (checkNumberMove(gamePtr) != 0) {
emptyDetect(gamePtr);
numberGenerate(gamePtr);
emptyDetect(gamePtr);
gamePtr->step += 1;
drawGame(gamePtr);
}
}
}
printf("%d\n",gamePtr->score);
if(gamePtr->score > best){
solve_best(best) ;
}
printf("\n游 戏 结 束 !\n");
return 0;
}
效果 :