[Plain Text] 超级无敌俄罗斯大回旋方块 →→→→→进入此内容的聊天室

来自 卢本伟, 2024-03-15, 写在 Plain Text, 查看 15 次.
URL http://www.code666.cn/view/de24bccc
  1.  #include <stdio.h>
  2.     #include <string.h>
  3.     #include <stdlib.h>
  4.     #include <time.h>
  5.     #include <conio.h>
  6.     #include <windows.h>
  7.      
  8.     #ifdef _MSC_VER  // M$的编译器要给予特殊照顾
  9.     #if _MSC_VER <= 1200  // VC6及以下版本
  10.     #error 你是不是还在用VC6?!
  11.     #else  // VC6以上版本
  12.     #if _MSC_VER >= 1600  // 据说VC10及以上版本有stdint.h了
  13.     #include <stdint.h>
  14.     #else  // VC10以下版本,自己定义int8_t和uint16_t
  15.     typedef signed char int8_t;
  16.     typedef unsigned short uint16_t;
  17.     #endif
  18.     #ifndef __cplusplus  // 据说VC都没有stdbool.h,不用C++编译,自己定义bool
  19.     typedef int bool;
  20.     #define true 1
  21.     #define false 0
  22.     #endif
  23.     #endif
  24.     #else  // 其他的编译器都好说
  25.     #include <stdint.h>
  26.     #ifndef __cplusplus  // 不用C++编译,需要stdbool.h里的bool
  27.     #include <stdbool.h>
  28.     #endif
  29.     #endif
  30.      
  31.     // =============================================================================
  32.     // 7种方块的4旋转状态(4位为一行)
  33.     static const uint16_t gs_uTetrisTable[7][4] = { { 0x00F0U, 0x2222U, 0x00F0U,
  34.             0x2222U },  // I型
  35.             { 0x0072U, 0x0262U, 0x0270U, 0x0232U },  // T型
  36.             { 0x0223U, 0x0074U, 0x0622U, 0x0170U },  // L型
  37.             { 0x0226U, 0x0470U, 0x0322U, 0x0071U },  // J型
  38.             { 0x0063U, 0x0264U, 0x0063U, 0x0264U },  // Z型
  39.             { 0x006CU, 0x0462U, 0x006CU, 0x0462U },  // S型
  40.             { 0x0660U, 0x0660U, 0x0660U, 0x0660U }   // O型
  41.     };
  42.      
  43.     // =============================================================================
  44.     // 初始状态的游戏池
  45.     // 每个元素表示游戏池的一行,下标大的是游戏池底部
  46.     // 两端各置2个1,底部2全置为1,便于进行碰撞检测
  47.     // 这样一来游戏池的宽度为12列
  48.     // 如果想要传统的10列,只需多填两个1即可(0xE007),当然显示相关部分也要随之改动
  49.     // 当某个元素为0xFFFFU时,说明该行已被填满
  50.     // 顶部4行用于给方块,不显示出来
  51.     // 再除去底部2行,显示出来的游戏池高度为22行
  52.     static const uint16_t gs_uInitialTetrisPool[28] = { 0xC003U, 0xC003U, 0xC003U,
  53.             0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,
  54.             0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U,
  55.             0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xC003U, 0xFFFFU,
  56.             0xFFFFU };
  57.      
  58.     #define COL_BEGIN 2
  59.     #define COL_END 14
  60.     #define ROW_BEGIN 4
  61.     #define ROW_END 26
  62.      
  63.     // =============================================================================
  64.     typedef struct TetrisManager  // 这个结构体存储游戏相关数据
  65.     {
  66.         uint16_t pool[28];  // 游戏池
  67.         int8_t x;  // 当前方块x坐标,此处坐标为方块左上角坐标
  68.         int8_t y;  // 当前方块y坐标
  69.         int8_t type[3];  // 当前、下一个和下下一个方块类型
  70.         int8_t orientation[3];  // 当前、下一个和下下一个方块旋转状态
  71.         unsigned score;  // 得分
  72.         unsigned erasedCount[4];  // 消行数
  73.         unsigned erasedTotal;  // 消行总数
  74.         unsigned tetrisCount[7];  // 各方块数
  75.         unsigned tetrisTotal;  // 方块总数
  76.         bool dead;  // 挂
  77.     } TetrisManager;
  78.      
  79.     // =============================================================================
  80.     typedef struct TetrisControl  // 这个结构体存储控制相关数据
  81.     {
  82.         bool pause;  // 暂停
  83.         bool clockwise;  // 旋转方向:顺时针为true
  84.         int8_t direction;  // 移动方向:0向左移动 1向右移动
  85.         // 游戏池内每格的颜色
  86.         // 由于此版本是彩色的,仅用游戏池数据无法存储颜色信息
  87.         // 当然,如果只实现单色版的,就没必要用这个数组了
  88.         int8_t color[28][16];
  89.     } TetrisControl;
  90.      
  91.     HANDLE g_hConsoleOutput;  // 控制台输出句柄
  92.      
  93.     // =============================================================================
  94.     // 函数声明
  95.     // 如果使用全局变量方式实现,就没必要传参了
  96.     void initGame(TetrisManager *manager, TetrisControl *control);  // 初始化游戏
  97.     void restartGame(TetrisManager *manager, TetrisControl *control);  // 重新开始游戏
  98.     void giveTetris(TetrisManager *manager);  // 给一个方块
  99.     bool checkCollision(const TetrisManager *manager);  // 碰撞检测
  100.     void insertTetris(TetrisManager *manager);  // 插入方块
  101.     void removeTetris(TetrisManager *manager);  // 移除方块
  102.     void horzMoveTetris(TetrisManager *manager, TetrisControl *control);  // 水平移动方块
  103.     void moveDownTetris(TetrisManager *manager, TetrisControl *control);  // 向下移动方块
  104.     void rotateTetris(TetrisManager *manager, TetrisControl *control);  // 旋转方块
  105.     void dropDownTetris(TetrisManager *manager, TetrisControl *control);  // 方块直接落地
  106.     bool checkErasing(TetrisManager *manager, TetrisControl *control);  // 消行检测
  107.     void keydownControl(TetrisManager *manager, TetrisControl *control, int key); // 键按下
  108.     void setPoolColor(const TetrisManager *manager, TetrisControl *control); // 设置颜色
  109.     void gotoxyWithFullwidth(short x, short y);  // 以全角定位
  110.     void printPoolBorder();  // 显示游戏池边界
  111.     void printTetrisPool(const TetrisManager *manager, const TetrisControl *control); // 显示游戏池
  112.     void printCurrentTetris(const TetrisManager *manager,
  113.             const TetrisControl *control);  // 显示当前方块
  114.     void printNextTetris(const TetrisManager *manager);  // 显示下一个和下下一个方块
  115.     void printScore(const TetrisManager *manager);  // 显示得分信息
  116.     void runGame(TetrisManager *manager, TetrisControl *control);  // 运行游戏
  117.     void printPrompting();  // 显示提示信息
  118.     bool ifPlayAgain();  // 再来一次
  119.      
  120.     // =============================================================================
  121.     // 出处:http://www.oschina.net/code/snippet_255612_16922
  122.     // 主函数
  123.     int main() {
  124.         TetrisManager tetrisManager;
  125.         TetrisControl tetrisControl;
  126.      
  127.         initGame(&tetrisManager, &tetrisControl);  // 初始化游戏
  128.         do {
  129.             printPrompting();  // 显示提示信息
  130.             printPoolBorder();  // 显示游戏池边界
  131.             runGame(&tetrisManager, &tetrisControl);  // 运行游戏
  132.             if (ifPlayAgain())  // 再来一次
  133.             {
  134.                 SetConsoleTextAttribute(g_hConsoleOutput, 0x7);
  135.                 system("cls");  // 清屏
  136.                 restartGame(&tetrisManager, &tetrisControl);  // 重新开始游戏
  137.             } else {
  138.                 break;
  139.             }
  140.         } while (1);
  141.         gotoxyWithFullwidth(0, 0);
  142.         CloseHandle(g_hConsoleOutput);
  143.         return 0;
  144.     }
  145.      
  146.     // =============================================================================
  147.     // 初始化游戏
  148.     void initGame(TetrisManager *manager, TetrisControl *control) {
  149.         CONSOLE_CURSOR_INFO cursorInfo = { 1, FALSE };  // 光标信息
  150.      
  151.         g_hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);  // 获取控制台输出句柄
  152.         SetConsoleCursorInfo(g_hConsoleOutput, &cursorInfo);  // 设置光标隐藏
  153.         SetConsoleTitleA("俄罗斯方块");
  154.      
  155.         restartGame(manager, control);
  156.     }
  157.      
  158.     // =============================================================================
  159.     // 重新开始游戏
  160.     void restartGame(TetrisManager *manager, TetrisControl *control) {
  161.         memset(manager, 0, sizeof(TetrisManager));  // 全部置0
  162.      
  163.         // 初始化游戏池
  164.         memcpy(manager->pool, gs_uInitialTetrisPool, sizeof(uint16_t[28]));
  165.         srand((unsigned) time(NULL ));  // 设置随机种子
  166.      
  167.         manager->type[1] = rand() % 7;  // 下一个
  168.         manager->orientation[1] = rand() & 3;
  169.      
  170.         manager->type[2] = rand() % 7;  // 下下一个
  171.         manager->orientation[2] = rand() & 3;
  172.      
  173.         memset(control, 0, sizeof(TetrisControl));  // 全部置0
  174.      
  175.         giveTetris(manager);  // 给下一个方块
  176.         setPoolColor(manager, control);  // 设置颜色
  177.     }
  178.      
  179.     // =============================================================================
  180.     // 给一个方块
  181.     void giveTetris(TetrisManager *manager) {
  182.         uint16_t tetris;
  183.      
  184.         manager->type[0] = manager->type[1];  // 下一个方块置为当前
  185.         manager->orientation[0] = manager->orientation[1];
  186.      
  187.         manager->type[1] = manager->type[2];  // 下下一个置方块为下一个
  188.         manager->orientation[1] = manager->orientation[2];
  189.      
  190.         manager->type[2] = rand() % 7;  // 随机生成下下一个方块
  191.         manager->orientation[2] = rand() & 3;
  192.      
  193.         tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]]; // 当前方块
  194.      
  195.         // 设置当前方块y坐标,保证刚给出时只显示方块最下面一行
  196.         // 这种实现使得玩家可以以很快的速度将方块落在不显示出来的顶部4行内
  197.         if (tetris & 0xF000) {
  198.             manager->y = 0;
  199.         } else {
  200.             manager->y = (tetris & 0xFF00) ? 1 : 2;
  201.         }
  202.         manager->x = 6;  // 设置当前方块x坐标
  203.      
  204.         if (checkCollision(manager))  // 检测到碰撞
  205.                 {
  206.             manager->dead = true;  // 标记游戏结束
  207.         } else  // 未检测到碰撞
  208.         {
  209.             insertTetris(manager);  // 将当前方块加入游戏池
  210.         }
  211.      
  212.         ++manager->tetrisTotal;  // 方块总数
  213.         ++manager->tetrisCount[manager->type[0]];  // 相应方块数
  214.      
  215.         printNextTetris(manager);  // 显示下一个方块
  216.         printScore(manager);  // 显示得分信息
  217.     }
  218.      
  219.     // =============================================================================
  220.     // 碰撞检测
  221.     bool checkCollision(const TetrisManager *manager) {
  222.         // 当前方块
  223.         uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];
  224.         uint16_t dest = 0;
  225.      
  226.         // 获取当前方块在游戏池中的区域:
  227.         // 游戏池坐标x y处小方格信息,按低到高存放在16位无符号数中
  228.         dest |= (((manager->pool[manager->y + 0] >> manager->x) << 0x0) & 0x000F);
  229.         dest |= (((manager->pool[manager->y + 1] >> manager->x) << 0x4) & 0x00F0);
  230.         dest |= (((manager->pool[manager->y + 2] >> manager->x) << 0x8) & 0x0F00);
  231.         dest |= (((manager->pool[manager->y + 3] >> manager->x) << 0xC) & 0xF000);
  232.      
  233.         // 若当前方块与目标区域存在重叠(碰撞),则位与的结果不为0
  234.         return ((dest & tetris) != 0);
  235.     }
  236.      
  237.     // =============================================================================
  238.     // 插入方块
  239.     void insertTetris(TetrisManager *manager) {
  240.         // 当前方块
  241.         uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];
  242.      
  243.         // 当前方块每4位取出,位或到游戏池相应位置,即完成插入方块
  244.         manager->pool[manager->y + 0] |= (((tetris >> 0x0) & 0x000F) << manager->x);
  245.         manager->pool[manager->y + 1] |= (((tetris >> 0x4) & 0x000F) << manager->x);
  246.         manager->pool[manager->y + 2] |= (((tetris >> 0x8) & 0x000F) << manager->x);
  247.         manager->pool[manager->y + 3] |= (((tetris >> 0xC) & 0x000F) << manager->x);
  248.     }
  249.      
  250.     // =============================================================================
  251.     // 移除方块
  252.     void removeTetris(TetrisManager *manager) {
  253.         // 当前方块
  254.         uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];
  255.      
  256.         // 当前方块每4位取出,按位取反后位与到游戏池相应位置,即完成移除方块
  257.         manager->pool[manager->y + 0] &=
  258.                 ~(((tetris >> 0x0) & 0x000F) << manager->x);
  259.         manager->pool[manager->y + 1] &=
  260.                 ~(((tetris >> 0x4) & 0x000F) << manager->x);
  261.         manager->pool[manager->y + 2] &=
  262.                 ~(((tetris >> 0x8) & 0x000F) << manager->x);
  263.         manager->pool[manager->y + 3] &=
  264.                 ~(((tetris >> 0xC) & 0x000F) << manager->x);
  265.     }
  266.      
  267.     // =============================================================================
  268.     // 设置颜色
  269.     void setPoolColor(const TetrisManager *manager, TetrisControl *control) {
  270.         // 由于显示游戏池时,先要在游戏池里判断某一方格有方块才显示相应方格的颜色
  271.         // 这里只作设置即可,没必要清除
  272.         // 当移动方块或给一个方块时调用
  273.      
  274.         int8_t i, x, y;
  275.      
  276.         // 当前方块
  277.         uint16_t tetris = gs_uTetrisTable[manager->type[0]][manager->orientation[0]];
  278.      
  279.         for (i = 0; i < 16; ++i) {
  280.             y = (i >> 2) + manager->y;  // 待设置的列
  281.             if (y > ROW_END)  // 超过底部限制
  282.             {
  283.                 break;
  284.             }
  285.             x = (i & 3) + manager->x;  // 待设置的行
  286.             if ((tetris >> i) & 1)  // 检测的到小方格属于当前方块区域
  287.                     {
  288.                 control->color[y][x] = (manager->type[0] | 8);  // 设置颜色
  289.             }
  290.         }
  291.     }
  292.      
  293.     // =============================================================================
  294.     // 旋转方块
  295.     void rotateTetris(TetrisManager *manager, TetrisControl *control) {
  296.         int8_t ori = manager->orientation[0];  // 记录原旋转状态
  297.      
  298.         removeTetris(manager);  // 移走当前方块
  299.      
  300.         // 顺/逆时针旋转
  301.         manager->orientation[0] =
  302.                 (control->clockwise) ? ((ori + 1) & 3) : ((ori + 3) & 3);
  303.      
  304.         if (checkCollision(manager))  // 检测到碰撞
  305.                 {
  306.             manager->orientation[0] = ori;  // 恢复为原旋转状态
  307.             insertTetris(manager);  // 放入当前方块。由于状态没改变,不需要设置颜色
  308.         } else {
  309.             insertTetris(manager);  // 放入当前方块
  310.             setPoolColor(manager, control);  // 设置颜色
  311.             printCurrentTetris(manager, control);  // 显示当前方块
  312.         }
  313.     }
  314.      
  315.     // =============================================================================
  316.     // 水平移动方块
  317.     void horzMoveTetris(TetrisManager *manager, TetrisControl *control) {
  318.         int x = manager->x;  // 记录原列位置
  319.      
  320.         removeTetris(manager);  // 移走当前方块
  321.         control->direction == 0 ? (--manager->x) : (++manager->x);  // 左/右移动
  322.      
  323.         if (checkCollision(manager))  // 检测到碰撞
  324.                 {
  325.             manager->x = x;  // 恢复为原列位置
  326.             insertTetris(manager);  // 放入当前方块。由于位置没改变,不需要设置颜色
  327.         } else {
  328.             insertTetris(manager);  // 放入当前方块
  329.             setPoolColor(manager, control);  // 设置颜色
  330.             printCurrentTetris(manager, control);  // 显示当前方块
  331.         }
  332.     }
  333.      
  334.     // =============================================================================
  335.     // 向下移动方块
  336.     void moveDownTetris(TetrisManager *manager, TetrisControl *control) {
  337.         int8_t y = manager->y;  // 记录原行位置
  338.      
  339.         removeTetris(manager);  // 移走当前方块
  340.         ++manager->y;  // 向下移动
  341.      
  342.         if (checkCollision(manager))  // 检测到碰撞
  343.                 {
  344.             manager->y = y;  // 恢复为原行位置
  345.             insertTetris(manager);  // 放入当前方块。由于位置没改变,不需要设置颜色
  346.             if (checkErasing(manager, control))  // 检测到消行
  347.                     {
  348.                 printTetrisPool(manager, control);  // 显示游戏池
  349.             }
  350.         } else {
  351.             insertTetris(manager);  // 放入当前方块
  352.             setPoolColor(manager, control);  // 设置颜色
  353.             printCurrentTetris(manager, control);  // 显示当前方块
  354.         }
  355.     }
  356.      
  357.     // =============================================================================
  358.     // 方块直接落地
  359.     void dropDownTetris(TetrisManager *manager, TetrisControl *control) {
  360.         removeTetris(manager);  // 移走当前方块
  361.         for (; manager->y < ROW_END; ++manager->y)  // 从上往下
  362.                 {
  363.             if (checkCollision(manager))  // 检测到碰撞
  364.                     {
  365.                 break;
  366.             }
  367.         }
  368.         --manager->y;  // 上移一格当然没有碰撞
  369.      
  370.         insertTetris(manager);  // 放入当前方块
  371.         setPoolColor(manager, control);  // 设置颜色
  372.      
  373.         checkErasing(manager, control);  // 检测消行
  374.         printTetrisPool(manager, control);  // 显示游戏池
  375.     }
  376.      
  377.     // =============================================================================
  378.     // 消行检测
  379.     bool checkErasing(TetrisManager *manager, TetrisControl *control) {
  380.         static const unsigned scores[5] = { 0, 10, 30, 90, 150 };  // 消行得分
  381.         int8_t count = 0;
  382.         int8_t k = 0, y = manager->y + 3;  // 从下往上检测
  383.      
  384.         do {
  385.             if (y < ROW_END && manager->pool[y] == 0xFFFFU)  // 有效区域内且一行已填满
  386.                     {
  387.                 ++count;
  388.                 // 消除一行方块
  389.                 memmove(manager->pool + 1, manager->pool, sizeof(uint16_t) * y);
  390.                 // 颜色数组的元素随之移动
  391.                 memmove(control->color[1], control->color[0],
  392.                         sizeof(int8_t[16]) * y);
  393.             } else {
  394.                 --y;
  395.                 ++k;
  396.             }
  397.         } while (y >= manager->y && k < 4);
  398.      
  399.         manager->erasedTotal += count;  // 消行总数
  400.         manager->score += scores[count];  // 得分
  401.      
  402.         if (count > 0) {
  403.             ++manager->erasedCount[count - 1];  // 消行
  404.         }
  405.      
  406.         giveTetris(manager);  // 给下一个方块
  407.         setPoolColor(manager, control);  // 设置颜色
  408.      
  409.         return (count > 0);
  410.     }
  411.      
  412.     // =============================================================================
  413.     // 键按下
  414.     void keydownControl(TetrisManager *manager, TetrisControl *control, int key) {
  415.         if (key == 13)  // 暂停/解除暂停
  416.                 {
  417.             control->pause = !control->pause;
  418.         }
  419.      
  420.         if (control->pause)  // 暂停状态,不作处理
  421.         {
  422.             return;
  423.         }
  424.      
  425.         switch (key) {
  426.         case 'w':
  427.         case 'W':
  428.         case '8':
  429.         case 72:  // 上
  430.             control->clockwise = true;  // 顺时针旋转
  431.             rotateTetris(manager, control);  // 旋转方块
  432.             break;
  433.         case 'a':
  434.         case 'A':
  435.         case '4':
  436.         case 75:  // 左
  437.             control->direction = 0;  // 向左移动
  438.             horzMoveTetris(manager, control);  // 水平移动方块
  439.             break;
  440.         case 'd':
  441.         case 'D':
  442.         case '6':
  443.         case 77:  // 右
  444.             control->direction = 1;  // 向右移动
  445.             horzMoveTetris(manager, control);  // 水平移动方块
  446.             break;
  447.         case 's':
  448.         case 'S':
  449.         case '2':
  450.         case 80:  // 下
  451.             moveDownTetris(manager, control);  // 向下移动方块
  452.             break;
  453.         case ' ':  // 直接落地
  454.             dropDownTetris(manager, control);
  455.             break;
  456.         case '0':  // 反转
  457.             control->clockwise = false;  // 逆时针旋转
  458.             rotateTetris(manager, control);  // 旋转方块
  459.             break;
  460.         default:
  461.             break;
  462.         }
  463.     }
  464.      
  465.     // =============================================================================
  466.     // 以全角定位
  467.     void gotoxyWithFullwidth(short x, short y) {
  468.         static COORD cd;
  469.      
  470.         cd.X = (short) (x << 1);
  471.         cd.Y = y;
  472.         SetConsoleCursorPosition(g_hConsoleOutput, cd);
  473.     }
  474.      
  475.     // =============================================================================
  476.     // 显示游戏池边界
  477.     void printPoolBorder() {
  478.         int8_t y;
  479.      
  480.         SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
  481.         for (y = ROW_BEGIN; y < ROW_END; ++y)  // 不显示顶部4行和底部2行
  482.                 {
  483.             gotoxyWithFullwidth(10, y - 3);
  484.             printf("%2s", "");
  485.             gotoxyWithFullwidth(23, y - 3);
  486.             printf("%2s", "");
  487.         }
  488.      
  489.         gotoxyWithFullwidth(10, y - 3);  // 底部边界
  490.         printf("%28s", "");
  491.     }
  492.      
  493.     // 定位到游戏池中的方格
  494.     #define gotoxyInPool(x, y) gotoxyWithFullwidth(x + 9, y - 3)
  495.      
  496.     // =============================================================================
  497.     // 显示游戏池
  498.     void printTetrisPool(const TetrisManager *manager, const TetrisControl *control) {
  499.         int8_t x, y;
  500.      
  501.         for (y = ROW_BEGIN; y < ROW_END; ++y)  // 不显示顶部4行和底部2行
  502.                 {
  503.             gotoxyInPool(2, y);
  504.             // 定点到游戏池中的方格
  505.             for (x = COL_BEGIN; x < COL_END; ++x)  // 不显示左右边界
  506.                     {
  507.                 if ((manager->pool[y] >> x) & 1)  // 游戏池该方格有方块
  508.                         {
  509.                     // 用相应颜色,显示一个实心方块
  510.                     SetConsoleTextAttribute(g_hConsoleOutput, control->color[y][x]);
  511.                     printf("■");
  512.                 } else  // 没有方块,显示空白
  513.                 {
  514.                     SetConsoleTextAttribute(g_hConsoleOutput, 0);
  515.                     printf("%2s", "");
  516.                 }
  517.             }
  518.         }
  519.     }
  520.      
  521.     // =============================================================================
  522.     // 显示当前方块
  523.     void printCurrentTetris(const TetrisManager *manager,
  524.             const TetrisControl *control) {
  525.         int8_t x, y;
  526.      
  527.         // 显示当前方块是在移动后调用的,为擦去移动前的方块,需要扩展显示区域
  528.         // 由于不可能向上移动,故不需要向下扩展
  529.         y = (manager->y > ROW_BEGIN) ? (manager->y - 1) : ROW_BEGIN;  // 向上扩展一格
  530.         for (; y < ROW_END && y < manager->y + 4; ++y) {
  531.             x = (manager->x > COL_BEGIN) ? (manager->x - 1) : COL_BEGIN;  // 向左扩展一格
  532.             for (; x < COL_END && x < manager->x + 5; ++x)  // 向右扩展一格
  533.                     {
  534.                 gotoxyInPool(x, y);
  535.                 // 定点到游戏池中的方格
  536.                 if ((manager->pool[y] >> x) & 1)  // 游戏池该方格有方块
  537.                         {
  538.                     // 用相应颜色,显示一个实心方块
  539.                     SetConsoleTextAttribute(g_hConsoleOutput, control->color[y][x]);
  540.                     printf("■");
  541.                 } else  // 没有方块,显示空白
  542.                 {
  543.                     SetConsoleTextAttribute(g_hConsoleOutput, 0);
  544.                     printf("%2s", "");
  545.                 }
  546.             }
  547.         }
  548.     }
  549.      
  550.     // =============================================================================
  551.     // 显示下一个和下下一个方块
  552.     void printNextTetris(const TetrisManager *manager) {
  553.         int8_t i;
  554.         uint16_t tetris;
  555.      
  556.         // 边框
  557.         SetConsoleTextAttribute(g_hConsoleOutput, 0xF);
  558.         gotoxyWithFullwidth(26, 1);
  559.         printf("┏━━━━┳━━━━┓");
  560.         gotoxyWithFullwidth(26, 2);
  561.         printf("┃%8s┃%8s┃", "", "");
  562.         gotoxyWithFullwidth(26, 3);
  563.         printf("┃%8s┃%8s┃", "", "");
  564.         gotoxyWithFullwidth(26, 4);
  565.         printf("┃%8s┃%8s┃", "", "");
  566.         gotoxyWithFullwidth(26, 5);
  567.         printf("┃%8s┃%8s┃", "", "");
  568.         gotoxyWithFullwidth(26, 6);
  569.         printf("┗━━━━┻━━━━┛");
  570.      
  571.         // 下一个,用相应颜色显示
  572.         tetris = gs_uTetrisTable[manager->type[1]][manager->orientation[1]];
  573.         SetConsoleTextAttribute(g_hConsoleOutput, manager->type[1] | 8);
  574.         for (i = 0; i < 16; ++i) {
  575.             gotoxyWithFullwidth((i & 3) + 27, (i >> 2) + 2);
  576.             ((tetris >> i) & 1) ? printf("■") : printf("%2s", "");
  577.         }
  578.      
  579.         // 下下一个,不显示彩色
  580.         tetris = gs_uTetrisTable[manager->type[2]][manager->orientation[2]];
  581.         SetConsoleTextAttribute(g_hConsoleOutput, 8);
  582.         for (i = 0; i < 16; ++i) {
  583.             gotoxyWithFullwidth((i & 3) + 32, (i >> 2) + 2);
  584.             ((tetris >> i) & 1) ? printf("■") : printf("%2s", "");
  585.         }
  586.     }
  587.      
  588.     // =============================================================================
  589.     // 显示得分信息
  590.     void printScore(const TetrisManager *manager) {
  591.         static const char *tetrisName = "ITLJZSO";
  592.         int8_t i;
  593.      
  594.         SetConsoleTextAttribute(g_hConsoleOutput, 0xE);
  595.      
  596.         gotoxyWithFullwidth(2, 2);
  597.         printf("■得分:%u", manager->score);
  598.      
  599.         gotoxyWithFullwidth(1, 6);
  600.         printf("■消行总数:%u", manager->erasedTotal);
  601.         for (i = 0; i < 4; ++i) {
  602.             gotoxyWithFullwidth(2, 8 + i);
  603.             printf("□消%d:%u", i + 1, manager->erasedCount[i]);
  604.         }
  605.      
  606.         gotoxyWithFullwidth(1, 15);
  607.         printf("■方块总数:%u", manager->tetrisTotal);
  608.      
  609.         for (i = 0; i < 7; ++i) {
  610.             gotoxyWithFullwidth(2, 17 + i);
  611.             printf("□%c形:%u", tetrisName[i], manager->tetrisCount[i]);
  612.         }
  613.     }
  614.      
  615.     // =============================================================================
  616.     // 显示提示信息
  617.     void printPrompting() {
  618.         SetConsoleTextAttribute(g_hConsoleOutput, 0xB);
  619.         gotoxyWithFullwidth(26, 10);
  620.         printf("■控制:");
  621.         gotoxyWithFullwidth(27, 12);
  622.         printf("□向左移动:← A 4");
  623.         gotoxyWithFullwidth(27, 13);
  624.         printf("□向右移动:→ D 6");
  625.         gotoxyWithFullwidth(27, 14);
  626.         printf("□向下移动:↓ S 2");
  627.         gotoxyWithFullwidth(27, 15);
  628.         printf("□顺时针转:↑ W 8");
  629.         gotoxyWithFullwidth(27, 16);
  630.         printf("□逆时针转:0");
  631.         gotoxyWithFullwidth(27, 17);
  632.         printf("□直接落地:空格");
  633.         gotoxyWithFullwidth(27, 18);
  634.         printf("□暂停游戏:回车");
  635.         gotoxyWithFullwidth(25, 23);
  636.         printf("■By: wohaaitinciu 12.12.29");
  637.     }
  638.      
  639.     // =============================================================================
  640.     // 运行游戏
  641.     void runGame(TetrisManager *manager, TetrisControl *control) {
  642.         clock_t clockLast, clockNow;
  643.      
  644.         clockLast = clock();  // 计时
  645.         printTetrisPool(manager, control);  // 显示游戏池
  646.      
  647.         while (!manager->dead)  // 没挂
  648.         {
  649.             while (_kbhit())  // 有键按下
  650.             {
  651.                 keydownControl(manager, control, _getch());  // 处理按键
  652.             }
  653.      
  654.             if (!control->pause)  // 未暂停
  655.             {
  656.                 clockNow = clock();  // 计时
  657.                 // 两次记时的间隔超过0.45秒
  658.                 if (clockNow - clockLast > 0.45F * CLOCKS_PER_SEC ) {
  659.                     clockLast = clockNow;
  660.                     keydownControl(manager, control, 80);  // 方块往下移
  661.                 }
  662.             }
  663.         }
  664.     }
  665.      
  666.     // =============================================================================
  667.     // 再来一次
  668.     bool ifPlayAgain() {
  669.         int ch;
  670.      
  671.         SetConsoleTextAttribute(g_hConsoleOutput, 0xF0);
  672.         gotoxyWithFullwidth(15, 10);
  673.         printf("游戏结束");
  674.         gotoxyWithFullwidth(13, 11);
  675.         printf("按Y重玩,按N退出");
  676.      
  677.         do {
  678.             ch = _getch();
  679.             if (ch == 'Y' || ch == 'y') {
  680.                 return true;
  681.             } else if (ch == 'N' || ch == 'n') {
  682.                 return false;
  683.             }
  684.         } while (1);
  685.     }
  686.      
  687.  
  688.  

回复 "超级无敌俄罗斯大回旋方块"

这儿你可以回复上面这条便签

captcha