官方网站优化价格,淘淘乐网站建设,做影视网站会侵权犯法吗,找人帮忙注册app推广不是#xff0c;一天点赞就到15了#xff1f;#xff01;好吧#xff0c;那我更新一下 
1. 逻辑 
#xff08;真的有人会看吗#xff1f;#xff09; 
注#xff1a;本文1.1章为AI生成#xff0c;如有错误欢迎在评论其指出#xff01; 
1.1 普通/最初逻辑 
这里我们首…不是一天点赞就到15了好吧那我更新一下 
1. 逻辑 
真的有人会看吗 
注本文1.1章为AI生成如有错误欢迎在评论其指出 
1.1 普通/最初逻辑 
这里我们首先考虑最初的逻辑 
通常游戏会有初始化、绘制界面、处理输入、更新游戏状态、判断胜负等部分。所以可能需要一个二维数组来表示4x4的网格存储每个格子的数值。然后需要处理键盘输入尤其是方向键的控制这可能需要使用EasyX的键盘事件处理函数。 然后关于图形绘制部分每个格子的大小、颜色、数字的显示都需要设计。不同的数字对应不同的颜色比如2是浅色4稍深以此类推。可能需要一个函数根据数字的值返回对应的颜色然后在绘制时调用。 接下来处理数字的移动和合并逻辑。这是比较复杂的部分。例如当用户按下右方向键时所有数字向右移动并且相邻相同的数字合并。这个过程需要分步骤处理先移动再合并再移动。每个方向的处理逻辑可能不同需要分别处理。比如向右移动的话每一行从右往左处理合并相同的数字并累加分值。这里可能需要四个不同的函数来处理四个方向或者找到一种统一的方式处理。 另外每次操作后需要在空白的位置随机生成一个2或4。需要记录所有空位的位置随机选择一个位置并生成数字。这一步需要每次操作后检查是否有空位没有的话游戏结束。 游戏结束的条件有两个一是所有格子填满且无法合并二是有一个格子达到2048即胜利。需要编写函数来检测这两种情况。 然后测试各个部分的功能是否正确。比如移动和合并是否正常分数是否正确计算界面是否正常刷新游戏结束的判断是否准确等。 可能的难点包括正确处理不同方向的移动和合并逻辑避免重复合并例如在一次移动中合并过的块不能再合并以及高效地检测游戏是否结束。 另外用户体验方面每次操作后需要刷新界面可能需要添加动画效果但考虑到EasyX的简单性可能只做简单的重绘。同时显示当前分数和最高分数可能需要全局变量来记录这些信息。 现在考虑代码的大致结构 1. 包含头文件graphics.h用于EasyXconio.h可能用于键盘输入time.h和stdlib.h用于随机数生成。 2. 定义常量如格子大小、窗口尺寸、颜色数组等。 3. 全局变量网格数组、分数、是否结束等。 4. 初始化函数初始化窗口设置随机种子初始化网格数组生成初始数字。 5. 绘制函数根据网格数组绘制每个格子显示分数。 6. 处理输入的函数使用GetAsyncKeyState检测方向键或者使用EasyX的消息循环处理按键。 7. 移动和合并逻辑四个方向的函数或者一个通用函数处理不同方向。 
8. 生成新数字的函数随机选择空白位置生成2或4。 
9. 判断游戏结束的函数检查是否还有移动的可能即是否有相邻相同的数字或者空位。 
10. 主循环处理输入更新游戏状态重绘界面判断结束条件。 
在具体实现时如何处理方向移动是关键。例如向右移动时对于每一行从右到左遍历将非零数字移到右边遇到相同的合并。例如对于行[2,2,2,2]右移后变成[0,0,4,4]。需要确保每次合并只发生一次比如四个2在右移时右边的两个先合并成4左边的两个再合并成4所以结果应该是0,0,4,4。 
另外生成新数字的逻辑每次移动有效即网格有变化后才生成新数字否则不生成。例如如果用户按下右方向键但所有数字无法移动或合并那么不生成新数字。 
测试案例比如当一行是2,2,2,2时右移后应为0,0,4,4左移应为4,4,0,0。当有4,4,8,8时右移合并成0,8,0,16。 
在编写移动函数时可能需要针对每个方向分别处理。例如右移时对每一行进行处理从最右边的列开始依次向左检查是否有可合并的块。另一种方法是将处理逻辑通用化比如将行提取出来处理合并后再放回去这样四个方向的处理可以复用同一段代码只需要调整行列的顺序。 
比如处理一行或一列的函数参数可以是行的指针或数组处理完合并后返回新的行和是否有变化。这样四个方向的处理都可以调用同一个函数但需要调整如何提取行和写回行。 
例如对于右移每一行处理为从右到左合并左移则处理为从左到右上移和下移则需要处理列可能需要将列转换为行数组处理后再转回去。 
这可能需要更复杂的代码结构但可以减少重复代码。 
现在具体到代码 
定义网格数组int grid[4][4]  {0}; 
初始化时生成两个初始数字通常是两个2或者一个2和一个4 
可能首先生成两个2。在初始化函数中调用生成新数字的函数两次。 
生成新数字的函数需要找到所有空位随机选一个并随机生成2或4通常是2的概率更高比如90%的210%的4。可以使用一个列表保存所有空位的坐标然后随机选择一个。 
绘制函数需要遍历每个格子根据数字的值绘制不同颜色的矩形并在中间显示数字。如果数字为0则不显示。数字的位置可能需要调整比如居中显示使用合适的字体大小。 
处理方向键输入比如使用GetAsyncKeyState检测VK_UP、VK_DOWN、VK_LEFT、VK_RIGHT。但需要注意按键的持续检测可能需要处理为每次按键触发一次移动而不是按住不放连续移动。或者设置一个延时避免按键处理过快。 
移动处理函数的大致步骤 
对于每个方向比如右移 
遍历每一行 
将当前行中的非零元素移到右侧合并相邻相同的数字并记录是否有移动或合并发生。 
例如处理一行数据 
原始行2,0,2,4 → 移动后0,0,4,4并加分8分合并两次224448。 
处理逻辑 
创建一个临时数组保存处理后的行初始为0。 
从右往左遍历原行记录上一个非零的值的位置。如果当前元素与上一个相同则合并分数增加并标记合并然后继续处理剩下的元素。 
或者另一种方法是先将所有非零元素紧凑排列到右侧然后遍历合并相邻相同的元素。 
比如步骤1将行中的非零元素移到右边如[2,0,2,4] → [0,2,2,4] 
然后从右到左检查相邻元素是否相同 
4和2不同跳过。2和2相同合并为4左边的元素变为0 → [0,0,4,4]。此时再紧凑一次但可能不需要因为合并后的元素已经靠右了。但可能会有中间的空隙比如[2,2,2,2] → 合并成0,0,4,4之后不需要再移动。或者在合并之后需要再次紧凑元素 
可能需要分步骤处理 
例如处理右移 
对于每一行 
1. 移除空格将非零元素移到右边保持相对顺序。例如行[2,0,2,4]变为[0,2,2,4]。 
2. 合并相邻相同的元素从右到左检查当前元素和右边的元素是否相同如果相同则合并右边的元素置0并加分。例如处理后的行可能变为[0,2, 0, 8]然后再移除空格变为[0,0,2,8]。 
或者可能需要先紧凑再合并再紧凑。 
例如步骤 
原始行2,0,2,4 → 紧凑后2,2,4,0 → 从右向左检查合并 
检查位置34和位置22不同位置22和位置12相同合并变为4位置1置0 → 行变为2,0,4,0 → 再次紧凑到右边0,0,2,4。这显然不正确。 
可能我的处理逻辑有问题。正确的右移合并应该是将两个相邻的相同数字合并一次比如右边的两个先合并 
或者正确的处理方式应该是这样的 
比如对于行 [2, 2, 2, 2]右移 
紧凑到右边四个2 → 没有空格。然后从右往左合并第三个和第四个合并为4第三个位置变为4第四个变为0。然后第二个和第三个合并为4第二个变为4第三个变为0。第一个和第二个合并为4第一个变为4第二个变为0。结果变成 [0,0,0,8]这显然不对正确的结果应为 [0,0,4,4]。 
所以正确的合并逻辑应该是在紧凑之后从右往左或从左往右合并但每个数字只能合并一次。这可能需要更细致的处理。 
正确的处理方式可能是这样的 
在处理一行的时候先紧凑将非零元素移到右侧对于右移的情况然后从右到左检查相邻元素是否可以合并。例如 
原始行2,2,2,2 → 紧凑后2,2,2,2 → 合并第三个和第四个合并为4得到2,2,0,4 → 再次紧凑得到2,2,4,0 → 再合并第二个和第三个或者可能我的思路错了。 
另一种思路是处理每个元素只合并一次。例如对于右移处理顺序是从右到左 
比如对于行 [2,2,2,2] 
索引3和2比较相同合并为4索引3为4索引2置0 → [2,2,0,4] 
然后索引1和0比较相同合并为4索引1为4索引0置0 → [0,4,0,4] 
然后再次紧凑得到 [4,4,0,0]这显然不对。 
看来这种方法有问题。正确的做法可能是在处理的时候每次合并后跳过下一个元素因为它们已经被处理过了。例如在合并索引i和i-1之后i的位置已经被处理所以下一次处理i-2的位置。 
正确的处理步骤可能需要这样的逻辑 
在紧凑之后的行中从右往左遍历 
例如处理右移后的紧凑行 [2,2,2,2] 
i从3到0 
- i3比较i和i-1的位置3和2相同合并分数增加i-1的位置置0然后i减一跳过下一个元素。 
这样合并3和2后i变成2接着处理i1 
比较i1和i0合并得到4分数增加i0。 
最后再次紧凑得到 [0,0,4,4]。 
这可能需要分步骤 
紧凑行 → 合并 → 再次紧凑。 
所以处理行的时候步骤如下 
1. 紧凑将非零元素移到右边中间无空格。 
2. 合并相邻的相同元素从右向左每个元素只能合并一次。 
3. 再次紧凑填补合并后产生的空格。 
例如 
原行2,0,2,4 → 紧凑后2,2,4,0 → 合并检查位置1和22和4不同位置0和12和2合并为4位置1置0 → 变为4,0,4,0 → 再次紧凑4,4,0,0 → 结果为4,4在右侧即行变成0,0,4,4 
或者可能我的步骤还是有问题。这时候可能需要更详细的例子。 
比如原行是 [2, 2, 2, 2]处理右移 
步骤1紧凑得到 [2,2,2,2] 
步骤2合并从右向左 
i3比较i3和i2都2合并为4i2置0 → 现在行变为 [2,2,0,4] 
然后i1比较i1和i0都2合并为4i0置0 → 行变为 [0,4,0,4] 
步骤3再次紧凑得到 [4,4,0,0] 
这显然不是正确的右移结果。正确的右移结果应该是 [0,0,4,4]。 
所以这说明我的合并逻辑不正确。正确的合并应该是在紧凑之后从右往左检查如果相邻元素相同则合并然后将右边的元素翻倍左边的元素置0然后紧凑一次。 
例如正确的处理 
原行2,2,2,2 → 紧凑后2,2,2,2 → 合并 
从右往左检查 
i3和i2都是2 → 合并得到4i2置0 → 行变为2,2,0,4 → 现在i1和i0都是2 → 合并得到4i0置0 → 行变为0,4,0,4 → 再次紧凑得到4,4,0,0 → 但这不是正确的结果。正确的结果应该是合并后两次合并得到0,0,4,4。 
哦问题可能出在合并后的再次紧凑方向。在合并后可能需要再次向右紧凑这样在例子中行变为0,4,0,4 → 再次向右紧凑得到0,0,4,4。 
哦对的合并后的步骤是再次向右紧凑。这样在合并之后再次将非零元素紧凑到右边。 
所以处理行的步骤是 
1. 向右紧凑移除空格 
2. 合并相邻的相同元素从右到左 
3. 再次向右紧凑 
这样在例子中 
原行2,2,2,2 → 步骤1后2,2,2,2 → 步骤2合并i3和i2 → 4i20 → 行变成2,2,0,4 → 合并i1和i0 → 4i00 → 行变成0,4,0,4 → 步骤3向右紧凑 → 0,0,4,4 → 正确。 
所以在处理每个方向时都需要进行这三个步骤紧凑、合并、再紧凑。 
现在如何将这个逻辑应用到每个方向 
例如处理右移时每一行都要经历这三个步骤。处理左移时每一行需要向左紧凑合并时从左到右然后再紧凑。处理上下方向时需要处理列将其转换为行处理再转回去。 
这可能需要编写通用函数来处理行或列的合并根据不同的方向进行调整。 
可能的实现步骤 
编写一个函数处理一个数组行或列进行紧凑、合并、再紧凑的操作并返回是否有任何移动或合并发生。例如 
bool ProcessLine(int line[4], bool reverse) { 
// 紧凑如果reverse为true则从右往左紧凑否则从左往右 
// 例如对于右移reverse为true紧凑到右边左移则reverse为false紧凑到左边。 
// 合并的方向也需要根据reverse来处理。 
} 
或者可能需要更明确的参数如处理方向。 
或者可以将每个行或列转换为一个一维数组处理完成后再放回去。例如对于右移和左移处理行对于上下移处理列。 
具体来说 
处理右移 
对每一行 
- 创建一个临时数组将非零元素紧凑到右侧。 
- 合并相邻相同的元素从右到左。 
- 再次紧凑到右侧。 
处理左移 
对每一行 
- 紧凑到左侧。 
- 合并相邻相同的元素从左到右。 
- 再次紧凑到左侧。 
处理上移 
对每一列 
- 紧凑到上侧。 
- 合并相邻相同的元素从上到下。 
- 再次紧凑到上侧。 
处理下移 
对每一列 
- 紧凑到下侧。 
- 合并相邻相同的元素从下到上。 
- 再次紧凑到下侧。 
这样每个方向的逻辑类似但处理的行或列不同紧凑的方向不同合并的方向不同。 
为了复用代码可以编写一个处理一维数组的函数根据参数决定紧凑的方向和合并的方向。 
例如 
// direction参数决定紧凑的方向0为左1为右2为上3为下或者用布尔值表示是否反向处理 
或者更通用地将数组视为行或列并指定处理顺序。 
可能比较复杂。或者针对行和列分别处理。 
关于主循环的结构 
初始化窗口初始化网格生成初始数字。 
然后循环 
- 绘制界面。 
- 处理输入。 
- 如果有有效的移动生成新数字。 
- 检查游戏是否结束。 
在EasyX中可能需要使用BeginBatchDraw和EndBatchDraw来减少闪烁。 
处理输入时可以使用GetAsyncKeyState来检测按键但需要注意不要多次触发同一个按键。例如在用户按下方向键时只处理一次直到释放后再按下。 
或者使用EasyX的ExMessage结构来处理消息循环例如 
ExMessage msg; 
while (true) { 
if (peekmessage(msg, EX_KEY)) { 
if (msg.message  WM_KEYDOWN) { 
switch (msg.vkcode) { 
case VK_LEFT: 
// 处理左移 
break; 
case VK_RIGHT: 
// 处理右移 
break; 
case VK_UP: 
// 处理上移 
break; 
case VK_DOWN: 
// 处理下移 
break; 
case VK_ESCAPE: 
exit(0); 
break; 
} 
} 
} 
} 
但这种方法可能无法检测到持续按下的键或者需要处理成每次按键触发一次移动。或者在每次循环中检测按键状态而不是通过消息队列。 
另一种方法是使用GetAsyncKeyState函数例如 
if (GetAsyncKeyState(VK_LEFT)  0x8000) { 
// 处理左移 
} 
同样的问题是如何防止多次触发。可以设置一个标志表示键是否已经被处理在键释放后重置。 
或者每次处理完移动后等待按键释放。这可能不太友好因为玩家可能需要快速操作。 
可能更简单的方式是在每次循环中处理输入但设置一个延时比如每次移动后等待100毫秒避免过于频繁的移动。 
但这样可能影响游戏的响应速度。另一种方法是记录上一次处理的时间只有当时间间隔超过一定值时才处理新的输入。 
这可能比较复杂对于简单的2048游戏可以接受每次按键触发一次移动即使按住不放也会有一定间隔。 
回到代码当处理方向键时调用对应的处理函数例如 
处理左移 
bool moved  false; 
for (int i0; i4; i) { 
int originalRow[4]; 
memcpy(originalRow, grid[i], sizeof(originalRow)); 
ProcessRowForLeft(grid[i], score); 
if (memcmp(originalRow, grid[i], sizeof(originalRow)) !0) { 
moved  true; 
} 
} 
if (moved) { 
GenerateNewNumber(); 
if (CheckGameOver()) { 
// 游戏结束 
} 
} 
类似地其他方向的处理。 
现在生成新数字的函数 
void GenerateNewNumber() { 
vectorpairint, int emptyCells; 
for (int i0; i4; i) { 
for (int j0; j4; j) { 
if (grid[i][j] 0) { 
emptyCells.emplace_back(i, j); 
} 
} 
} 
if (emptyCells.empty()) { 
return; 
} 
int index  rand() % emptyCells.size(); 
int value  (rand() %10 0) ?4 :2; // 10%的概率生成4 
grid[emptyCells[index].first][emptyCells[index].second]  value; 
} 
检查游戏是否结束 
bool CheckGameOver() { 
// 检查是否有空位 
for (int i0; i4; i) { 
for (int j0; j4; j) { 
if (grid[i][j] 0) { 
return false; 
} 
} 
} 
// 检查是否有相邻相同的数字 
for (int i0; i4; i) { 
for (int j0; j4; j) { 
int current  grid[i][j]; 
// 检查右边 
if (j 3  grid[i][j1]  current) { 
return false; 
} 
// 检查下边 
if (i 3  grid[i1][j]  current) { 
return false; 
} 
} 
} 
return true; 
} 
另外胜利条件需要检查是否有2048出现 
在每次生成新数字后检查是否达到2048如果有则提示胜利但游戏可能继续直到无法移动。或者根据游戏规则一旦有2048即胜利可以选择继续游戏。这里可能需要根据用户需求来处理但通常2048游戏允许玩家继续合并直到无法移动。 
所以在生成新数字后可以检查是否有2048并标记游戏胜利。 
现在关于绘制函数 
void Draw() { 
cleardevice(); 
setbkcolor(RGB(250, 248, 239)); // 设置背景色 
cleardevice(); 
int cellSize  100; 
int margin  10; 
for (int i0; i4; i) { 
for (int j0; j4; j) { 
int x  j * (cellSize  margin)  margin; 
int y  i * (cellSize  margin)  margin; 
int value  grid[i][j]; 
COLORREF color  GetColor(value); 
setfillcolor(color); 
fillrectangle(x, y, x  cellSize, y  cellSize); 
if (value !0) { 
TCHAR str[10]; 
_stprintf(str, _T(%d), value); 
settextstyle(40, 0, _T(Arial)); 
setbkmode(TRANSPARENT); 
int textWidth  textwidth(str); 
int textHeight  textheight(str); 
int tx  x  (cellSize - textWidth)/2; 
int ty  y  (cellSize - textHeight)/2; 
outtextxy(tx, ty, str); 
} 
} 
} 
// 显示分数 
TCHAR scoreStr[50] 
_stprintf(scoreStr, _T(Score: %d), score); 
settextstyle(20, 0, _T(Arial)); 
outtextxy(10, 460, scoreStr); 
// 如果游戏结束 
if (gameOver) { 
settextstyle(40, 0, _T(Arial)); 
outtextxy(100, 200, _T(Game Over!)); 
} 
FlushBatchDraw(); 
} 
其中GetColor函数根据数值返回颜色 
COLORREF GetColor(int value) { 
switch (value) { 
case 0: return RGB(205, 193, 180); 
case 2: return RGB(238, 228, 218); 
case 4: return RGB(237, 224, 200); 
case 8: return RGB(242, 177, 121); 
case 16: return RGB(245, 149, 99); 
case 32: return RGB(246, 124, 95); 
case 64: return RGB(246, 94, 59); 
case 128: return RGB(237, 207, 114); 
case 256: return RGB(237, 204, 97); 
case 512: return RGB(237, 200, 80); 
case 1024: return RGB(237, 197, 63); 
case 2048: return RGB(237, 194, 46); 
default: return RGB(60, 58, 50); 
} 
} 
现在将这些部分整合起来形成完整的代码。 
测试过程中需要注意的问题 
1. 是否正确处理移动和合并逻辑 
2. 分数是否正确累加 
3. 是否在移动后生成新数字 
4. 游戏结束条件是否准确 
5. 颜色和显示是否正确 
可能的错误点 
- 在合并时分数累加是否正确例如合并两个2得到4应加4分而不是2分 
根据2048的规则合并后的数字即为所得的分数。例如224得分4448得分8等等。所以在代码中当合并时应将合并后的值加到分数中。 
例如在ProcessRowForRight函数中 
当合并两个2时生成4分数 4 
在代码中的score  temp[i]; 因为temp[i]在合并后被设置为原来的两倍所以是正确的。 
例如原来的两个2合并为4此时temp[i] 4所以score 4是正确的。 
另一个可能的问题是在合并时是否跳过了下一个元素以避免重复合并。例如在合并i和i-1后i--使得循环中的i递减从而跳过下一个元素。 
在ProcessRowForRight的合并循环中 
for (int i 3; i 0; i--) { 
if (temp[i]  temp[i-1]  temp[i] !0) { 
temp[i] *2; 
score  temp[i]; 
temp[i-1] 0; 
merged  true; 
i--; // 跳过下一个避免重复合并 
} 
} 
这样当i3时如果合并了i3和i2那么i会减到2然后循环继续时i变成1处理i1的情况。这样避免了重复合并。 
这可能正确。 
现在编写主函数 
int main() { 
initgraph(500, 600); // 窗口大小500x600下面显示分数 
srand((unsigned)time(NULL)); 
InitializeGrid(); 
score 0; 
gameOver  false; 
bool win  false; 
BeginBatchDraw(); 
while (true) { 
Draw(); 
// 处理输入 
if (_kbhit()) { 
char ch  _getch(); 
if (ch  27) { // ESC退出 
break; 
} 
} 
if (GetAsyncKeyState(VK_LEFT)  0x8000) { 
bool moved  false; 
for (int i0; i4; i) { 
int original[4]; 
memcpy(original, grid[i], sizeof(original)); 
ProcessRowForLeft(grid[i], score); 
if (memcmp(original, grid[i], sizeof(original)) !0) { 
moved  true; 
} 
} 
if (moved) { 
GenerateNewNumber(); 
if (CheckGameOver()) { 
gameOver  true; 
} 
} 
Sleep(100); // 防止连续按键处理过快 
} 
else if (GetAsyncKeyState(VK_RIGHT)  0x8000) { 
bool moved  false; 
for (int i0; i4; i) { 
int original[4]; 
memcpy(original, grid[i], sizeof(original)); 
ProcessRowForRight(grid[i], score); 
if (memcmp(original, grid[i], sizeof(original)) !0) { 
moved  true; 
} 
} 
if (moved) { 
GenerateNewNumber(); 
if (CheckGameOver()) { 
gameOver  true; 
} 
} 
Sleep(100); 
} 
else if (GetAsyncKeyState(VK_UP)  0x8000) { 
bool moved  false; 
for (int j0; j4; j) { 
int col[4]; 
for (int i0; i4; i) { 
col[i]  grid[i][j]; 
} 
int original[4]; 
memcpy(original, col, sizeof(original)); 
ProcessColumnForUp(col, score); 
if (memcmp(original, col, sizeof(original)) !0) { 
moved  true; 
for (int i0; i4; i) { 
grid[i][j]  col[i]; 
} 
} 
} 
if (moved) { 
GenerateNewNumber(); 
if (CheckGameOver()) { 
gameOver  true; 
} 
} 
Sleep(100); 
} 
else if (GetAsyncKeyState(VK_DOWN)  0x8000) { 
bool moved  false; 
for (int j0; j4; j) { 
int col[4]; 
for (int i0; i4; i) { 
col[i]  grid[i][j]; 
} 
int original[4]; 
memcpy(original, col, sizeof(original)); 
ProcessColumnForDown(col, score); 
if (memcmp(original, col, sizeof(original)) !0) { 
moved  true; 
for (int i0; i4; i) { 
grid[i][j]  col[i]; 
} 
} 
} 
if (moved) { 
GenerateNewNumber(); 
if (CheckGameOver()) { 
gameOver  true; 
} 
} 
Sleep(100); 
} 
if (gameOver) { 
// 可以添加重新开始或退出逻辑 
// 例如按空格键重新开始 
if (GetAsyncKeyState(VK_SPACE)  0x8000) { 
InitializeGrid(); 
score 0; 
gameOver  false; 
} 
} 
另外初始化函数 
void InitializeGrid() { 
for (int i0; i4; i) { 
for (int j0; j4; j) { 
grid[i][j] 0; 
} 
} 
// 生成两个初始数字 
GenerateNewNumber(); 
GenerateNewNumber(); 
} 
可能存在的问题 
在上下移动的处理中ProcessColumnForUp和ProcessColumnForDown是否正确处理了列数据并在移动后写回grid 
例如对于上移 
原列是 [2,2,0,0]处理后应变为 [4,0,0,0]所以将修改后的col写回grid的列。 
代码中当处理列j时 
for (int j0; j4; j) { 
int col[4]; 
for (int i0; i4; i) { 
col[i]  grid[i][j]; 
} 
ProcessColumnForUp(col, score); 
// 检查是否变化如果变化则写回 
if (memcmp(original, col, ...) { 
for (int i0; i4; i) { 
grid[i][j]  col[i]; 
} 
moved  true; 
} 
} 
这是正确的。 综上将这些函数整合起来应该可以实现2048的基本逻辑。可能还需要调整颜色、字体大小、窗口尺寸等细节以及处理胜利条件的显示。 最后测试各个方向移动是否正常合并是否正确分数是否正确游戏结束条件是否触发。 
1.2 改进/进阶逻辑 
增加数字4096、8192……65536绘制方块时绘制圆角当格子满时有的时候可以再次消除玩家操作时用GetAsynckeyState来代替case将字符设得大一点方块颜色颜色应遵照原版有的时候颜色偏深字体应该改成白色有的时候颜色偏浅字体应该改成黑色可循环游戏游戏结束后弹窗询问是否再来一局将分数、最大方块和最高分显示。生成文件每次开始游戏读入游戏结束时将数据录入 
1.3 完善/再次改进目前未完成 
动画合并方块时的动画及移动方块时的动画   已完成文件文件录入时可能会出bug                          已完成最大方块无法显示最大方块                            已完成背景自行选择背景色主题白色或黑色出现方块时方块刷新可能有问题 
2. 代码 
2.1 整体代码 
#include graphics.h
#include conio.h
#include time.h
#include stdlib.h
#include vector
#include windows.h
#include fstream
#include sstream
using namespace std;// 常量定义
const int CELL_SIZE  120;
const int MARGIN  15;
const int WINDOW_WIDTH  600;
const int WINDOW_HEIGHT  700;
const int CORNER_RADIUS  20;
const int INFO_HEIGHT  150;// 颜色定义
const COLORREF SCORE_BG  RGB(158, 174, 187);    // 0x9eaebb
const COLORREF TEXT_LIGHT  RGB(219, 230, 238);  // 0xdbe6ee
const COLORREF TEXT_DARK  RGB(112, 123, 131);   // 0x707b83// 全局变量
int grid[4][4]  { 0 };
int score  0;
int maxTile  0;
int highScore  0;
bool gameOver  false;// 文件操作
void SaveRecord() {ofstream file(2048.save);if (file) {file  highScore  endl;file  maxTile  endl;}
}void LoadRecord() {ifstream file(2048.save);if (file) {file  highScore;file  maxTile;}else {highScore  0;maxTile  0;}
}// 根据数字获取颜色
COLORREF GetColor(int value) {switch (value) {case 0:    return RGB(205, 193, 180);case 2:    return RGB(238, 228, 218);case 4:    return RGB(237, 224, 200);case 8:    return RGB(242, 177, 121);case 16:   return RGB(245, 149, 99);case 32:   return RGB(246, 124, 95);case 64:   return RGB(246, 94, 59);case 128:  return RGB(237, 207, 114);case 256:  return RGB(237, 204, 97);case 512:  return RGB(237, 200, 80);case 1024: return RGB(237, 197, 63);case 2048: return RGB(237, 194, 46);case 4096: return RGB(180, 220, 90);case 8192: return RGB(150, 200, 80);case 16384:return RGB(120, 180, 70);case 32768:return RGB(90, 160, 60);case 65536:return RGB(60, 140, 50);default:   return RGB(60, 58, 50);}
}// 初始化网格
void InitializeGrid() {for (int i  0; i  4; i)for (int j  0; j  4; j)grid[i][j]  0;score  0;maxTile  2;gameOver  false;vectorpairint, int emptyCells;for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) {emptyCells.emplace_back(i, j);}}}if (!emptyCells.empty()) {int index  rand() % emptyCells.size();grid[emptyCells[index].first][emptyCells[index].second]  2;index  rand() % emptyCells.size();grid[emptyCells[index].first][emptyCells[index].second]  2;}
}// 生成新数字
void GenerateNewNumber() {vectorpairint, int emptyCells;for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) {emptyCells.emplace_back(i, j);}}}if (emptyCells.empty()) return;int index  rand() % emptyCells.size();int value  (rand() % 10  0) ? 4 : 2;grid[emptyCells[index].first][emptyCells[index].second]  value;
}// 检查游戏是否结束
bool CheckGameOver() {for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) return false;if (j  3  grid[i][j]  grid[i][j  1]) return false;if (i  3  grid[i][j]  grid[i  1][j]) return false;}}return true;
}// 文字居中绘制辅助函数
void DrawCenteredText(int x, int y, int width, int height, const wchar_t* str) {int textWidth  textwidth(str);int textHeight  textheight(str);int tx  x  (width - textWidth) / 2;int ty  y  (height - textHeight) / 2;outtextxy(tx, ty, str);
}// 绘制界面
void Draw() {cleardevice();setbkcolor(RGB(250, 248, 239));cleardevice();//  分数面板 const int scorePanelWidth  152;const int scorePanelHeight  89;// 当前分数setfillcolor(SCORE_BG);solidroundrect(MARGIN, MARGIN, MARGIN  scorePanelWidth, MARGIN  scorePanelHeight, 10, 10);settextstyle(28, 0, _T(Arial));settextcolor(TEXT_LIGHT);DrawCenteredText(MARGIN, MARGIN  10, scorePanelWidth, 30, _T(SCORE));wchar_t scoreStr[20];swprintf_s(scoreStr, L%d, score);settextstyle(44, 0, _T(Arial));settextcolor(WHITE);DrawCenteredText(MARGIN, MARGIN  45, scorePanelWidth, 44, scoreStr);// 最高分数setfillcolor(SCORE_BG);solidroundrect(MARGIN * 2  scorePanelWidth, MARGIN,MARGIN * 2  scorePanelWidth * 2, MARGIN  scorePanelHeight, 10, 10);settextstyle(28, 0, _T(Arial));settextcolor(TEXT_LIGHT);DrawCenteredText(MARGIN * 2  scorePanelWidth, MARGIN  10, scorePanelWidth, 30, _T(BEST));wchar_t bestStr[20];swprintf_s(bestStr, L%d, highScore);settextstyle(44, 0, _T(Arial));settextcolor(WHITE);DrawCenteredText(MARGIN * 2  scorePanelWidth, MARGIN  45, scorePanelWidth, 44, bestStr);// 提示信息settextstyle(24, 0, _T(Arial));settextcolor(TEXT_DARK);wchar_t tipStr[50];swprintf_s(tipStr, L目标合成 %d 方块, maxTile * 2);DrawCenteredText(0, INFO_HEIGHT - 40, WINDOW_WIDTH, 40, tipStr);//  游戏网格 for (int i  0; i  4; i) {for (int j  0; j  4; j) {int x  j * (CELL_SIZE  MARGIN)  MARGIN;int y  i * (CELL_SIZE  MARGIN)  MARGIN  INFO_HEIGHT;int value  grid[i][j];setfillcolor(GetColor(value));fillroundrect(x, y, x  CELL_SIZE, y  CELL_SIZE,CORNER_RADIUS, CORNER_RADIUS);if (value ! 0) {wchar_t str[10];swprintf_s(str, L%d, value);int fontSize  75;if (value  10000) fontSize  60;else if (value  1000) fontSize  65;else if (value  100) fontSize  70;settextstyle(fontSize, 0, _T(Arial));setbkmode(TRANSPARENT);int textWidth  textwidth(str);int textHeight  textheight(str);int tx  x  (CELL_SIZE - textWidth) / 2;int ty  y  (CELL_SIZE - textHeight) / 2;settextcolor(RGB(150, 150, 150));outtextxy(tx  3, ty  3, str);settextcolor(WHITE);outtextxy(tx, ty, str);}if (value  maxTile) {maxTile  value;}}}// 游戏结束提示if (gameOver) {settextstyle(48, 0, _T(微软雅黑));settextcolor(RGB(255, 100, 100));outtextxy(150, 300, _T(游戏结束!));}FlushBatchDraw();
}// 移动处理函数 
bool MoveLeft() {bool moved  false;for (int i  0; i  4; i) {int temp[4]  { 0 };int index  0;for (int j  0; j  4; j) {if (grid[i][j] ! 0) {temp[index]  grid[i][j];}}for (int j  0; j  3; j) {if (temp[j]  temp[j  1]  temp[j] ! 0) {temp[j] * 2;score  temp[j];temp[j  1]  0;j;}}int newRow[4]  { 0 };index  0;for (int j  0; j  4; j) {if (temp[j] ! 0) {newRow[index]  temp[j];}}if (memcmp(grid[i], newRow, sizeof(newRow))) {memcpy(grid[i], newRow, sizeof(newRow));moved  true;}}return moved;
}bool MoveRight() {bool moved  false;for (int i  0; i  4; i) {int temp[4]  { 0 };int index  3; // 从右向左填充// 紧凑到右侧for (int j  3; j  0; j--) {if (grid[i][j] ! 0) {temp[index--]  grid[i][j];}}// 合并相同数字从右向左合并for (int j  3; j  0; j--) {if (temp[j]  temp[j - 1]  temp[j] ! 0) {temp[j] * 2;score  temp[j];temp[j - 1]  0;j--; // 跳过已合并的位置}}// 再次紧凑到右侧int newRow[4]  { 0 };index  3;for (int j  3; j  0; j--) {if (temp[j] ! 0) {newRow[index--]  temp[j];}}// 检查是否变化if (memcmp(grid[i], newRow, sizeof(newRow)) ! 0) {memcpy(grid[i], newRow, sizeof(newRow));moved  true;}}return moved;
}bool MoveDown() {bool moved  false;for (int j  0; j  4; j) { // 按列处理int temp[4]  { 0 };int index  3; // 从下向上填充// 紧凑到下方for (int i  3; i  0; i--) {if (grid[i][j] ! 0) {temp[index--]  grid[i][j];}}// 合并相同数字从下向上合并for (int i  3; i  0; i--) {if (temp[i]  temp[i - 1]  temp[i] ! 0) {temp[i] * 2;score  temp[i];temp[i - 1]  0;i--; // 跳过已合并的位置}}// 再次紧凑到下方int newCol[4]  { 0 };index  3;for (int i  3; i  0; i--) {if (temp[i] ! 0) {newCol[index--]  temp[i];}}// 检查是否变化for (int i  0; i  4; i) {if (grid[i][j] ! newCol[i]) {moved  true;break;}}if (moved) {for (int i  0; i  4; i) {grid[i][j]  newCol[i];}}}return moved;
}bool MoveUp() {bool moved  false;for (int j  0; j  4; j) { // 按列处理int temp[4]  { 0 };int index  0;// 紧凑到上方for (int i  0; i  4; i) {if (grid[i][j] ! 0) {temp[index]  grid[i][j];}}// 合并相同数字for (int i  0; i  3; i) {if (temp[i]  temp[i  1]  temp[i] ! 0) {temp[i] * 2;score  temp[i];temp[i  1]  0;i; // 跳过已合并的位置}}// 再次紧凑int newCol[4]  { 0 };index  0;for (int i  0; i  4; i) {if (temp[i] ! 0) {newCol[index]  temp[i];}}// 检查是否变化for (int i  0; i  4; i) {if (grid[i][j] ! newCol[i]) {moved  true;break;}}if (moved) {for (int i  0; i  4; i) {grid[i][j]  newCol[i];}}}return moved;
}int main() {initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);srand((unsigned)time(NULL));LoadRecord();InitializeGrid();BeginBatchDraw();while (true) {while (!gameOver) {Draw();bool moved  false;if (GetAsyncKeyState(VK_LEFT)  0x8000 || GetAsyncKeyState(A)  0x8000) {moved  MoveLeft();}else if (GetAsyncKeyState(VK_RIGHT)  0x8000 || GetAsyncKeyState(D)  0x8000) {moved  MoveRight();}else if (GetAsyncKeyState(VK_UP)  0x8000 || GetAsyncKeyState(W)  0x8000) {moved  MoveUp();}else if (GetAsyncKeyState(VK_DOWN)  0x8000 || GetAsyncKeyState(S)  0x8000) {moved  MoveDown();}if (moved) {GenerateNewNumber();gameOver  CheckGameOver();Sleep(150);}if (GetAsyncKeyState(VK_ESCAPE)  0x8000) break;Sleep(10);}if (score  highScore) {highScore  score;SaveRecord();}Draw();int ret  MessageBox(GetHWnd(), L再来一局, L游戏结束, MB_YESNO);if (ret  IDYES) {InitializeGrid();}else {break;}}EndBatchDraw();closegraph();return 0;
} 
2.2 代码解释 
含注释版代码 
#include graphics.h
#include conio.h
#include time.h
#include stdlib.h
#include vector
#include windows.h
#include fstream
#include sstream
using namespace std;// 常量定义
const int CELL_SIZE  120;    // 每个方格的大小
const int MARGIN  15;        // 方格之间的边距
const int WINDOW_WIDTH  600; // 窗口宽度
const int WINDOW_HEIGHT  700;// 窗口高度
const int CORNER_RADIUS  15; // 方格圆角半径
const int INFO_HEIGHT  150;  // 显示分数等信息的高度// 颜色定义
const COLORREF SCORE_BG  RGB(158, 174, 187);    // 分数背景颜色
const COLORREF TEXT_LIGHT  RGB(219, 230, 238);  // 浅色文字颜色
const COLORREF TEXT_DARK  RGB(112, 123, 131);   // 深色文字颜色// 全局变量
int grid[4][4]  { 0 }; // 游戏网格初始值为0
int score  0;          // 当前得分
int maxTile  0;        // 最大数字
int highScore  0;      // 最高分
bool gameOver  false;  // 游戏是否结束标志// 文件操作保存记录
void SaveRecord() {ofstream file(2048.save);if (file) {file  highScore  endl; // 写入最高分file  maxTile  endl;   // 写入最大数字}
}// 文件操作加载记录
void LoadRecord() {ifstream file(2048.save);if (file) {file  highScore; // 读取最高分file  maxTile;   // 读取最大数字}else {highScore  0; // 默认最高分为0maxTile  2;   // 默认最大数字为2}
}// 根据数字获取对应的颜色
COLORREF GetColor(int value) {switch (value) {case 0:    return RGB(205, 193, 180);case 2:    return RGB(238, 228, 218);case 4:    return RGB(237, 224, 200);case 8:    return RGB(242, 177, 121);case 16:   return RGB(245, 149, 99);case 32:   return RGB(246, 124, 95);case 64:   return RGB(246, 94, 59);case 128:  return RGB(237, 207, 114);case 256:  return RGB(237, 204, 97);case 512:  return RGB(237, 200, 80);case 1024: return RGB(237, 197, 63);case 2048: return RGB(237, 194, 46);case 4096: return RGB(180, 220, 90);case 8192: return RGB(150, 200, 80);case 16384:return RGB(120, 180, 70);case 32768:return RGB(90, 160, 60);case 65536:return RGB(60, 140, 50);default:   return RGB(60, 58, 50);}
}// 初始化游戏网格
void InitializeGrid() {for (int i  0; i  4; i)for (int j  0; j  4; j)grid[i][j]  0; // 将所有方格初始化为0score  0;       // 分数清零gameOver  false; // 游戏状态设为未结束vectorpairint, int emptyCells;for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) {emptyCells.emplace_back(i, j); // 记录空方格位置}}}if (!emptyCells.empty()) {int index  rand() % emptyCells.size();grid[emptyCells[index].first][emptyCells[index].second]  2; // 在随机空方格中放置一个2index  rand() % emptyCells.size();grid[emptyCells[index].first][emptyCells[index].second]  2; // 再放置一个2}
}// 生成新数字2或4
void GenerateNewNumber() {vectorpairint, int emptyCells;for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) {emptyCells.emplace_back(i, j); // 记录空方格位置}}}if (emptyCells.empty()) return; // 如果没有空方格则返回int index  rand() % emptyCells.size();int value  (rand() % 10  0) ? 4 : 2; // 有10%的概率生成4否则生成2grid[emptyCells[index].first][emptyCells[index].second]  value; // 在随机空方格中放置新数字
}// 检查游戏是否结束
bool CheckGameOver() {for (int i  0; i  4; i) {for (int j  0; j  4; j) {if (grid[i][j]  0) return false; // 存在空方格则游戏未结束if (j  3  grid[i][j]  grid[i][j  1]) return false; // 相邻方格相同则游戏未结束if (i  3  grid[i][j]  grid[i  1][j]) return false; // 相邻方格相同则游戏未结束}}return true; // 所有条件都不满足则游戏结束
}// 辅助函数在指定区域内居中文本绘制
void DrawCenteredText(int x, int y, int width, int height, const wchar_t* str) {int textWidth  textwidth(str); // 获取文本宽度int textHeight  textheight(str);// 获取文本高度int tx  x  (width - textWidth) / 2; // 计算文本左上角x坐标int ty  y  (height - textHeight) / 2; // 计算文本左上角y坐标outtextxy(tx, ty, str); // 绘制文本
}
void Draw() {cleardevice(); // 清除设备上的所有内容setbkcolor(RGB(250, 248, 239)); // 设置背景颜色cleardevice(); // 再次清除设备上的所有内容//  分数面板 const int scorePanelWidth  152; // 分数面板宽度const int scorePanelHeight  89; // 分数面板高度// 当前分数setfillcolor(SCORE_BG); // 设置填充颜色为分数背景色solidroundrect(MARGIN, MARGIN, MARGIN  scorePanelWidth, MARGIN  scorePanelHeight, 10, 10); // 绘制圆角矩形settextstyle(28, 0, _T(Arial)); // 设置文本样式settextcolor(TEXT_LIGHT); // 设置文本颜色为浅色DrawCenteredText(MARGIN, MARGIN  10, scorePanelWidth, 30, _T(SCORE)); // 居中绘制“SCORE”wchar_t scoreStr[20]; // 定义存储当前分数的字符串swprintf_s(scoreStr, L%d, score); // 将当前分数转换为字符串settextstyle(44, 0, _T(Arial)); // 设置文本样式settextcolor(WHITE); // 设置文本颜色为白色DrawCenteredText(MARGIN, MARGIN  45, scorePanelWidth, 44, scoreStr); // 居中绘制当前分数// 最高分数setfillcolor(SCORE_BG); // 设置填充颜色为分数背景色solidroundrect(MARGIN * 2  scorePanelWidth, MARGIN,MARGIN * 2  scorePanelWidth * 2, MARGIN  scorePanelHeight, 10, 10); // 绘制圆角矩形settextstyle(28, 0, _T(Arial)); // 设置文本样式settextcolor(TEXT_LIGHT); // 设置文本颜色为浅色DrawCenteredText(MARGIN * 2  scorePanelWidth, MARGIN  10, scorePanelWidth, 30, _T(BEST)); // 居中绘制“BEST”wchar_t bestStr[20]; // 定义存储最高分的字符串swprintf_s(bestStr, L%d, highScore); // 将最高分转换为字符串settextstyle(44, 0, _T(Arial)); // 设置文本样式settextcolor(WHITE); // 设置文本颜色为白色DrawCenteredText(MARGIN * 2  scorePanelWidth, MARGIN  45, scorePanelWidth, 44, bestStr); // 居中绘制最高分// 最大方块setfillcolor(GetColor(maxTile)); // 设置填充颜色为最大方块的颜色fillroundrect(349, 15, 349  90, 15  90, 10, 10); // 绘制圆角矩形wchar_t str[10]; // 定义存储最大方块数值的字符串swprintf_s(str, L%d, maxTile); // 将最大方块数值转换为字符串int fontSize  60; // 初始字体大小if (maxTile  10000) fontSize  35; // 根据数值调整字体大小else if (maxTile  1000) fontSize  42;else if (maxTile  100) fontSize  55;settextstyle(fontSize, 0, _T(Arial)); // 设置文本样式int textWidth  textwidth(str); // 获取文本宽度int textHeight  textheight(str); // 获取文本高度int tx  349  (90 - textWidth) / 2; // 计算文本左上角x坐标int ty  15  (90 - textHeight) / 2; // 计算文本左上角y坐标settextcolor(RGB(150, 150, 150)); // 设置文本颜色为灰色阴影outtextxy(tx  2, ty  2, str); // 绘制带阴影的文字settextcolor(WHITE); // 设置文本颜色为白色outtextxy(tx, ty, str); // 绘制文字// 提示信息settextstyle(24, 0, _T(Arial)); // 设置文本样式settextcolor(TEXT_DARK); // 设置文本颜色为深色wchar_t tipStr[50]; // 定义存储提示信息的字符串swprintf_s(tipStr, L目标合成 %d 方块, maxTile * 2); // 构造提示信息DrawCenteredText(0, INFO_HEIGHT - 40, WINDOW_WIDTH, 40, tipStr); // 居中绘制提示信息//  游戏网格 for (int i  0; i  4; i) {for (int j  0; j  4; j) {int x  j * (CELL_SIZE  MARGIN)  MARGIN; // 计算方格左上角x坐标int y  i * (CELL_SIZE  MARGIN)  MARGIN  INFO_HEIGHT; // 计算方格左上角y坐标int value  grid[i][j]; // 获取方格中的数值setfillcolor(GetColor(value)); // 设置填充颜色为方格数值对应的颜色fillroundrect(x, y, x  CELL_SIZE, y  CELL_SIZE, CORNER_RADIUS, CORNER_RADIUS); // 绘制圆角矩形if (value ! 0) { // 如果方格中有数字wchar_t str[10]; // 定义存储方格数值的字符串swprintf_s(str, L%d, value); // 将方格数值转换为字符串int fontSize  75; // 初始字体大小if (value  10000) fontSize  50; // 根据数值调整字体大小else if (value  1000) fontSize  60;else if (value  100) fontSize  70;settextstyle(fontSize, 0, _T(Arial)); // 设置文本样式setbkmode(TRANSPARENT); // 设置背景模式为透明int textWidth  textwidth(str); // 获取文本宽度int textHeight  textheight(str); // 获取文本高度int tx  x  (CELL_SIZE - textWidth) / 2; // 计算文本左上角x坐标int ty  y  (CELL_SIZE - textHeight) / 2; // 计算文本左上角y坐标settextcolor(RGB(150, 150, 150)); // 设置文本颜色为灰色阴影outtextxy(tx  3, ty  3, str); // 绘制带阴影的文字settextcolor(WHITE); // 设置文本颜色为白色outtextxy(tx, ty, str); // 绘制文字}if (value  maxTile) {maxTile  value; // 更新最大方块数值}}}// 游戏结束提示if (gameOver) {settextstyle(48, 0, _T(微软雅黑)); // 设置文本样式settextcolor(RGB(255, 100, 100)); // 设置文本颜色为红色outtextxy(150, 300, _T(游戏结束!)); // 绘制“游戏结束!”}FlushBatchDraw(); // 刷新绘图缓冲区
}
bool MoveLeft() {bool moved  false;for (int i  0; i  4; i) {int temp[4]  { 0 }; // 临时数组用于存储当前行的非零值int index  0; // 临时数组的索引// 将当前行的非零值紧凑到左侧for (int j  0; j  4; j) {if (grid[i][j] ! 0) {temp[index]  grid[i][j];}}// 合并相邻相同的数字从左向右合并for (int j  0; j  3; j) {if (temp[j]  temp[j  1]  temp[j] ! 0) {temp[j] * 2; // 合并相同数字score  temp[j]; // 更新分数temp[j  1]  0; // 清空合并后的单元格j; // 跳过已合并的位置}}// 再次将合并后的结果紧凑到左侧int newRow[4]  { 0 };index  0;for (int j  0; j  4; j) {if (temp[j] ! 0) {newRow[index]  temp[j];}}// 检查是否发生了移动if (memcmp(grid[i], newRow, sizeof(newRow))) {memcpy(grid[i], newRow, sizeof(newRow)); // 更新网格moved  true;}}return moved;
}bool MoveRight() {bool moved  false;for (int i  0; i  4; i) {int temp[4]  { 0 }; // 临时数组用于存储当前行的非零值int index  3; // 临时数组的索引从右向左填充// 将当前行的非零值紧凑到右侧for (int j  3; j  0; j--) {if (grid[i][j] ! 0) {temp[index--]  grid[i][j];}}// 合并相邻相同的数字从右向左合并for (int j  3; j  0; j--) {if (temp[j]  temp[j - 1]  temp[j] ! 0) {temp[j] * 2; // 合并相同数字score  temp[j]; // 更新分数temp[j - 1]  0; // 清空合并后的单元格j--; // 跳过已合并的位置}}// 再次将合并后的结果紧凑到右侧int newRow[4]  { 0 };index  3;for (int j  3; j  0; j--) {if (temp[j] ! 0) {newRow[index--]  temp[j];}}// 检查是否发生了移动if (memcmp(grid[i], newRow, sizeof(newRow)) ! 0) {memcpy(grid[i], newRow, sizeof(newRow)); // 更新网格moved  true;}}return moved;
}bool MoveDown() {bool moved  false;for (int j  0; j  4; j) { // 按列处理int temp[4]  { 0 }; // 临时数组用于存储当前列的非零值int index  3; // 临时数组的索引从下向上填充// 将当前列的非零值紧凑到下方for (int i  3; i  0; i--) {if (grid[i][j] ! 0) {temp[index--]  grid[i][j];}}// 合并相邻相同的数字从下向上合并for (int i  3; i  0; i--) {if (temp[i]  temp[i - 1]  temp[i] ! 0) {temp[i] * 2; // 合并相同数字score  temp[i]; // 更新分数temp[i - 1]  0; // 清空合并后的单元格i--; // 跳过已合并的位置}}// 再次将合并后的结果紧凑到下方int newCol[4]  { 0 };index  3;for (int i  3; i  0; i--) {if (temp[i] ! 0) {newCol[index--]  temp[i];}}// 检查是否发生了移动for (int i  0; i  4; i) {if (grid[i][j] ! newCol[i]) {moved  true;break;}}if (moved) {for (int i  0; i  4; i) {grid[i][j]  newCol[i]; // 更新网格}}}return moved;
}bool MoveUp() {bool moved  false;for (int j  0; j  4; j) { // 按列处理int temp[4]  { 0 }; // 临时数组用于存储当前列的非零值int index  0; // 临时数组的索引// 将当前列的非零值紧凑到上方for (int i  0; i  4; i) {if (grid[i][j] ! 0) {temp[index]  grid[i][j];}}// 合并相邻相同的数字从上向下合并for (int i  0; i  3; i) {if (temp[i]  temp[i  1]  temp[i] ! 0) {temp[i] * 2; // 合并相同数字score  temp[i]; // 更新分数temp[i  1]  0; // 清空合并后的单元格i; // 跳过已合并的位置}}// 再次将合并后的结果紧凑到上方int newCol[4]  { 0 };index  0;for (int i  0; i  4; i) {if (temp[i] ! 0) {newCol[index]  temp[i];}}// 检查是否发生了移动for (int i  0; i  4; i) {if (grid[i][j] ! newCol[i]) {moved  true;break;}}if (moved) {for (int i  0; i  4; i) {grid[i][j]  newCol[i]; // 更新网格}}}return moved;
}int main() {initgraph(WINDOW_WIDTH, WINDOW_HEIGHT); // 初始化图形窗口srand((unsigned)time(NULL)); // 设置随机种子LoadRecord(); // 加载记录InitializeGrid(); // 初始化游戏网格BeginBatchDraw(); // 开始批量绘图while (true) {while (!gameOver) {Draw(); // 绘制游戏界面bool moved  false;// 处理键盘输入if (GetAsyncKeyState(VK_LEFT)  0x8000 || GetAsyncKeyState(A)  0x8000) {moved  MoveLeft(); // 左移}else if (GetAsyncKeyState(VK_RIGHT)  0x8000 || GetAsyncKeyState(D)  0x8000) {moved  MoveRight(); // 右移}else if (GetAsyncKeyState(VK_UP)  0x8000 || GetAsyncKeyState(W)  0x8000) {moved  MoveUp(); // 上移}else if (GetAsyncKeyState(VK_DOWN)  0x8000 || GetAsyncKeyState(S)  0x8000) {moved  MoveDown(); // 下移}if (moved) {GenerateNewNumber(); // 生成新数字gameOver  CheckGameOver(); // 检查游戏是否结束Sleep(150); // 延迟一段时间}if (GetAsyncKeyState(VK_ESCAPE)  0x8000) break; // 按Esc键退出Sleep(10); // 延迟一段时间}if (score  highScore) {highScore  score; // 更新最高分SaveRecord(); // 保存记录}Draw(); // 最后一次绘制游戏界面int ret  MessageBox(GetHWnd(), L再来一局, L游戏结束, MB_YESNO); // 弹出确认对话框if (ret  IDYES) {InitializeGrid(); // 重新初始化游戏网格}else {break; // 退出游戏}}EndBatchDraw(); // 结束批量绘图closegraph(); // 关闭图形窗口return 0;
} 3.后记 
点赞破30火速更下一期。第一期点赞量15 
目前为第二期本期更新内容见本文1.3 
去我的主页查看更多小游戏链接EasyX游戏合集【最新版】_easyx小游戏-CSDN博客 
哦对了本系列为限时免费如果你们点赞快的话也许系列更完了都还是免费的所以点赞冲冲冲详见评论区 文章转载自: http://www.morning.zrbpx.cn.gov.cn.zrbpx.cn http://www.morning.mzmqg.cn.gov.cn.mzmqg.cn http://www.morning.wgqtt.cn.gov.cn.wgqtt.cn http://www.morning.ailvturv.com.gov.cn.ailvturv.com http://www.morning.ktdqu.cn.gov.cn.ktdqu.cn http://www.morning.clndl.cn.gov.cn.clndl.cn http://www.morning.rmpkn.cn.gov.cn.rmpkn.cn http://www.morning.yrblz.cn.gov.cn.yrblz.cn http://www.morning.bcnsl.cn.gov.cn.bcnsl.cn http://www.morning.sjwqr.cn.gov.cn.sjwqr.cn http://www.morning.ggjlm.cn.gov.cn.ggjlm.cn http://www.morning.jfqqs.cn.gov.cn.jfqqs.cn http://www.morning.phlrp.cn.gov.cn.phlrp.cn http://www.morning.qnhcx.cn.gov.cn.qnhcx.cn http://www.morning.xpfwr.cn.gov.cn.xpfwr.cn http://www.morning.rbcw.cn.gov.cn.rbcw.cn http://www.morning.tllhz.cn.gov.cn.tllhz.cn http://www.morning.ldpjm.cn.gov.cn.ldpjm.cn http://www.morning.ymdhq.cn.gov.cn.ymdhq.cn http://www.morning.mtgnd.cn.gov.cn.mtgnd.cn http://www.morning.tqrbl.cn.gov.cn.tqrbl.cn http://www.morning.cykqb.cn.gov.cn.cykqb.cn http://www.morning.pgmbl.cn.gov.cn.pgmbl.cn http://www.morning.zfzgp.cn.gov.cn.zfzgp.cn http://www.morning.dwdjj.cn.gov.cn.dwdjj.cn http://www.morning.jyzqn.cn.gov.cn.jyzqn.cn http://www.morning.xqqcq.cn.gov.cn.xqqcq.cn http://www.morning.pqwjh.cn.gov.cn.pqwjh.cn http://www.morning.bkryb.cn.gov.cn.bkryb.cn http://www.morning.czwed.com.gov.cn.czwed.com http://www.morning.bnpcq.cn.gov.cn.bnpcq.cn http://www.morning.fpxyy.cn.gov.cn.fpxyy.cn http://www.morning.xqndf.cn.gov.cn.xqndf.cn http://www.morning.tmrjb.cn.gov.cn.tmrjb.cn http://www.morning.yrfxb.cn.gov.cn.yrfxb.cn http://www.morning.rrxmm.cn.gov.cn.rrxmm.cn http://www.morning.ylpl.cn.gov.cn.ylpl.cn http://www.morning.kflbf.cn.gov.cn.kflbf.cn http://www.morning.pqsys.cn.gov.cn.pqsys.cn http://www.morning.prkdl.cn.gov.cn.prkdl.cn http://www.morning.amlutsp.cn.gov.cn.amlutsp.cn http://www.morning.knpbr.cn.gov.cn.knpbr.cn http://www.morning.flchj.cn.gov.cn.flchj.cn http://www.morning.bfjyp.cn.gov.cn.bfjyp.cn http://www.morning.jqkjr.cn.gov.cn.jqkjr.cn http://www.morning.chtnr.cn.gov.cn.chtnr.cn http://www.morning.brzlp.cn.gov.cn.brzlp.cn http://www.morning.pghry.cn.gov.cn.pghry.cn http://www.morning.wflsk.cn.gov.cn.wflsk.cn http://www.morning.mzbyl.cn.gov.cn.mzbyl.cn http://www.morning.lyhrg.cn.gov.cn.lyhrg.cn http://www.morning.fygbq.cn.gov.cn.fygbq.cn http://www.morning.jcbmm.cn.gov.cn.jcbmm.cn http://www.morning.rflcy.cn.gov.cn.rflcy.cn http://www.morning.fcxt.cn.gov.cn.fcxt.cn http://www.morning.xsetx.com.gov.cn.xsetx.com http://www.morning.djmdk.cn.gov.cn.djmdk.cn http://www.morning.rqfkh.cn.gov.cn.rqfkh.cn http://www.morning.xwrhk.cn.gov.cn.xwrhk.cn http://www.morning.hnmbq.cn.gov.cn.hnmbq.cn http://www.morning.dywgl.cn.gov.cn.dywgl.cn http://www.morning.qbrs.cn.gov.cn.qbrs.cn http://www.morning.bnfsw.cn.gov.cn.bnfsw.cn http://www.morning.hqykb.cn.gov.cn.hqykb.cn http://www.morning.hjjfp.cn.gov.cn.hjjfp.cn http://www.morning.jftl.cn.gov.cn.jftl.cn http://www.morning.ccphj.cn.gov.cn.ccphj.cn http://www.morning.jqpq.cn.gov.cn.jqpq.cn http://www.morning.zhishizf.cn.gov.cn.zhishizf.cn http://www.morning.ltspm.cn.gov.cn.ltspm.cn http://www.morning.hqbnx.cn.gov.cn.hqbnx.cn http://www.morning.npbkx.cn.gov.cn.npbkx.cn http://www.morning.lnfkd.cn.gov.cn.lnfkd.cn http://www.morning.gtdf.cn.gov.cn.gtdf.cn http://www.morning.mczjq.cn.gov.cn.mczjq.cn http://www.morning.srgbr.cn.gov.cn.srgbr.cn http://www.morning.lzqxb.cn.gov.cn.lzqxb.cn http://www.morning.jjtwh.cn.gov.cn.jjtwh.cn http://www.morning.bpmdg.cn.gov.cn.bpmdg.cn http://www.morning.bsqbg.cn.gov.cn.bsqbg.cn