# 烏克蘭方塊 (Ukraine Tetris) 首先一進入遊戲 會出現熱情奔放的歡迎頁面 ![](https://hackmd.io/_uploads/BJcXorCIn.png) 再來選擇**是否按F進入遊戲**(只有內部測試人員才知道按G可以開啟beta版的測試功能)![](https://hackmd.io/_uploads/rkHsqSRUn.gif) 下載正常版即享有專業代碼**破解高清畫面** 隨附**方塊代管系統 足跡保存系統 時空粒子加速功能** ## 破解高清畫面 ![reference link](https://hackmd.io/_uploads/H1rMC4CIh.png) ※本商品建議在光線暗的地方使用,效果更佳、更明顯出色 請不要在背光、反光的環境下使用(因光線充足會產生折射,造成光線混亂,使畫面模糊不清,甚至會感到頭昏眼花哦) ## 隨附方塊代管系統 ![](https://hackmd.io/_uploads/rks3zrRU2.gif) 提供客製化台藉管家全天服務, 針對每一種方塊類型的需求,安排適合的管家,並且提供飯店式管家服務水準,讓您每一次操作都像在享受五星級飯店的專人管家服務。 ## 足跡保存系統 ![](https://hackmd.io/_uploads/H1QBrBR8h.gif) 是個人足跡地圖,可根據定位記錄呈現您消除的行數、路線和行程。您可以在遊戲結束後查看足跡,也可以在遊戲後刪除時間軸中的分數記錄。 ※本功能假如開啟了網路和應用程式活動等設定,即使已關閉定位記錄功能或將位置資料從定位記錄中刪除,系統仍「**可能**」會在您使用其他 Google 協作平台、應用程式和服務時,將位置資料儲存至雲端帳戶中。 ## 時空粒子加速功能 ![](https://hackmd.io/_uploads/BJgYwHCU3.png) 超時空粒子加速功能為同盟國聯軍通用的支援技能,由超時空傳送儀解鎖。 使用後,能通過特定條件(消除特定行數),觸發重力場變化,改變時間的流速,從而讓一定範圍內的使用使用的四方形、長條狀、閃電型方塊移動速度提高,且從理論而言速度可無止盡上升。 # beta版 可以體驗開發團隊正在測試的**自旋姿態落點精準判定系統** **外搖桿操縱物體質變系統** ## 自旋姿態落點精準判定系統 ## ![](https://hackmd.io/_uploads/Hyb00SAI3.gif) 本系統涉及以等傾角姿態控制的自旋穩定方塊姿態方式,此方法以自旋穩定方塊在參考坐標系下的初始狀態、目標姿態和姿控量為輸入, 對方塊姿態進行預測,計算麥卡托座標圖,並對X軸0度角水平線和Y軸垂直鉛直線進行預測,根據已經計算出的姿態控制參數(姿控量)和給定的控制方式計算出方塊姿態因受控而發生垂直翻轉、水平翻轉之姿態變化。 ## 外搖桿操縱物體質變系統 ![](https://hackmd.io/_uploads/HJtdZUAI2.gif) 又稱為外搖桿操縱物體質變系統(External Joystick Manipulation System),此技術為我們帶來了前所未有的物體操作體驗。本系統乃基於普遍應用的單面物理觸點技術運作,使我們能夠以鍵盤為媒介,打破物理守則,消除不需要的方塊,遠端一鍵操控引起方塊的質變。 以下為程式碼 ``` #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <time.h> #include <windows.h> #define DELETE_KEY 0x44 #define DELETE_FUNC() GetAsyncKeyState(DELETE_KEY) & 0x8000 #define LEFT_KEY 0x25 // The key to move left, default = 0x25 (left arrow) #define RIGHT_KEY 0x27 // The key to move right, default = 0x27 (right arrow) #define ROTATE_KEY 0x26 // The key to rotate, default = 0x26 (up arrow) #define DOWN_KEY 0x28 // The key to move down, default = 0x28 (down arrow) #define FALL_KEY 0x20 // The key to fall, default = 0x20 (spacebar) #define FALL_DELAY 500 // The delay between each fall, default = 500 #define RENDER_DELAY 100 // The delay between each frame, default = 100 #define LEFT_FUNC() GetAsyncKeyState(LEFT_KEY) & 0x8000 #define RIGHT_FUNC() GetAsyncKeyState(RIGHT_KEY) & 0x8000 #define ROTATE_FUNC() GetAsyncKeyState(ROTATE_KEY) & 0x8000 #define DOWN_FUNC() GetAsyncKeyState(DOWN_KEY) & 0x8000 #define FALL_FUNC() GetAsyncKeyState(FALL_KEY) & 0x8000 #define HOLD_FUNC() GetAsyncKeyState(HOLD_KEY) & 0x8000 #define QUIT_FUNC() GetAsyncKeyState(QUIT_KEY) & 0x8000 #define HOLD_KEY 0x43 #define QUIT_KEY 0x51 #define CANVAS_WIDTH 10 #define CANVAS_HEIGHT 20 int tmp = 0; int tmpscore = 0; int flag = 0; typedef enum { RED = 41, GREEN, YELLOW, BLUE, PURPLE, CYAN, WHITE, BLACK = 0, }Color; typedef enum { EMPTY = -1, I, J, L, O, S, T, Z }ShapeId; typedef struct { ShapeId shape; Color color; int size; char rotates[4][4][4]; }Shape; typedef struct { int x; int y; int score; int rotate; int fallTime; ShapeId queue[4]; }State; typedef struct { Color color; ShapeId shape; bool current; }Block; Shape shapes[7] = { { .shape = I, .color = CYAN, .size = 4, .rotates = { { {0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0} }, { {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0} }, { {0, 0, 0, 0}, {0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0} }, { {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0}, {0, 1, 0, 0} } } }, { .shape = J, .color = BLUE, .size = 3, .rotates = { { {1, 0, 0}, {1, 1, 1}, {0, 0, 0} }, { {0, 1, 1}, {0, 1, 0}, {0, 1, 0} }, { {0, 0, 0}, {1, 1, 1}, {0, 0, 1} }, { {0, 1, 0}, {0, 1, 0}, {1, 1, 0} } } }, { .shape = L, .color = YELLOW, .size = 3, .rotates = { { {0, 0, 1}, {1, 1, 1}, {0, 0, 0} }, { {0, 1, 0}, {0, 1, 0}, {0, 1, 1} }, { {0, 0, 0}, {1, 1, 1}, {1, 0, 0} }, { {1, 1, 0}, {0, 1, 0}, {0, 1, 0} } } }, { .shape = O, .color = WHITE, .size = 2, .rotates = { { {1, 1}, {1, 1} }, { {1, 1}, {1, 1} }, { {1, 1}, {1, 1} }, { {1, 1}, {1, 1} } } }, { .shape = S, .color = GREEN, .size = 3, .rotates = { { {0, 1, 1}, {1, 1, 0}, {0, 0, 0} }, { {0, 1, 0}, {0, 1, 1}, {0, 0, 1} }, { {0, 0, 0}, {0, 1, 1}, {1, 1, 0} }, { {1, 0, 0}, {1, 1, 0}, {0, 1, 0} } } }, { .shape = T, .color = PURPLE, .size = 3, .rotates = { { {0, 1, 0}, {1, 1, 1}, {0, 0, 0} }, { {0, 1, 0}, {0, 1, 1}, {0, 1, 0} }, { {0, 0, 0}, {1, 1, 1}, {0, 1, 0} }, { {0, 1, 0}, {1, 1, 0}, {0, 1, 0} } } }, { .shape = Z, .color = RED, .size = 3, .rotates = { { {1, 1, 0}, {0, 1, 1}, {0, 0, 0} }, { {0, 0, 1}, {0, 1, 1}, {0, 1, 0} }, { {0, 0, 0}, {1, 1, 0}, {0, 1, 1} }, { {0, 1, 0}, {1, 1, 0}, {1, 0, 0} } } }, }; Shape Hold = {.size = 0}; bool isHold = false; int scoremode = 0; bool programContinue = true; bool drop_predict(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], int X_position, int Y_position, int newRotate, ShapeId shapeId) { Shape shapeData = shapes[shapeId]; for (int i = 0; i < shapeData.size; i++) { for (int j = 0; j < shapeData.size; j++) { if (shapeData.rotates[newRotate][i][j]) { if (X_position + j < 0 || X_position + j >= CANVAS_WIDTH || Y_position + i < 0 || Y_position + i >= CANVAS_HEIGHT) { return false; } if (!canvas[Y_position + i][X_position + j].current && canvas[Y_position + i][X_position + j].shape != EMPTY) { return false; } } } } return true; } void setBlock(Block* block, Color color, ShapeId shape, bool current) { block->color = color; block->shape = shape; block->current = current; } void resetBlock(Block* block) { block->color = BLACK; block->shape = EMPTY; block->current = false; } void cleanShape(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], int originalX, int originalY, int originalRotate, ShapeId shapeId) { Shape shapeData = shapes[shapeId]; int size = shapeData.size; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[originalRotate][i][j]) { resetBlock(&canvas[originalY + i][originalX + j]); } } } } bool move(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], int originalX, int originalY, int originalRotate, int newX, int newY, int newRotate, ShapeId shapeId) { Shape shapeData = shapes[shapeId]; int size = shapeData.size; // check if the new position is valid to place the block for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[newRotate][i][j]) { if (newX + j < 0 || newX + j >= CANVAS_WIDTH || newY + i < 0 || newY + i >= CANVAS_HEIGHT) { return false; } if (!canvas[newY + i][newX + j].current && canvas[newY + i][newX + j].shape != EMPTY) { return false; } } } } // remove the old position for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[originalRotate][i][j]) { resetBlock(&canvas[originalY + i][originalX + j]); } } } // move the block for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[newRotate][i][j]) { setBlock(&canvas[newY + i][newX + j], shapeData.color, shapeId, true); } } } return true; } void printCanvas(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], State* state, char tmp) { int y_position = state->y + 1; printf("\033[0;0H\n"); for (int i = 0; i < CANVAS_HEIGHT; i++) { printf("|"); for (int j = 0; j < CANVAS_WIDTH; j++) { printf("\033[%dm ", canvas[i][j].color); } printf("\033[0m|\n"); } Shape shapeData = shapes[state->queue[1]]; printf("\033[%d;%dHNext:", 3, CANVAS_WIDTH * 2 + 5); for (int i = 1; i <= 3; i++) { shapeData = shapes[state->queue[i]]; for (int j = 0; j < 4; j++) { printf("\033[%d;%dH", i * 4 + j, CANVAS_WIDTH * 2 + 15); for (int k = 0; k < 4; k++) { if (j < shapeData.size && k < shapeData.size && shapeData.rotates[0][j][k]) { printf("\x1b[%dm ", shapeData.color); } else { printf("\x1b[0m "); } } } } if(tmp=='g'){ // 計算掉落方塊的最終位置 while (drop_predict(canvas, state->x, y_position, state->rotate, state->queue[0])) { y_position++; } // 顯示正在掉落的方塊 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (i < shapeData.size && j < shapeData.size && shapeData.rotates[state->rotate][i][j]) { printf("\033[%d;%dH\033[%dmo\033[0m", y_position + i + 1, 2 * (state->x + j)+2 , 37); } } } } printf("\033[%d;%dHHold:", 3, CANVAS_WIDTH * 2 + 25); if (!isHold) { for (int j = 0; j < 4; j++) { printf("\033[%d;%dH", 1 * 4 + j, CANVAS_WIDTH * 2 + 35); for (int k = 0; k < 4; k++) { if (j < Hold.size && k < Hold.size && Hold.rotates[0][j][k]) { printf("\x1b[%dm ", Hold.color); } else { printf("\x1b[0m "); } } } } printf("\033[%d;%dHScore: %d", 20, CANVAS_WIDTH * 2 + 5, (state->score)); return; } int clearLine(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH]) { for (int i = 0; i < CANVAS_HEIGHT; i++) { for (int j = 0; j < CANVAS_WIDTH; j++) { if (canvas[i][j].current) { canvas[i][j].current = false; } } } int linesCleared = 0; for (int i = CANVAS_HEIGHT - 1; i >= 0; i--) { bool isFull = true; for (int j = 0; j < CANVAS_WIDTH; j++) { if (canvas[i][j].shape == EMPTY) { isFull = false; break; } } if (isFull) { linesCleared += 1; for (int j = i; j > 0; j--) { for (int k = 0; k < CANVAS_WIDTH; k++) { setBlock(&canvas[j][k], canvas[j - 1][k].color, canvas[j - 1][k].shape, false); resetBlock(&canvas[j - 1][k]); } } i++; } } return linesCleared; } void logic(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], State* state, char tmp) { if (ROTATE_FUNC()) { int newRotate = (state->rotate + 1) % 4; if (move(canvas, state->x, state->y, state->rotate, state->x, state->y, newRotate, state->queue[0])) { state->rotate = newRotate; } } else if (LEFT_FUNC()) { if (move(canvas, state->x, state->y, state->rotate, state->x - 1, state->y, state->rotate, state->queue[0])) { state->x -= 1; } } else if (RIGHT_FUNC()) { if (move(canvas, state->x, state->y, state->rotate, state->x + 1, state->y, state->rotate, state->queue[0])) { state->x += 1; } } else if (DOWN_FUNC()) { state->fallTime = FALL_DELAY; } else if (FALL_FUNC()) { state->fallTime += FALL_DELAY * CANVAS_HEIGHT; } else if (HOLD_FUNC() && !isHold) { isHold = false; cleanShape(canvas, state->x, state->y, state->rotate, state->queue[0]);//clean original shape if (Hold.size == 0) { Hold = shapes[state->queue[0]]; state->queue[0] = state->queue[1]; state->queue[1] = state->queue[2]; state->queue[2] = state->queue[3]; state->queue[3] = rand() % 7; }//hold have nothing else { ShapeId temp = state->queue[0]; state->queue[0] = Hold.shape; Hold = shapes[temp]; }//when hold exist state->rotate = 0; } else if (DELETE_FUNC()) { // Check if the current block can be deleted bool canDelete = true; Shape shapeData = shapes[state->queue[0]]; int size = shapeData.size; if(tmp=='g'){ for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[state->rotate][i][j]) { int deleteX = state->x + j; int deleteY = state->y + i; if (deleteY >= 0 && deleteY < CANVAS_HEIGHT && deleteX >= 0 && deleteX < CANVAS_WIDTH) { if (!canvas[deleteY][deleteX].current) { canDelete = false; break; } } } } if (!canDelete) { break; } } // Delete the current block if (canDelete) { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { if (shapeData.rotates[state->rotate][i][j]) { int deleteX = state->x + j; int deleteY = state->y + i; if (deleteY >= 0 && deleteY < CANVAS_HEIGHT && deleteX >= 0 && deleteX < CANVAS_WIDTH) { resetBlock(&canvas[deleteY][deleteX]); } } } } } } } state->fallTime += RENDER_DELAY; if (state->score > tmpscore) { flag = 0; } else { flag = 1; } if ((state->score) % 2 == 0 && state->score != 0 && flag == 0) { tmp += 15; flag = 1; } state->fallTime += tmp; while (state->fallTime >= FALL_DELAY) { state->fallTime -= FALL_DELAY; if (move(canvas, state->x, state->y, state->rotate, state->x, state->y + 1, state->rotate, state->queue[0])) { state->y++; tmpscore = state->score; } else { tmpscore = state->score; state->score += 5*clearLine(canvas); state->x = CANVAS_WIDTH / 2; state->y = 0; state->rotate = 0; state->fallTime = 0; state->queue[0] = state->queue[1]; state->queue[1] = state->queue[2]; state->queue[2] = state->queue[3]; state->queue[3] = rand() % 7; if (!move(canvas, state->x, state->y, state->rotate, state->x, state->y, state->rotate, state->queue[0])) { system("cls"); printf("\033[%d;%dH\x1b[41m GAME OVER \x1b[0m\033[%d;%dH\n", CANVAS_HEIGHT - 15, CANVAS_WIDTH * 2-10, CANVAS_HEIGHT + 10, -10); printf(" Your scores is : %d !!!!\n\n\n\n",state->score); exit(0); } } } return; } void playIntroAnimation() { // 開頭動畫程式碼 printf("<<<<<<<<<<<<<<<<<<<__>>>>>>>>>>>>>>>>>>>>>\n"); printf("========~~~~~~Ukraine TETRIS!~~~~~~=======\n"); printf("<<<<<<<<<<<<<<<<<<<-->>>>>>>>>>>>>>>>>>>>>\n"); Sleep(2000); } int main() { char tmp; srand(time(NULL)); playIntroAnimation(); State state = { .x = CANVAS_WIDTH / 2, .y = 0, .score = 0, .rotate = 0, .fallTime = 0 }; for (int i = 0; i < 4; i++) { state.queue[i] = rand() % 7; } Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH]; for (int i = 0; i < CANVAS_HEIGHT; i++) { for (int j = 0; j < CANVAS_WIDTH; j++) { resetBlock(&canvas[i][j]); } } system("cls"); printf("\nPress\nF\nto\nenter\nthe\ntetris: "); scanf("%c", &tmp); if (tmp != 'f' && tmp!= 'g') return 0; // printf("\e[?25l"); // hide cursor move(canvas, state.x, state.y, state.rotate, state.x, state.y, state.rotate, state.queue[0]); while (1) { logic(canvas, &state, tmp); printCanvas(canvas, &state, tmp); Sleep(100); } }//pray for ukraine ```