# Tetris D1061139 ### 修改 * 主頁面 * 重新開始 ### 程式碼 #### 主頁面 ```javascript= /*開始介面*/ void PrintStartScreen() { printf("**********************************************\n"); printf("* *\n"); printf("* Welcome to My Game! *\n"); printf("* *\n"); printf("**********************************************\n"); printf("\n"); } /*按下x關閉遊戲其餘開始遊戲*/ int main() { PrintStartScreen(); char leave; printf("Press 'x' to exit or any other key to start the game:"); leave = getch(); if (leave == 'X' || leave == 'x') { printf("\nExiting the game...\n"); return 0; } ``` 使用函示,函式放在main最開始的時候。 #### 重新開始 ```javascript= /*重製遊戲*/ void resetGame(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], State* state) { state->x = CANVAS_WIDTH / 2; state->y = 0; state->score = 0; state->rotate = 0; state->fallTime = 0; for (int i = 0; i < 4; i++) { state->queue[i] = rand() % 7; } for (int i = 0; i < CANVAS_HEIGHT; i++) { for (int j = 0; j < CANVAS_WIDTH; j++) { resetBlock(&canvas[i][j]); } } } /*main*/ else { srand(time(NULL)); Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH]; State state; bool playAgain = true; while (playAgain) { resetGame(canvas, &state); while (1) { system("cls"); move(canvas, state.x, state.y, state.rotate, state.x, state.y, state.rotate, state.queue[0]); logic(canvas, &state); printCanvas(canvas, &state); Sleep(100); if (!move(canvas, state.x, state.y, state.rotate, state.x, state.y, state.rotate, state.queue[0])) { break; } } system("cls"); printf("Still wanna play?\n"); printf("Yes/No : "); char ch,ch2; ch = getch(); ch2 = getch(); getch(); if (ch2 == 'N' || ch2 == 'n') { system("cls"); playAgain = false; } else { system("cls"); } } printf("Exiting the game...\n"); return 0; } } ``` 將遊戲初始化包裝成一個函式,並且遊戲結束時(logic中的while迴圈裡的exit要刪掉)詢問是否重新開始遊戲。 ### 完整程式碼 ```javascript= #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <time.h> #include <windows.h> #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 CANVAS_WIDTH 10 #define CANVAS_HEIGHT 20 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} } } }, }; 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; } 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) { 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\u3000", 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 "); } } } } 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) { 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; } state->fallTime += RENDER_DELAY; 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++; } else { state->score += 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])) { printf("\033[%d;%dH\x1b[41m GAME OVER \x1b[0m\033[%d;%dH", CANVAS_HEIGHT - 3, CANVAS_WIDTH * 2 + 5, CANVAS_HEIGHT + 5, 0); //exit(0); } } } return; } void PrintStartScreen() { printf("**********************************************\n"); printf("* *\n"); printf("* Welcome to My Game! *\n"); printf("* *\n"); printf("**********************************************\n"); printf("\n"); } void resetGame(Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH], State* state) { state->x = CANVAS_WIDTH / 2; state->y = 0; state->score = 0; state->rotate = 0; state->fallTime = 0; for (int i = 0; i < 4; i++) { state->queue[i] = rand() % 7; } for (int i = 0; i < CANVAS_HEIGHT; i++) { for (int j = 0; j < CANVAS_WIDTH; j++) { resetBlock(&canvas[i][j]); } } } int main() { PrintStartScreen(); char leave; printf("Press 'x' to exit or any other key to start the game:"); leave = getch(); if (leave == 'X' || leave == 'x') { printf("\nExiting the game...\n"); return 0; } else { srand(time(NULL)); Block canvas[CANVAS_HEIGHT][CANVAS_WIDTH]; State state; bool playAgain = true; while (playAgain) { resetGame(canvas, &state); while (1) { system("cls"); move(canvas, state.x, state.y, state.rotate, state.x, state.y, state.rotate, state.queue[0]); logic(canvas, &state); printCanvas(canvas, &state); Sleep(100); if (!move(canvas, state.x, state.y, state.rotate, state.x, state.y, state.rotate, state.queue[0])) { break; } } system("cls"); printf("Still wanna play?\n"); printf("Yes/No : "); char ch,ch2; ch = getch(); ch2 = getch(); getch(); if (ch2 == 'N' || ch2 == 'n') { system("cls"); playAgain = false; } else { system("cls"); } } printf("Exiting the game...\n"); return 0; } } ```