最大值最小值在象棋运用的很多,也是最基础的走棋算法:首先根据基础局面计算各个走棋的局面分,假如说电脑要计算三层,那么如图:
总之就是要在所有走法中瘸子里面挑将军的意思:电脑想自己得分最高,电脑假设人下棋的时候要推断出最优的走法也就是得分最高的走法,那么人就会选择电脑走法得分最高的走法,然后人从这些走法中挑选出分值最小的走法给电脑,电脑又想从人给的这些走法中挑出值最大的哪一个,所以这就是最小值最大值算法
下面是C++版本的AI走棋算法:
Step& AI::getStep(GameScene& game,int level) {
this->step = NULL;
this->level = level;
//game.chessBoard->pieces.at(1)->col;
// 从所有最小值中获得最大值
this->getMaxScore(&game,level);
return *this->step;
}
// 获得所有可能移动的移动方案
Vector<Step*> AI::getAllSteps(GameScene& game) {
Vector<Step*> stepArr;
time_t start, end;
double cost;
time(&start);
int start = 0;
if (game.selfType) {
start = 16;
}
else {
start = 0;
}
for (int i = start; i < start + 16; i++) {
Piece* piece = game.chessBoard->pieces.at(i);
// 死去的棋子没有办法吃棋走棋逻辑
if (!piece->isDead) {
for (int row = 0; row < 10; row++) {
for (int col = 0; col < 9; col++) {
int killId = game.chessBoard->getPieceIdByRowAndCol(row, col);
if (piece->row == row && piece->col == col) {
continue;
}
if (killId == -1 && game.chessBoard->dealRealWar(piece->id, killId, piece->row, piece->col, row, col)) {
// 创建一个step
Step* step = Step::create(piece->id, piece->row, piece->col, row, col, killId);
stepArr.pushBack(step);
}
else if (killId != -1 && game.chessBoard->dealWar(piece->id, killId)) {
// 棋子类型相同的时候不允许加入到走棋数组中去
if (game.chessBoard->pieces.at(killId)->type != game.chessBoard->pieces.at(piece->id)->type) {
// 创建一个step
Step* step = Step::create(piece->id, piece->row, piece->col, row, col, killId);
stepArr.pushBack(step);
}
}
}
}
}
}
time(&end);
cost = difftime(end,start);
return stepArr;
}
// 获得局面分最大的分数
int AI::getMaxScore(GameScene* game, int level) {
if (level == 0) {
return this->calScore(game);
}
Vector<Step*> allMoves = this->getAllSteps(*game);
int topScore = -30000323;
// 遍历每一种走法
for (int i = 0; i < allMoves.size(); i++) {
Step* moveItem = allMoves.at(i);
// 走棋试探
this->fakeMove(game, moveItem);
// 计算局面分
int score = this->getMinScore(game,level - 1);
if (score > topScore) {
topScore = score;
//currentStep = moveItem;
if (level == this->level) {
this->step = moveItem;
}
}
// 取消走棋试探
this->unFakeMove(game, moveItem);
}
return topScore;
}
// Ai获得对方子局面中最小的分值
int AI::getMinScore(GameScene* game, int level) {
if (level == 0) {
return this->calScore(game);
}
Vector<Step*> allMoves = this->getAllSteps(*game);
int minScore = 30000323;
// 遍历每一种走法
for (int i = 0; i < allMoves.size(); i++) {
Step* moveItem = allMoves.at(i);
// 走棋试探
this->fakeMove(game, moveItem);
// 计算局面分
int score = this->getMaxScore(game, level - 1);
if (score < minScore) {
minScore = score;
//currentStep = moveItem;
if (level == this->level) {
this->step = moveItem;
}
}
// 取消走棋试探
this->unFakeMove(game, moveItem);
}
return minScore;
}
// 计算得分
int AI::calScore(GameScene* game) {
// 每个棋子的评分
int gameScore[] = { 10,5,3,2,1000,2,3,5,10,5,5,1,1,1,1,1 };
// 己方得分
int bottomScore = 0;
// 敌方得分
int upScore = 0;
for (int i = 0; i < 16; i++) {
if (!game->chessBoard->pieces.at(i)->isDead) {
bottomScore += gameScore[i];
}
}
for (int j = 16; j < 32; j++) {
if (!game->chessBoard->pieces.at(j)->isDead) {
upScore += gameScore[(32 - j) - 1];
}
}
// 返回得分
return upScore - bottomScore;
}
// 试探性的走棋
void AI::fakeMove(GameScene* game,Step* step) {
/*Piece* pieceItem = game->chessBoard->pieces.at(step->sId);
pieceItem->row = step->toRow;
pieceItem->col = step->toCol;*/
game->movePiece(step->sId,step->toRow,step->toCol,step->killId);
}
// 取消试探走棋逻辑
void AI::unFakeMove(GameScene* game, Step* step) {
/*int row = step->fromRow;
int col = step->fromCol;
game->movePiece(step->sId, row, col, step->killId);*/
// 还原原来棋子的行和列
game->chessBoard->pieces.at(step->sId)->row = step->fromRow;
game->chessBoard->pieces.at(step->sId)->col = step->fromCol;
game->chessBoard->map[step->fromRow][step->fromCol] = 1;
if (step->killId != -1) {
game->chessBoard->map[step->toRow][step->toCol] = 1;
Piece* targetNode = game->chessBoard->pieces.at(step->killId);
targetNode->row = step->toRow;
targetNode->col = step->toCol;
// 目标棋子的死亡状态重置为false
targetNode->isDead = false;
}
else {
game->chessBoard->map[step->toRow][step->toCol] = 0;
}
game->redRun = !game->redRun;
}