首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言實作「Color Lines」經典益智遊戲完整原始碼解析

     編輯:關於C語言

遊戲規則速覽

  • 9×9 棋盤,每回合生成 3 顆隨機顏色(7 色)棋子。
  • 玩家點選一顆棋子,再點選目標空格,若存在路徑(上下左右連通空格)則移動成功。
  • 移動後若同色棋子在橫、直、斜任一方向連線 ≥ 5 顆,消除並得 10 分,該回合不生成新棋子。
  • 棋盤填滿遊戲結束。

核心資料結構

#define BOARD_SIZE 9
#define COLOR_MAX  7

char chesscolor[BOARD_SIZE][BOARD_SIZE];  // 0=空格, 1~7=顏色
char chessboard[BOARD_SIZE][BOARD_SIZE];  // 0=有棋子, 1=可通行空格
long grade = 0;                           // 分數

雙陣列分離「顏色屬性」與「連通性狀態」,便於路徑搜尋與消除判斷獨立演化。

關鍵演算法詳細解析

1. 棋盤滿檢查 boardfull()

int boardfull(void) {
    for (int i = 0; i < 9; ++i)
        for (int t = 0; t < 9; ++t)
            if (chessboard[i][t] == 1) return 0;  // 仍有空格
    return 1;
}

O(81) 掃描,極輕量。

2. 隨機生成棋子 buildchess()

void buildchess(void) {
    int x, y;
    do {
        x = rand() % 9;
        y = rand() % 9;
    } while (chesscolor[y][x] != 0);  // 找空格
    chesscolor[y][x] = rand() % 7 + 1;
    chessboard[y][x] = 0;
    delchess(y, x);  // 立即檢查是否形成連線(極罕見)
}

注意:rand()%9 有模數偏差,嚴謹專案應用 arc4random_uniform(9) 或自製拒絕採樣。

3. 路徑尋找 canmove() — DFS 遞迴

int canmove(int x, int y, int tx, int ty) {
    if (x == tx && y == ty) return 1;
    chessboard[x][y] = 0;  // 標記已訪問
    // 四方向嘗試
    if (x < 8 && chessboard[x+1][y] && canmove(x+1, y, tx, ty)) { chessboard[x][y]=1; return 1; }
    if (x > 0 && chessboard[x-1][y] && canmove(x-1, y, tx, ty)) { chessboard[x][y]=1; return 1; }
    if (y < 8 && chessboard[x][y+1] && canmove(x, y+1, tx, ty)) { chessboard[x][y]=1; return 1; }
    if (y > 0 && chessboard[x][y-1] && canmove(x, y-1, tx, ty)) { chessboard[x][y]=1; return 1; }
    chessboard[x][y] = 1;  // 回溯恢復
    return 0;
}

利用 chessboard 做訪問標記(0=已訪/不可通行,1=可通行),避免額外 visited 陣列。9×9 格最大遞迴深度 81,堆疊安全。

4. 消除判斷 delchess() — 四方向掃描

對新落子座標 (x,y),分別向雙向掃描四條線(垂直、水平、主對角、副對角),統計同色連續數 sum。若 5(含自身共 5 顆以上),將該線上所有同色棋子清空(chesscolor=0, chessboard=1),返回 1 觸發加分。
關鍵細節:掃描條件 chesscolor[x][y] != chesscolor[i][j] 以首顆顏色為基準,確保只消除同色連線。

5. 移動邏輯 movechess() — 滑鼠事件迴圈

  • scare_mouse()/unscare_mouse():繪圖前隱藏滑鼠游標,防止殘影(DOS 圖形庫慣用技巧)。
  • 座標轉換:螢幕像素 → 棋盤索引 (mouse-20)/40,邊界檢查 <=20 || >=380。
  • 雙擊流程:第一擊選棋子(畫紅框提示),第二擊選目標,驗證 canmove 後交換 chessboard/chesscolor,檢查消除。

圖形繪製模組(依賴 neo.h 圖形庫)

函式功能關鍵參數
drawboard()繪製網格線 + 所有棋子圓形hline/vline 畫線, circlefill 實心圓
circlefill(x,y,r,color)畫棋子中心 (col*40+40, row*40+40), 半徑 12
rect()選中棋子紅框左上/右下座標
neo_printf()顯示分數座標 (0,0) 字串格式

主流程 main()

int main(void) {
    neo_init();                    // 圖形庫初始化
    set_video_mode(640,480,8,0,0); // 640×480 256 色
    install_keyboard(); _install_timer(); change_timer(500);
    install_mouse(); srand(100);
    memset(chessboard, 1, sizeof(chessboard)); // 全部標記為空格
    for (int i=0; i<3; ++i) buildchess();      // 初始 3 顆
    while (!boardfull()) {
        movechess();             // 玩家移動
        for (int i=0; i<3; ++i)  // 移動後生成 3 顆
            if (!boardfull()) buildchess();
    }
    // 遊戲結束顯示分數
    scare_mouse(); drawboard();
    neo_printf(0,0, "遊戲結束,最終得分:%ld", grade);
    _getch(); return 0;
}

現代化移植建議

原組件現代替代遷移要點
neo.h / DOS 圖形SDL2 / SFML / Raylib將繪圖呼叫封裝為 Renderer 介面
滑鼠輪詢 get_click_info()事件迴圈 SDL_PollEvent按鍵按下/釋放分離邏輯
rand()std::mt19937 / random_device均勻分布 uniform_int_distribution(0,8)
全域變數GameState 結構體 + 單例/依賴注入便於單元測試、存檔/讀檔
遞迴 DFSBFS 隊列 / A* 启發式大棋盤時避免堆疊溢位

擴充玩法創意

  1. 撤銷功能:每步儲存 chesscolor 快照(81 bytes),支援多步回溯。
  2. 提示系統:預測下一步最佳移動(評估函數:潛在消除數 × 權重 - 路徑長度)。
  3. 特殊棋子:萬用色、炸彈、凍結格,豐富策略深度。
  4. 網路對戰:序列化移動指令,配合 WebSocket 即時同步。

總結

此程式雖基於 DOS 時代圖形庫,但完整展示了:狀態分離、DFS 路徑搜尋、多方向掃描消除、事件驅動主迴圈 等遊戲核心架構。代碼結構清晰,模組化程度高,是從「控制台小程式」邁向「圖形互動遊戲」的優秀教學案例。建議讀者嘗試移植至現代框架,並在保持核心邏輯不變的前提下重構架構,體會「業務邏輯與渲染分離」的工程智慧。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved