设计思路
- 游戏地图和初始设置:
- 使用一个 4x4 的二维数组
map
来表示游戏地图。 - 初始时,所有位置的值均为 0。
score
记录玩家得分,move_num
记录移动次数。
- 使用一个 4x4 的二维数组
- 随机生成数字:
- 在地图上随机选择一个空位置生成 2 或 4。
- 只有在地图发生变化时才会生成新数字。
- 游戏菜单:
- 使用
menu()
函数显示当前的游戏状态,包括地图、得分和移动次数。 - 提示玩家使用 W、A、S、D 键进行移动。
- 使用
- 玩家移动:
- 使用
move()
函数读取玩家输入,并根据输入的方向调用相应的移动函数 (up()
、left()
、down()
、right()
)。 - 每个移动函数都负责处理特定方向的移动,并更新地图。
- 使用
- 移动逻辑:
- 移动时首先合并相同的数字,然后将非零元素向目标方向移动填补空格。
change
变量用于记录地图是否发生变化,以决定是否生成新数字。
- 游戏结束判断:
- 使用
over()
函数检查游戏是否结束。 - 游戏结束的条件是:地图没有空位且没有相邻的相同数字。
- 若游戏结束,输出最终得分和移动次数。
- 使用
细节分析
- 随机数生成:使用
rand()
函数生成随机位置和数字,但未处理随机数种子的初始化位置,可能会导致每次运行的结果相同。 - 输入处理:使用
getch()
函数获取用户输入,并根据输入调用相应的移动函数。 - 移动实现:每个方向的移动函数都按照特定的顺序检查并合并相同的数字,然后移动非零元素。
- 游戏结束检测:遍历整个地图,检查是否还有空位或相邻的相同数字。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h> // 用于 getch 函数
int map[4][4] = {0}; // 游戏地图
int score = 0; // 玩家得分
int move_num = -1; // 移动次数
int game_over = 1; // 游戏结束标志,0表示游戏结束
int change = 1; // 跟踪地图是否发生变化,0表示没有变化
char input; // 控制方向
// 函数声明
void start();
void randIntNum();
void menu();
void move();
int up();
int left();
int down();
int right();
int over();
// 在数组中随机生成一个位置并赋值2或4
void randIntNum()
{
int i, j, n;
if (change >= 1) // 只有在地图变化时才生成新数字
{
do
{
i = rand() % 4; // 随机行索引
j = rand() % 4; // 随机列索引
} while (map[i][j] != 0); // 确保位置为空
n = rand() % 2; // 随机选择0或1
map[i][j] = (n == 0) ? 2 : 4; // 将2或4赋值给选中的位置
move_num++; // 增加移动计数
}
}
// 显示游戏菜单
void menu()
{
system("cls"); // 清屏
int i, j;
printf(" 欢迎来到2048\n");
printf(" ----------------------------------------\n");
printf(" W——UP S——DOWN A——LEFT D——RIGHT\n");
printf(" 请按0退出游戏。\n");
printf(" MOVE:%d SCORE:%d\n", move_num, score);
printf(" \n |-------------------------------------------|\n");
for (i = 0; i <= 3; i++)
{
for (j = 0; j <= 3; j++)
{
printf(" ");
if (map[i][j] == 0)
printf("| ");
else
printf("|%5d", map[i][j]);
}
printf(" |\n |-------------------------------------------|\n");
}
}
// 处理玩家的移动
void move()
{
char ch = getch(); // 从键盘读取控制输入
change = 0; // 重置变化跟踪器
switch (ch)
{
case '0': // 如果玩家输入'0'
printf("确定要退出吗?(y/n)\n"); // 确认退出
ch = getchar();
if (ch == 'y' || ch == 'Y') // 如果是,退出游戏
exit(0);
break;
case 'w': // 上移
case 'W':
up();
break;
case 'a': // 左移
case 'A':
left();
break;
case 's': // 下移
case 'S':
down();
break;
case 'd': // 右移
case 'D':
right();
break;
default: // 无效输入
printf("无效输入,请重新输入!\n");
break;
}
}
// 向上移动
int up()
{
int now, next;
int i, j, k;
for (j = 0; j < 4; j++)
{
for (i = 0; i < 4; i++)
{
now = map[i][j];
{
k = i + 1;
while (k < 4)
{
next = map[k][j];
if (next != 0)
{
if (now == next)
{
change = 1;
score += map[k][j] * 2;
map[i][j] = 2 * map[k][j];
map[k][j] = 0;
}
k = 4;
}
k++;
}
}
}
}
// 将非零元素向上移动,填补空格
for (j = 0; j < 4; j++)
{
for (i = 0; i < 4; i++)
{
now = map[i][j];
if (now == 0)
{
k = 1 + i;
while (k < 4)
{
next = map[k][j];
if (next != 0)
{
change = 1;
map[i][j] = next;
map[k][j] = 0;
k = 4;
}
k++;
}
}
}
}
return change;
}
// 向右移动
int right()
{
int i, j;
int now, next, k;
for (i = 0; i < 4; i++)
{
for (j = 3; j >= 0; j--)
{
now = map[i][j];
k = j - 1;
while (k >= 0)
{
next = map[i][k];
if (next != 0)
{
if (next == now)
{
change = 1;
score += map[i][k] * 2;
map[i][j] = map[i][k] * 2;
map[i][k] = 0;
}
k = -1;
}
k--;
}
}
}
// 将非零元素向右移动,填补空格
for (i = 0; i < 4; i++)
{
for (j = 3; j >= 0; j--)
{
now = map[i][j];
if (now == 0)
{
k = j - 1;
while (k >= 0)
{
next = map[i][k];
if (next != 0)
{
change = 1;
map[i][j] = map[i][k];
map[i][k] = 0;
k = -1;
}
k--;
}
}
}
}
return change;
}
// 向左移动
int left()
{
int i, j;
int now, next, k;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
now = map[i][j];
k = j + 1;
while (k < 4)
{
next = map[i][k];
if (next != 0)
{
if (now == next)
{
change = 1;
score += 2 * map[i][k];
map[i][j] = map[i][k] * 2;
map[i][k] = 0;
}
k = 4;
}
k++;
}
}
}
// 将非零元素向左移动,填补空格
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
now = map[i][j];
if (now == 0)
{
k = j + 1;
while (k < 4)
{
next = map[i][k];
if (next != 0)
{
change = 1;
map[i][j] = map[i][k];
map[i][k] = 0;
k = 4;
}
k++;
}
}
}
}
return change;
}
// 向下移动
int down()
{
int i, j;
int now, next, k;
for (j = 0; j < 4; j++)
{
for (i = 3; i >= 0; i--)
{
now = map[i][j];
if (now != 0)
{
k = i - 1;
while (k >= 0)
{
next = map[k][j];
if (next != 0)
{
if (now == next)
{
change = 1;
score += map[k][j] * 2;
map[i][j] = map[k][j] * 2;
map[k][j] = 0;
}
k = -1;
}
k--;
}
}
}
}
// 将非零元素向下移动,填补空格
for (j = 0; j < 4; j++)
{
for (i = 3; i >= 0; i--)
{
now = map[i][j];
if (now == 0)
{
k = i - 1;
while (k >= 0)
{
next = map[k][j];
if (next != 0)
{
change = 1;
map[i][j] = map[k][j];
map[k][j] = 0;
k = -1;
}
k--;
}
}
}
}
return change;
}
// 结束函数
int over()
{
// 检查游戏是否结束
game_over = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
//判断地图里是否还有空位
if (map[i][j] == 0)
{
game_over = 1;
break;
}
//判断是否有相同的两个数字挨在一起,若有则gameover改为1,
if (i > 1)
{
if (map[i][j] == map[i - 1][j])
game_over = 1;
break;
}
if (j > 1)
{
if (map[i][j] == map[i][j - 1])
{
game_over = 1;
break;
}
}
}
if (game_over == 1)
break;
}
if (game_over == 0) // 游戏结束
{
printf("游戏结束!\n最终得分:%d\n", score);
printf("移动次数:%d\n", move_num);
}
}
// 游戏开始函数
void start()
{
srand((unsigned)time(NULL)); // 初始化随机数生成器
while (game_over) // 游戏循环
{
randIntNum(); // 在随机位置生成初始数字
menu(); // 显示菜单
move(); // 处理玩家输入和移动
over();
}
}
int main()
{
start(); // 开始游戏
return 0;
}