PACMAN
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

系統設定

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
請務必先完成 Dev-C++ 設定

Dev-C++
  1. 點選左上角 File -> Open

    image

  2. 選擇 桌面 -> EEcamp -> EEcamp_6.22.1 -> main.cpp 及 pacman.hpp -> 點選 open

    image

  3. 開啟檔案後點選上方 Tools -> Compiler Options

    image

  4. 勾選

  • Add the following commands when calling the compiler
    並新增:
    -std=c++14 -static
    再點選 ok✅
    image
終端機介面

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
在你的程式可以執行之後設定

  1. 對彈出的視窗(終端機terminal)上方白色區域點擊右鍵
  2. 選擇內容
  3. 設定字型大小 28
  4. 設定字體種類 Consolas
  5. 點擊下方確定

程式碼複製區

main.cpp
#include <bits/stdc++.h> #include <windows.h> #define HEIGHT 15 #define WIDTH 66 // 定 義 遊 戲 區 域 的 高 度 和 寬 度 #define powerNum 4 #define ghostNum 4 // 能 量 球 和 鬼 的 數 量 #include "pacman.hpp" //#define __VScode // 若 使 用 VScode 請 取 消 註 解 using namespace std; int dir[5][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, {0, 0}}; // d,s,a,w,stop bool gameRunning = true; // 檢 查 是 否 與 牆 壁 碰 撞 bool checkNotCollideWall(string grid[], int i, int j) { int n = HEIGHT, m = WIDTH; if (/*question 1*/) return false; // 如 果 超 出 邊 界 或 碰 到 牆 壁 , 回 傳 false return true; // 否 則 回 傳 true } // 檢 查 是 否 與 鬼 碰 撞 bool checkCollideGhost(int (*ghostPos)[2], int playerPos[2]) { for (int i = 0; i < ghostNum; i++) { if (/*question 2*/) { return true; // 如 果 pacman 與 鬼 的 座 標 相 同 , 回 傳true } } return false; // 否 則 回 傳 false } // 計 算 最 佳 方 向 int bestDir(string grid[], int curPos[2], int curDir, int target[2]) { int n = HEIGHT, m = WIDTH; int ans = 4; // 預 設 為 停 止 int minDis = INT16_MAX; // 最 小 距 離 初 始 化 為 最 大 值 for (int i = 0; i < 4; i++) { if (i == (curDir + 2) % 4) continue; // 不 考 慮 反 方 向 int newI = curPos[0] + dir[i][0]; // 新 的 i 座 標 int newJ = curPos[1] + dir[i][1]; //新 的 j 座 標 int dis = /*question 3*/ ; if (dis < minDis && checkNotCollideWall(grid, newI, newJ)) { ans = i; // 更 新 最 佳 方 向 minDis = dis; // 更 新 最 小 距 離 } } return ans; // 回 傳 最 佳 方 向 } // 移 動 鬼 template <int _N> void moveGhost(string grid[], int (&ghostPos)[_N][2], int (&ghostDir)[_N], char ghostType[], int playerPos[2], int playerDir, bool scaredMode) { for (int i = 0; i < ghostNum; i++) { int legalRoute = 0; // 合 法 路 徑 計 數 int possibleDir[3]; // 存 儲 可 能 的 方 向 for (int j = 0; j < 4; j++) { if ((checkNotCollideWall(grid, ghostPos[i][0] + dir[j][0], ghostPos[i][1] + dir[j][1])) && (j != (ghostDir[i] + 2) % 4)) { possibleDir[legalRoute] = j; // 存 儲 有 效 方 向 legalRoute++; } } legalRoute++; if (!scaredMode) { // 如 果 不 是 驚 嚇 模 式 if (legalRoute == 1) { ghostDir[i] = (ghostDir[i] + 2) % 4; // 反 向 移 動 } else if (legalRoute == 2) { ghostDir[i] = possibleDir[0]; // 隨 機 選 擇 一 個 方 向 } else if (legalRoute == 3 || legalRoute == 4) { int target[2] = {}; if (ghostType[i] == 'a') { // 紅 鬼 :目 標 pacman 位 置 /*question 4*/ } else if (ghostType[i] == 'b') { // 粉 紅 鬼 :目 標 pacman 位 置 4 格 前 /*question 5*/ } else if (ghostType[i] == 'c') { // 淺 藍 鬼 :目 標 與 紅 色 鬼 對 稱 中 心 在 pacman 前 方 2 格 int indexOfRed = 0; for (int j = 0; j < ghostNum; j++) { if (ghostType[j] == 'a') { indexOfRed = j; break; } } int center[2]; center[0] = playerPos[0] + dir[playerDir][0] * 2; center[1] = playerPos[1] + dir[playerDir][1] * 2; /*question 6*/ } else if (ghostType[i] == 'd') { // 橙 鬼 :保 持 4 格 距 離 double a, b; a = ghostPos[i][0] - playerPos[0]; b = ghostPos[i][1] - playerPos[1]; target[0] = round(playerPos[0] + a * 4 / sqrt(a * a + b * b)); target[1] = round(playerPos[1] + b * 4 / sqrt(a * a + b * b)); } ghostDir[i] = bestDir(grid, ghostPos[i], ghostDir[i], target); // 計 算 最 佳 方 向 } } else { // 如 果 是 驚 嚇 模 式 if (isupper(ghostType[i])) { if (legalRoute == 1) { ghostDir[i] = (ghostDir[i] + 2) % 4; // 反 向 移 動 } else if (legalRoute == 2) { // 不 回 頭 ghostDir[i] = possibleDir[0]; } else if (legalRoute == 3 || legalRoute == 4) { // 不 回 頭 ghostDir[i] = possibleDir[rand() % (legalRoute - 1)]; } } if (islower(ghostType[i])) { // 復 活 先 不 動 ghostDir[i] = 4; } } if (checkNotCollideWall(grid, ghostPos[i][0] + dir[ghostDir[i]][0], ghostPos[i][1] + dir[ghostDir[i]][1])) { ghostPos[i][0] += dir[ghostDir[i]][0]; // 根 據 方 向 移 動 ghostPos[i][1] += dir[ghostDir[i]][1]; } } } // 吃 掉 鬼 void eatGhost(string grid[], int playerPos[2], int (*ghostPos)[2], int (&ghostDir)[ghostNum], char (&ghostType)[ghostNum], int &score) { for (int i = 0; i < ghostNum; i++) { if (ghostPos[i][0] == playerPos[0] && ghostPos[i][1] == playerPos[1]) { score += 200; // 吃 掉 鬼 的 得 分 /*question 7*/ ghostDir[i] = 4; // 設 置 鬼 的 方 向 為 停 止 ghostType[i] = tolower(ghostType[i]); // 將 鬼 的 類 型 改 為 小 寫 } } } int main() { srand(time(0)); // 設 置 隨 機 數 種 子 #ifndef __VScode SetConsoleCtrlHandler(ConsoleHandler, TRUE); system("chcp 65001"); #endif string initGrid[HEIGHT] = { "#################################################################", "#...............................................................#", "#..###...#...##...##.....#####....#......#...#######...#######..#", "#..#.#...#....##.##.....##...##...#......#...#.........#........#", "#..#.###.#.....###......#.........#......#...#######...#######..#", "#..#...#.#......#.......##...##...##....##...#.........#........#", "#..#...###......#........#####.....######....#######...#######..#", "#...............................0...............................#", "#...#####.....#####....##....##...########...#######...#######..#", "#..##...##...## ##...###..###...# #.........#...#........#", "#..#.........#######...#.####.#...########...#######...#######..#", "#..##...##...#.....#...#..##..#...#..........#...............#..#", "#...#####....#.....#...#......#...#..........#######...#######..#", "#...............................................................#", "#################################################################"}; int pointsCnt = 0; int playerPos[2]; // pacman 位 置 int playerDir = 3; // 初 始 方 向 為 'w' int ghostPos[ghostNum][2]; // 鬼 的 位 置 int ghostDir[ghostNum] = {4, 4, 4, 4}; // 鬼 的 方 向 char ghostType[ghostNum]; // 鬼 的 類 型 int score = 0; // 分 數 int scaredTime = 0; // 驚 嚇 時 間 bool scaredMode = false; // 是 否 在 驚 嚇 模 式 string pointsGrid[HEIGHT]; // 點 數 網 格 string gridDisplay[HEIGHT]; // 顯 示 網 格 string prevGridDisplay[HEIGHT]; // 前 一 個 顯 示 網 格 for (int i = 0; i < HEIGHT; i++) { string row = ""; row.append(WIDTH, ' '); pointsGrid[i] = row; // 初 始 化 點 數 網 格 gridDisplay[i] = row; // 初 始 化 顯 示 網 格 prevGridDisplay[i] = row; // 初 始 化 前 一 個 顯 示 網 格 } for (int i = 0; i < HEIGHT; i++) { // 設 定 pacman 位 置 的 初 始 狀 態 for (int j = 0; j < WIDTH; j++) { char c = initGrid[i][j]; if (c == '0') { /*question 8*/ } } } // 隨 機 放 置 能 量 球 for (int p = 0; p < powerNum; p++) { int x, y; do { x = rand() % HEIGHT; // 隨 機 列 y = rand() % WIDTH; // 隨 機 行 } while (/*question 9*/); initGrid[x][y] = '*'; // 放 置 能 量 球 } // 隨 機 放 置 鬼 for (int i = 0; i < ghostNum; i++) { int x, y; do { x = rand() % HEIGHT; // 隨 機 列 y = rand() % WIDTH; // 隨 機 行 } while (!(initGrid[x][y] == '.' && ((x - playerPos[0]) * (x - playerPos[0]) + (y - playerPos[1]) * (y - playerPos[1])) >= 49)); // 確 保 放 置 在 合 法 位 置 且 距 離 pacman 有 一 定 距 離 ghostPos[i][0] = x; // 設 置 鬼 的 行 ghostPos[i][1] = y; // 設 置 鬼 的 列 ghostType[i] = 'a' + i; // 分 配 鬼 的 類 型 a, b, c, d } for (/*question 10-1*/) { // 設 定 點 數 網 格 的 初 始 狀 態 for (/*question 10-2*/) { char c = initGrid[i][j]; gridDisplay[i][j] = c; // 初 始 化 顯 示 網 格 if (c == '.' || c == '*') { pointsGrid[i][j] = c; // 設 置 點 數 網 格 pointsCnt++; // 增 加 點 數 計 數 } } } KeyManager keyM; // 創 建 鍵 盤 管 理 器 int curDir = playerDir; // 當 前 方 向 bool gameOver = false; // 遊 戲 是 否 結 束 cout << "\x1B[2J\x1B[H" << "\033[?25l"; // 初 始 化 螢 幕 , 清 除 並 隱 藏 鼠 標 update(initGrid, playerPos, ghostPos, ghostDir, ghostType, pointsGrid, pointsCnt, gridDisplay, score, scaredMode, scaredTime); gridPrint(gridDisplay, prevGridDisplay); cout << "\033[" << (HEIGHT + 1) << ";1H\033[K"; cout << "press any key to start game (use arrows or WASD to move pacman)" << endl; keyM.anyKeyToContinue(); for (int i = 3; i > 0; i--) { cout << "\033[" << (HEIGHT + 1) << ";1H\033[K"; cout << "starting in " << i << "........." << endl; Sleep(1000); } while (!gameOver && gameRunning) { // 移 動 pacman movePacman(initGrid, playerPos, playerDir, keyM); // 檢 查 是 否 與 鬼 碰 撞 if (checkCollideGhost(ghostPos, playerPos)) { if (scaredMode) eatGhost(initGrid, playerPos, ghostPos, ghostDir, ghostType, score); // 吃 掉 鬼 else gameOver = true; // 如 果 不 是 驚 嚇 模 式 , 遊 戲 結 束 } // 移 動 鬼 if (!(scaredMode && scaredTime % 2)) // 如 果 是 驚 嚇 模 式 只 有 一 半 的 時 間 會 移 動 鬼 moveGhost(initGrid, ghostPos, ghostDir, ghostType, playerPos, playerDir, scaredMode); // 再 次 檢 查 是 否 與 鬼 碰 撞 if (checkCollideGhost(ghostPos, playerPos)) { if (scaredMode) eatGhost(initGrid, playerPos, ghostPos, ghostDir, ghostType, score); // 吃 掉 鬼 else gameOver = true; // 如 果 不 是 驚 嚇 模 式 , 遊 戲 結 束 } // 更 新 遊 戲 狀 態 update(initGrid, playerPos, ghostPos, ghostDir, ghostType, pointsGrid, pointsCnt, gridDisplay, score, scaredMode, scaredTime); // 輸 出 遊 戲 網 格 gridPrint(gridDisplay, prevGridDisplay); cout << "\033[" << (HEIGHT + 1) << ";1H\033[K"; // 移 動 鼠 標 到 顯 示 分 數 的 位 置 cout << "Score: " << score << endl; // 顯 示 分 數 Sleep(500); // 暫 停 0.5 秒 if (pointsCnt == 0) gameOver = true; // 如 果 所 有 點 數 都 被 吃 掉 , 遊 戲 結 束 } // 遊 戲 結 束 cout << "\033[?25h" << "\033[" << (HEIGHT + 2) << ";1H"; // 恢 復 鼠 標 顯 示 if (pointsCnt == 0) { cout << "You win! Final score: " << score << endl; // 如 果 贏 了 , 顯 示 勝 利 信 息 } else { cout << "Game Over! Final score: " << score << endl; // 如 果 遊 戲 結 束 , 顯 示 結 束 信 息 } return 0; // 回 傳 0 , 結 束 程 序 }
pacman.hpp
#pragma once #include <bits/stdc++.h> #include <windows.h> using namespace std; extern int dir[5][2]; extern bool gameRunning; bool checkNotCollideWall(string grid[], int i, int j); bool checkCollideGhost(int (*ghostPos)[2], int playerPos[2]); int bestDir(string grid[], int curPos[2], int curDir, int target[2]); template <int _N> void moveGhost(string grid[], int (&ghostPos)[_N][2], int (&ghostDir)[_N], char ghostType[], int playerPos[2], int playerDir, bool scaredMode); void eatGhost(string grid[], int playerPos[2], int (*ghostPos)[2], int (&ghostDir)[ghostNum], char (&ghostType)[ghostNum], int &score); // 鍵 盤 管 理 器 結 構 struct KeyManager { char lastDirC; // 最 後 按 下 的 方 向 鍵 字 符 int lastDir; // 最 後 按 下 的 方 向 std::map<char, int> wasdToDir = {{'d', 0}, {'s', 1}, {'a', 2}, {'w', 3}}; // WASD 鍵 對 應 的 方 向 bool start; // 是 否 開 始 bool newInput; // 是 否 有 新 輸 入 KeyManager() : lastDirC('w'), lastDir(4), start(true), newInput(false) { thread rK(&KeyManager::updateStatus, this); // 啟 動 更 新 狀 態 的 線 程 rK.detach(); // 分 離 線 程 } ~KeyManager() { start = false; // 停 止 更 新 狀 態 INPUT inputs[3] = {}; ZeroMemory(inputs, sizeof(inputs)); // 清 空 輸 入 inputs[1].type = INPUT_KEYBOARD; inputs[1].ki.wVk = 'w'; // 模 擬 按 下 'w' 鍵 inputs[2].type = INPUT_KEYBOARD; inputs[2].ki.wVk = 'w'; inputs[2].ki.dwFlags = KEYEVENTF_KEYUP; // 模 擬 釋 放 'w' 鍵 UINT unsent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT)); // 發 送 輸 入 } // 更 新 鍵 盤 狀 態 void updateStatus() { char cur = 'w'; lastDirC = cur; while (start) { cur = readKey(); // 讀 取 當 前 按 鍵 newInput = true; if (cur == 'w' || cur == 'a' || cur == 's' || cur == 'd') { lastDirC = cur; lastDir = wasdToDir[lastDirC]; // 更 新 方 向 } } return; } // 讀 取 按 鍵 char readKey() { INPUT_RECORD inputRecord; DWORD written; HANDLE stdInH = GetStdHandle(STD_INPUT_HANDLE); while (true) { ReadConsoleInputA(stdInH, &inputRecord, 1, &written); // 讀 取 控 制 台 輸 入 if (inputRecord.EventType == KEY_EVENT && inputRecord.Event.KeyEvent.bKeyDown) break; // 如 果 是 按 鍵 事 件 且 按 鍵 被 按 下 , 則 退 出 循 環 } switch (inputRecord.Event.KeyEvent.wVirtualScanCode) { case 72: return 'w'; // 回 傳 'w' case 75: return 'a'; // 回 傳 'a' case 80: return 's'; // 回 傳 's' case 77: return 'd'; // 回 傳 'd' default: return inputRecord.Event.KeyEvent.uChar.AsciiChar; // 回 傳 其 他 字 符 } } // 獲 取 最 後 按 下 的 鍵 int getLastKey() { return lastDir; } void anyKeyToContinue() { newInput = false; while (!newInput) {} return; } }; // 輸 出 遊 戲 網 格 void gridPrint(string grid[], string (&prevGrid)[HEIGHT]) { int n = HEIGHT, m = WIDTH; vector<vector<string>> gridDisplay(n, vector<string>(m, " ")); vector<vector<string>> gridDisplayColor(n, vector<string>(m, "")); vector<vector<string>> gridDisplayThick(n, vector<string>(m, "")); // 輸 出 顏 色 的 函 數 function<string(string, string, string)> outputColor = [&](string color, string thick, string output) { string ans = "\033["; std::map<string, string> colorGrid = { {"black", "0"}, {"red", "196"}, {"green", "46"}, {"yellow", "11"}, {"blue", "27"}, {"purple", "105"}, {"lightblue", "87"}, {"white", "255"}, {"pink", "219"}, {"skin", "224"}, {"orange", "214"}}; std::map<string, string> thickGrid = { {"bold", ";1"}, {"normal", ""}, {"light", ";2"}}; ans += "38;5;" + colorGrid[color] + thickGrid[thick] + "m"; ans += output; ans += "\033[0m"; return ans; }; // 檢 查 上 方 是 否 有 牆 壁 function<bool(int, int)> checkUp = [&](int x, int y) { if (0 <= x && x < n && 0 <= y && y < m) if (grid[x][y] == '#') return 1; // 如 果 是 牆 壁 , 回 傳 1 return 0; // 否 則 回 傳 0 }; // 填 充 網 格 顯 示 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (grid[i][j] == '#') { // 當 前 位 置 只 看 上 下 左 右 有 幾 個 # // 一 個 : ─ or │ // 兩 個 : ─ │ ┌ ┐ └ ┘ // 三 個 : 看 缺 少 的 邊 對 馬 步 的 兩 個 角 // 有 一 個 為 空 就 是 ├ ┤ ┬ ┴ 都 是 滿 的 就 是 ─ │ // 四 個 : 根 據 缺 角 // 缺 一 個 ┌ ┐ └ ┘ 缺 兩 個 相 鄰 ├ ┤ ┬ ┴ // 缺 兩 個 對 角 ┼ 缺 三 個 以 上 ┼ gridDisplayColor[i][j] = "blue"; // 牆 壁 顏 色 gridDisplayThick[i][j] = "normal"; // 牆 壁 粗 細 string type[16] = {"X", "─", "│", "╮", "─", "─", "╭", "┬", "│", "╯", "│", "┤", "╰", "┴", "├", "┼"}; int next = checkUp(i + 1, j) + checkUp(i - 1, j) + checkUp(i, j + 1) + checkUp(i, j - 1); if (next == 1 || next == 2) { int iCheck = checkUp(i - 1, j) * 8 + checkUp(i, j + 1) * 4 + checkUp(i + 1, j) * 2 + checkUp(i, j - 1); gridDisplay[i][j] = type[iCheck]; // 根 據 周 圍 牆 壁 的 數 量 選 擇 顯 示 的 字 符 } else if (next == 3) { if (!checkUp(i + 1, j) && (checkUp(i - 1, j + 1) && checkUp(i - 1, j - 1))) gridDisplay[i][j] = type[1]; else if (!checkUp(i - 1, j) && (checkUp(i + 1, j + 1) && checkUp(i + 1, j - 1))) gridDisplay[i][j] = type[1]; else if (!checkUp(i, j + 1) && (checkUp(i - 1, j - 1) && checkUp(i + 1, j - 1))) gridDisplay[i][j] = type[2]; else if (!checkUp(i, j - 1) && (checkUp(i - 1, j + 1) && checkUp(i + 1, j + 1))) gridDisplay[i][j] = type[2]; else { int iCheck = checkUp(i - 1, j) * 8 + checkUp(i, j + 1) * 4 + checkUp(i + 1, j) * 2 + checkUp(i, j - 1); gridDisplay[i][j] = type[iCheck]; } } else if (next == 4) { int angle = checkUp(i + 1, j + 1) + checkUp(i - 1, j + 1) + checkUp(i + 1, j - 1) + checkUp(i - 1, j - 1); if (angle == 4) { gridDisplay[i][j] = " "; // 如 果 四 周 都 有 牆 , 顯 示 空 格 } else if (angle == 3) { if (!checkUp(i + 1, j + 1)) gridDisplay[i][j] = type[6]; // ┌ else if (!checkUp(i - 1, j + 1)) gridDisplay[i][j] = type[12]; // └ else if (!checkUp(i + 1, j - 1)) gridDisplay[i][j] = type[3]; // ┐ else if (!checkUp(i - 1, j - 1)) gridDisplay[i][j] = type[9]; // ┘ } else if (angle == 2) { if (!checkUp(i + 1, j + 1) && !checkUp(i + 1, j - 1)) gridDisplay[i][j] = type[13]; // ┴ else if (!checkUp(i - 1, j + 1) && !checkUp(i - 1, j - 1)) gridDisplay[i][j] = type[7]; // ┬ else if (!checkUp(i + 1, j + 1) && !checkUp(i - 1, j + 1)) gridDisplay[i][j] = type[11]; // ┤ else if (!checkUp(i + 1, j - 1) && !checkUp(i - 1, j - 1)) gridDisplay[i][j] = type[14]; // ├ else gridDisplay[i][j] = type[15]; // ┼ } else gridDisplay[i][j] = type[15]; // ┼ } } else if (grid[i][j] == '0') { gridDisplayColor[i][j] = "yellow"; // pacman 顏 色 gridDisplayThick[i][j] = "bold"; // pacman 粗 細 gridDisplay[i][j] = "●"; // pacman 符 號 } else if (grid[i][j] == '*') { gridDisplayColor[i][j] = "skin"; // 能 量 球 顏 色 gridDisplayThick[i][j] = "normal"; // 能 量 球 粗 細 gridDisplay[i][j] = "○"; // 能 量 球 符 號 } else if (grid[i][j] == '.') { gridDisplayColor[i][j] = "skin"; // 點 數 顏 色 gridDisplayThick[i][j] = "normal"; // 點 數 粗 細 gridDisplay[i][j] = "."; // 點 數 符 號 } else if (grid[i][j] == ' ') { gridDisplayColor[i][j] = "white"; // 空 白 顏 色 gridDisplayThick[i][j] = "normal"; // 空 白 粗 細 gridDisplay[i][j] = " "; // 空 白 符 號 } else if (isalpha(grid[i][j])) { if (grid[i][j] == 'G') { // 嚇 人 的 鬼 gridDisplayColor[i][j] = "white"; gridDisplayThick[i][j] = "normal"; gridDisplay[i][j] = "ö"; // 嚇 人 的 鬼 符 號 } else if (isupper(grid[i][j])) { gridDisplayColor[i][j] = "purple"; // 鬼 的 顏 色 gridDisplayThick[i][j] = "normal"; // 鬼 的 粗 細 gridDisplay[i][j] = "ö"; // 鬼 符 號 } else if (islower(grid[i][j])) { string ghost[4] = {"red", "pink", "lightblue", "orange"}; gridDisplayColor[i][j] = ghost[grid[i][j] - 'a']; // 小 鬼 的 顏 色 gridDisplayThick[i][j] = "normal"; // 小 鬼 的 粗 細 gridDisplay[i][j] = "∩"; // 小 鬼 符 號 } } } } cout << "\033[H"; // 移 動 鼠 標 到 左 上 角 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (prevGrid[i][j] != grid[i][j]) { cout << "\033[" << (i + 1) << ";" << (j + 1) << "H"; // 移 動 光 標 到 指 定 位 置 cout << outputColor(gridDisplayColor[i][j], "normal", gridDisplay[i][j]); // 輸 出 顏 色 和 符 號 } } } cout << "\033[" << (n + 1) << ";1H"; // 移 動 鼠 標 到 下 一 行 for (int i = 0; i < n; i++) { prevGrid[i] = grid[i]; // 更 新 前 一 個 網 格 } } // 移 動 pacman void movePacman(string grid[], int (&playerPos)[2], int &curDir, KeyManager &keyM) { int input = keyM.getLastKey(); // 獲 取 最 後 按 下 的 鍵 if (checkNotCollideWall(grid, playerPos[0] + dir[input][0], playerPos[1] + dir[input][1])) { playerPos[0] += dir[input][0]; // 更 新 pacman 位 置 playerPos[1] += dir[input][1]; curDir = input; // 更 新 當 前 方 向 } else { curDir = 4; // 如 果 碰 到 牆 壁 , 設 置 為 停 止 } return; } // 重 新 生 成 鬼 的 位 置 void respawnGhost(string grid[], int (&ghostPos)[2], int playerPos[2]) { int maxDistance = -1; int farX = -1, farY = -1; for (int x = 0; x < HEIGHT; x++) { for (int y = 0; y < WIDTH; y++) { if (grid[x][y] == '.' && (x != playerPos[0] || y != playerPos[1])) { int distance = (x - playerPos[0]) * (x - playerPos[0]) + (y - playerPos[1]) * (y - playerPos[1]); if (distance > maxDistance) { maxDistance = distance; farX = x; farY = y; // 更 新 最 遠 位 置 } } } } ghostPos[0] = farX; // 設 置 鬼 的 位 置 ghostPos[1] = farY; } // 更 新 遊 戲 狀 態 void update(string grid[], int playerPos[2], int (*ghostPos)[2], int ghostDir[], char ghostType[], string (&pointsGrid)[HEIGHT], int &pointsCnt, string (&display)[HEIGHT], int &score, bool &scaredMode, int &scaredTime) { int n = HEIGHT, m = WIDTH; for (int i = 0; i < n; i++) { string row = ""; row.append(WIDTH, ' '); display[i] = row; // 初 始 化 顯 示 } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (grid[i][j] == '#') { display[i][j] = '#'; // 牆 壁 } if (pointsGrid[i][j] == '.') { display[i][j] = '.'; // 點 數 } if (pointsGrid[i][j] == '*') { display[i][j] = '*'; // 能 量 球 } } } if (pointsGrid[playerPos[0]][playerPos[1]] == '.') { pointsGrid[playerPos[0]][playerPos[1]] = ' '; // 吃 掉 點 數 score += 10; // 正 常 得 分 pointsCnt--; // 減 少 點 數 計 數 } else if (pointsGrid[playerPos[0]][playerPos[1]] == '*') { pointsGrid[playerPos[0]][playerPos[1]] = ' '; // 吃 掉 能 量 球 score += 50; // 能 量 球 得 分 scaredMode = true; // 啟 動 驚 嚇 模 式 scaredTime = 20; // 設 置 驚 嚇 時 間 為 20 , 實 際 時 間 0.5*20 為 10 秒 // 將 鬼 的 類 型 改 為 大 寫 for (int i = 0; i < ghostNum; i++) { ghostType[i] = toupper(ghostType[i]); } } // 減 少 驚 嚇 時 間 if (scaredMode) { scaredTime--; if (scaredTime <= 0) { scaredMode = false; // 停 止 驚 嚇 模 式 // 將 鬼 的 類 型 改 回 小 寫 for (int i = 0; i < ghostNum; i++) { ghostType[i] = tolower(ghostType[i]); } } } display[playerPos[0]][playerPos[1]] = '0'; // pacman 位 置 for (int i = 0; i < ghostNum; i++) { // 如 果 剩 下 3 秒 , 改 變 鬼 的 顏 色 if (scaredMode && scaredTime <= 6) { display[ghostPos[i][0]][ghostPos[i][1]] = 'G'; // 在 驚 嚇 模 式 下 用 'G' 表 示 鬼 } else { display[ghostPos[i][0]][ghostPos[i][1]] = ghostType[i]; // 正 常 鬼 顯 示 } } } #ifndef __VScode BOOL WINAPI ConsoleHandler(DWORD signal) { if (signal == CTRL_C_EVENT || signal == CTRL_CLOSE_EVENT) { gameRunning = false; return TRUE; } return FALSE; } #endif
(補充) pacman.hpp 內函數功能解說
KeyManager

持續偵測鍵盤輸入,紀錄最後按下的方向鍵或 W,A,S,D 鍵

void gridPrint(string grid[], string (&prevGrid)[HEIGHT])

傳入 grid 後會將其美化上色並輸出,另外需傳入 prevGrid 僅輸出有變化的部分以提高效率

void movePacman(string grid[], int (&playerPos)[2], int &curDir, KeyManager &keyM)

根據最後被按下的按鍵移動pacman

void respawnGhost(string grid[], int (&ghostPos)[2], int playerPos[2])

復活被pacman吃掉的鬼,使其距離pacman盡量遠

void update(string grid[], int playerPos[2], int (*ghostPos)[2],
            int ghostDir[], char ghostType[],
            string (&pointsGrid)[HEIGHT], int &pointsCnt, string (&display)[HEIGHT],
            int &score, bool &scaredMode, int &scaredTime)

更新玩家和鬼的位置,檢查玩家是否吃掉了點數或能量球,並更新分數。它還會處理驚嚇模式的啟動和結束,並更新顯示的遊戲狀態

GITHUB

回答表單

題目及提示

question 1 (line19)

if (/*question 1*/) return false; // 如果超出邊界或碰到牆壁,回傳false return true; // 否則回傳true

目標:
檢查超出邊界或碰到牆壁

  • 1.
i < 0 || i > n || j < 0 || j > m || grid[i][j] == '#'
  • 2.
i < 0 || i >= n || j < 0 || j >= m || grid[i][j] == '#'
  • 3.
i < 0 || i >= n || j < 0 || j >= m || grid[i][j] == '.'
  • 4.
i < 0 || i >= n || j < 0 || j >= m 

question 2 (line27)

if (/*question 2*/) { return true; // 如果pacman與鬼的座標相同,回傳true }

目標:
判斷pacman與鬼的座標是否相同

  • 1.
ghostPos[i][1] == playerPos[1] && ghostPos[i][2] == playerPos[2]
  • 2.
ghostPos[i][0] == playerPos[0] || ghostPos[i][1] == playerPos[1]
  • 3.
ghostPos[i][0] == playerPos[0] && ghostPos[i][1] == playerPos[1]
  • 4.
ghostPos[i] == playerPos

question 3 (line46)

int dis = /*question 3*/ ;

目標:
計算 newI, newJ 和 target 的直線距離的平方

  • 1.
(newI - target[0]) * (newI - target[0]) + (newJ - target[1]) * (newJ - target[1])
  • 2.
(newI - target[0]) + (newJ - target[1])
  • 3.
(newI - target[i]) + (newJ - target[j])
  • 4.
(newI  + newJ) - target

question 4 (line82)

if (ghostType[i] == 'a') { // 紅鬼:目標pacman位置 /*question 4*/ }

目標:
找到紅色鬼的目標位置(pacman位置)

  • 1.
target == playerPos;
  • 2.
target = playerPos;
  • 3.
target[0] == playerPos[0];
target[1] == playerPos[1];
  • 4.
target[0] = playerPos[0];
target[1] = playerPos[1];

question 5 (line84)

else if (ghostType[i] == 'b') { // 粉紅鬼:目標pacman位置4格前 /*question 5*/ }

目標:
找到粉紅鬼的目標位置(pacman位置前方4格)

  • 1.
target = playerPos + 4 dir[playerDir];
  • 2.
target[0] == playerPos[0] + dir[playerDir][0] * 4;
target[1] == playerPos[1] + dir[playerDir][1] * 4;
  • 3.
target[0] = playerPos[0] + dir[playerDir][0] * 4;
target[1] = playerPos[1] + dir[playerDir][1] * 4;
  • 4.
target[0] = playerPos[0] + 4 dir[playerDir][0];
target[1] = playerPos[1] + 4 dir[playerDir][1];

question 6 (line96)

int center[2]; center[0] = playerPos[0] + dir[playerDir][0] * 2; center[1] = playerPos[1] + dir[playerDir][1] * 2; /*question 6*/

目標:
找到淺藍鬼的目標位置(與紅色鬼對稱中心在pacman前方2格)

  • 1.
target[0] = center[0] * 2 - ghostPos[indexOfRed][0];
target[1] = center[1] * 2 - ghostPos[indexOfRed][1];
  • 2.
target[0] + ghostPos[indexOfRed][0] = center[0] * 2;
target[1] + ghostPos[indexOfRed][1] = center[1] * 2;
  • 3.
target = center * 2 - ghostPos[indexOfRed];
  • 4.
target[0] = center[0] - ghostPos[indexOfRed][0];
target[1] = center[1] - ghostPos[indexOfRed][1];

question 7 (line135)

if (ghostPos[i][0] == playerPos[0] && ghostPos[i][1] == playerPos[1]) { score += 200; // 吃掉鬼的得分 /*question 7*/ ghostDir[i] = 4; // 設置鬼的方向為停止 ghostType[i] = tolower(ghostType[i]); // 將鬼的類型改為小寫 }

目標:
鬼被吃掉之後應該做什麼?

  • 1.
checkCollideGhost(ghostPos, playerPos, ghostNum);
  • 2.
respawnGhost(grid, ghostPos[i], playerPos);
  • 3.
ghostPos[i][0] = 0;
ghostPos[i][1] = 0;
  • 4.
checkNotCollideWall(grid, ghostPos[i][0], ghostPos[i][1]);

question 8 (line194)

if (c == '0') { /*question 8*/ }

目標:
紀錄pacman的初始位置

  • 1.
playerPos[i] = '0';
playerPos[j] = '0';
  • 2.
playerPos = i,j;
  • 3.
playerPos[0] = '0';
playerPos[1] = '0';
  • 4.
playerPos[0] = i;
playerPos[1] = j;

question 9 (line205)

int x, y; do { x = rand() % HEIGHT; // 隨機列 y = rand() % WIDTH; // 隨機行 } while (/*question 9*/); initGrid[x][y] = '*'; // 放置能量球

目標:
確保能量球放置在原本是點數位置(.是點數,*是能量球)

  • 1.
initGrid[x][y] == '.'
  • 2.
initGrid[x][y] != '.'
  • 3.
initGrid[x][y] = '.'
  • 4.
initGrid[x][y] = .

question 10 (line224)

for (/*question 10-1*/) { // 設定點數網格的初始狀態 for (/*question 10-2*/) { char c = initGrid[i][j]; gridDisplay[i][j] = c; // 初始化顯示網格 if (c == '.' || c == '*') { pointsGrid[i][j] = c; // 設置點數網格 pointsCnt++; // 增加點數計數 } } }

目標:
如何設定全部點數網格的初始狀態

  • 1.
10-1: int i = 0; i < HEIGHT; i++
10-2: int j = 0; j < WIDTH; j++
  • 2.
10-1: int i = 0; i < HEIGHT; i+1
10-2: int j = 0; j < WIDTH; j+1
  • 3.
10-1: int i = 0; i <= HEIGHT; i++
10-2: int j = 0; j <= WIDTH; j++
  • 4.
10-1: int i = 0; i < HEIGHT; i+1
10-2: int j = i; j < WIDTH; j+1

大功告成

及時排名

刷新頁面以更新

你很厲害的話

點此看挑戰題
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

沒了

image
image