C++五子棋(四)——走棋原理及權值計算
阿新 • • 發佈:2021-07-07
原理
計算
- 計算每個落子點的“權值”,找到權值最大的落子點
- 對於每個空白點,分別計算周圍的八個方向
- 不妨以該空白點作為參照原點,以水平向右作為X軸正方向,以豎直向下為Y軸正方向建立平面直角座標系
- 因為在計算某個方向時,正向和反向需同時考慮,實際上只需要四個方向,即向量(1,0)的方向、向量(1,1)方向、向量(0,1)方向和向量(-1,1)方向,圖示如下(靈魂畫圖,請勿吐槽
滑稽)
走棋原理
產生效果
- 黑棋走這個點
產生效果 | 評分 |
---|---|
連2 | 10 |
死3 | 30 |
活3 | 40 |
死4 | 60 |
活4 | 200 |
連5 | 20000 |
- 如果白棋(AI)走這個點
產生效果 | 評分 |
---|---|
連1 | 5 |
連2 | 10 |
死3 | 25 |
活3 | 50 |
死4 | 55 |
活4 | 300 |
連5 | 30000 |
權值計算
- chessData.h
void calcScore(ChessData* data);
- chessData.cpp
#include <string>
void calcScore(ChessData* data){ if(!data) return; //統計玩家或AI連子 int personNum = 0; //玩家 int botNum = 0; //AI int emptyNum = 0; //各方向空白位數 //清空評分陣列 memset(data->scoreMap, 0, sizeof(data->scoreMap)); for (int row = 0; row < BOARD_GRAD_SIZE; row++){ for(int col = 0; col < BOARD_GRAD_SIZE; col++){ //空白點計算 if(row >= 0 && col >= 0 && data->chessMap[row][col] == 0){ //遍歷四個方向,然後分別計算正反四個方向 int directs[4][2] = {{1,0}, {1,1}, {0,1}, {-1,1}}; for(int k = 0; k < 4; k++){ int x = directs[k][0]; int y = directs[k][1]; //重置 personNum = 0; botNum = 0; emptyNum = 0; //對黑棋評分(正向) for(int i = 1; i <= 4; i++){ if(row + i * y >= 0 && row + i * y < BOARD_GRAD_SIZE && col + i * x >= 0 && col + i * x < BOARD_GRAD_SIZE && data->chessMap[row + i * y][col + i * x] == 1){ //玩家的子 personNum++; }else if(row + i * y >= 0 && row + i * y < BOARD_GRAD_SIZE && col + i * x >= 0 && col + i * x < BOARD_GRAD_SIZE && data->chessMap[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 < BOARD_GRAD_SIZE && col - i * x >= 0 && col - i * x <BOARD_GRAD_SIZE && data->chessMap[row - i * y][col - i * x] == 1){ personNum++; }else if(row - i * y >= 0 && row - i * y <BOARD_GRAD_SIZE && col - i * x >= 0 && col - i * x < BOARD_GRAD_SIZE && data->chessMap[row -i * y][col - i * x] == 0){ emptyNum++; break; }else{ break; } } if(personNum == 1){ data->scoreMap[row][col] += 10; }else if(personNum == 2){ if(emptyNum == 1){ //死3 data->scoreMap[row][col] += 30; }else if(emptyNum == 2){ //活3 data->scoreMap[row][col] += 40; } }else if(personNum == 3){ if(empty == 1){ //死4 data->scoreMap[row][col] += 60; }else if (emptyNum == 2){ //活4 data->scoreMap[row][col] += 200; } }else if(personNum == 4){ data->scoreMap[row][col] += 20000; } emptyNum = 0; //清空 //對白棋評分(正向) for(int i = 1; i <= 4; i++){ if(row + i * y > 0 && row + i * y < BOARD_GRAD_SIZE && col + i * x > 0 && col + i * x < BOARD_GARD_SIZE && data->chessMap[row + i * y][col + i * x == -1]){ botNum++; }else if(row + i * y >0 && row + i * y < BOARD_GRAD_SIZE && col + i * x > 0 && col + i * x < BOARD_GRAD_SIZE && data->chessMap[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 <BOARD_GRAD_SIZE && col - i * x > 0 && col - i * x < BOARD_GRAD_SIZE && data->chessMap[row - i * y][col -i * x] == -1){ botNum++; }else if (row - i * y >0 && row - i * y < BOARD_GRAD_SIZE && col - i * x > 0 && col - i * x < BOARD_GRAD_SIZE && data->chessMap[row - i * y][col - i * x] == 0){ emptyNum++; break; }else{ break; //出邊界 } } if(botNum == 0){ //連1 data->scoreMap[row][col] += 5; }else if(botNum == 1){ //活2 data->scoreMap[row][col] += 10; }else if(botNum == 2){ if(emptyNum == 1){ //死3 data->scoreMap[row][col] += 25; }else if(emptyNum == 2){ //活3 data->scoreMap[row][col] += 50; } }else if(botNum == 3){ if(emptyNum == 1){ //死4 data->scoreMap[row][col] += 55; }else if(botNum == 2){ //活4 data->scoreMap[row][col] += 300; } }else if(botNum >= 4){ //活5 data->scoreMap[row][col] += 30000; } } } } } }