Qt小遊戲開發:五子棋(帶AI功能)
阿新 • • 發佈:2019-01-27
void GameModel::actionByAI(int &clickRow, int &clickCol) { // 計算評分 calculateScore(); // 從評分中找出最大分數的位置 int maxScore = 0; std::vector<std::pair<int, int>> maxPoints; for (int row = 1; row < kBoardSizeNum; row++) for (int col = 1; col < kBoardSizeNum; col++) { // 前提是這個座標是空的 if (gameMapVec[row][col] == 0) { if (scoreMapVec[row][col] > maxScore) // 找最大的數和座標 { maxPoints.clear(); maxScore = scoreMapVec[row][col]; maxPoints.push_back(std::make_pair(row, col)); } else if (scoreMapVec[row][col] == maxScore) // 如果有多個最大的數,都存起來 maxPoints.push_back(std::make_pair(row, col)); } } // 隨機落子,如果有多個點的話 srand((unsigned)time(0)); int index = rand() % maxPoints.size(); std::pair<int, int> pointPair = maxPoints.at(index); clickRow = pointPair.first; // 記錄落子點 clickCol = pointPair.second; updateGameMap(clickRow, clickCol); } // 最關鍵的計算評分函式 void GameModel::calculateScore() { // 統計玩家或者電腦連成的子 int personNum = 0; // 玩家連成子的個數 int botNum = 0; // AI連成子的個數 int emptyNum = 0; // 各方向空白位的個數 // 清空評分陣列 scoreMapVec.clear(); for (int i = 0; i < kBoardSizeNum; i++) { std::vector<int> lineScores; for (int j = 0; j < kBoardSizeNum; j++) lineScores.push_back(0); scoreMapVec.push_back(lineScores); } // 計分(此處是完全遍歷,其實可以用bfs或者dfs加減枝降低複雜度,通過調整權重值,調整AI智慧程度以及攻守風格) for (int row = 0; row < kBoardSizeNum; row++) for (int col = 0; col < kBoardSizeNum; col++) { // 空白點就算 if (row > 0 && col > 0 && gameMapVec[row][col] == 0) { // 遍歷周圍八個方向 for (int y = -1; y <= 1; y++) for (int x = -1; x <= 1; x++) { // 重置 personNum = 0; botNum = 0; emptyNum = 0; // 原座標不算 if (!(y == 0 && x == 0)) { // 每個方向延伸4個子 // 對玩家白子評分(正反兩個方向) for (int i = 1; i <= 4; i++) { if (row + i * y > 0 && row + i * y < kBoardSizeNum && col + i * x > 0 && col + i * x < kBoardSizeNum && gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子 { personNum++; } else if (row + i * y > 0 && row + i * y < kBoardSizeNum && col + i * x > 0 && col + i * x < kBoardSizeNum && gameMapVec[row + i * y][col + i * x] == 0) // 空白位 { emptyNum++; break; } else // 出邊界 break; } for (int i = 1; i <= 4; i++) { if (row - i * y > 0 && row - i * y < kBoardSizeNum && col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == 1) // 玩家的子 { personNum++; } else if (row - i * y > 0 && row - i * y < kBoardSizeNum && col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == 0) // 空白位 { emptyNum++; break; } else // 出邊界 break; } if (personNum == 1) // 殺二 scoreMapVec[row][col] += 10; else if (personNum == 2) // 殺三 { if (emptyNum == 1) scoreMapVec[row][col] += 30; else if (emptyNum == 2) scoreMapVec[row][col] += 40; } else if (personNum == 3) // 殺四 { // 量變空位不一樣,優先順序不一樣 if (emptyNum == 1) scoreMapVec[row][col] += 60; else if (emptyNum == 2) scoreMapVec[row][col] += 110; } else if (personNum == 4) // 殺五 scoreMapVec[row][col] += 10100; // 進行一次清空 emptyNum = 0; // 對AI黑子評分 for (int i = 1; i <= 4; i++) { if (row + i * y > 0 && row + i * y < kBoardSizeNum && col + i * x > 0 && col + i * x < kBoardSizeNum && gameMapVec[row + i * y][col + i * x] == 1) // 玩家的子 { botNum++; } else if (row + i * y > 0 && row + i * y < kBoardSizeNum && col + i * x > 0 && col + i * x < kBoardSizeNum && gameMapVec[row +i * y][col + i * x] == 0) // 空白位 { emptyNum++; break; } else // 出邊界 break; } for (int i = 1; i <= 4; i++) { if (row - i * y > 0 && row - i * y < kBoardSizeNum && col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == -1) // AI的子 { botNum++; } else if (row - i * y > 0 && row - i * y < kBoardSizeNum && col - i * x > 0 && col - i * x < kBoardSizeNum && gameMapVec[row - i * y][col - i * x] == 0) // 空白位 { emptyNum++; break; } else // 出邊界 break; } if (botNum == 0) // 普通下子 scoreMapVec[row][col] += 5; else if (botNum == 1) // 活二 scoreMapVec[row][col] += 10; else if (botNum == 2) { if (emptyNum == 1) // 死三 scoreMapVec[row][col] += 25; else if (emptyNum == 2) scoreMapVec[row][col] += 50; // 活三 } else if (botNum == 3) { if (emptyNum == 1) // 死四 scoreMapVec[row][col] += 55; else if (emptyNum == 2) scoreMapVec[row][col] += 100; // 活四 } else if (botNum >= 4) scoreMapVec[row][col] += 10000; // 活五 } } } } }
3 遊戲介面類
用於繪圖,人機互動