387 lines
12 KiB
C++
387 lines
12 KiB
C++
// 亚马逊棋(Amazons)蒙特卡洛AI程序 - 优化版
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <vector>
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
#include <random>
|
|
#include <chrono>
|
|
#include <queue>
|
|
#include <cstring> // 添加memset
|
|
|
|
#define GRIDSIZE 8
|
|
#define OBSTACLE 2
|
|
#define judge_black 0
|
|
#define judge_white 1
|
|
#define grid_black 1
|
|
#define grid_white -1
|
|
|
|
using namespace std;
|
|
|
|
// 均衡型参数配置
|
|
const double CONTROL_FACTOR = 1.0;
|
|
const double SAFETY_FACTOR = 1.0;
|
|
const double SURROUND_FACTOR = 10.0;
|
|
const double CENTER_FACTOR = 1.0;
|
|
|
|
// 蒙特卡洛参数 - 减少模拟次数提高速度
|
|
const int SIMULATIONS_PER_MOVE = 15; // 减少模拟次数
|
|
const int MAX_SIMULATION_STEPS = 5; // 减少模拟步数
|
|
const int MCTS_ITERATIONS = 50; // 减少迭代次数
|
|
|
|
// 预计算方向向量
|
|
const int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
|
|
const int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
|
|
|
|
int currBotColor;
|
|
int gridInfo[GRIDSIZE][GRIDSIZE] = { 0 };
|
|
|
|
// 随机数生成器
|
|
static mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
|
|
|
|
// 走法结构体 - 紧凑表示
|
|
struct Move {
|
|
unsigned char x0, y0, x1, y1, x2, y2;
|
|
|
|
Move(int x0=0, int y0=0, int x1=0, int y1=0, int x2=0, int y2=0)
|
|
: x0(x0), y0(y0), x1(x1), y1(y1), x2(x2), y2(y2) {}
|
|
|
|
bool isValid() const { return x0 != 255; }
|
|
};
|
|
|
|
// 移动缓存结构
|
|
struct MoveCache {
|
|
int pieceX, pieceY;
|
|
int moveCount;
|
|
int moves[56]; // 最大可能移动数:8个方向 * 7步 = 56
|
|
|
|
MoveCache() : pieceX(-1), pieceY(-1), moveCount(0) {
|
|
memset(moves, 0, sizeof(moves));
|
|
}
|
|
};
|
|
|
|
// 预计算中心距离
|
|
const double centerDistance[GRIDSIZE][GRIDSIZE] = {
|
|
{9.90, 8.96, 8.06, 7.28, 7.28, 8.06, 8.96, 9.90},
|
|
{8.96, 7.07, 6.10, 5.39, 5.39, 6.10, 7.07, 8.96},
|
|
{8.06, 6.10, 4.95, 4.03, 4.03, 4.95, 6.10, 8.06},
|
|
{7.28, 5.39, 4.03, 2.12, 2.12, 4.03, 5.39, 7.28},
|
|
{7.28, 5.39, 4.03, 2.12, 2.12, 4.03, 5.39, 7.28},
|
|
{8.06, 6.10, 4.95, 4.03, 4.03, 4.95, 6.10, 8.06},
|
|
{8.96, 7.07, 6.10, 5.39, 5.39, 6.10, 7.07, 8.96},
|
|
{9.90, 8.96, 8.06, 7.28, 7.28, 8.06, 8.96, 9.90}
|
|
};
|
|
|
|
// 全局移动列表缓存
|
|
vector<Move> allPossibleMoves;
|
|
vector<MoveCache> moveCache[2]; // 0:黑方, 1:白方
|
|
|
|
inline bool inMap(int x, int y) {
|
|
return (unsigned)x < GRIDSIZE && (unsigned)y < GRIDSIZE;
|
|
}
|
|
|
|
// 快速棋盘复制(使用memcpy)
|
|
inline void copyBoard(const int src[GRIDSIZE][GRIDSIZE], int dst[GRIDSIZE][GRIDSIZE]) {
|
|
memcpy(dst, src, sizeof(int) * GRIDSIZE * GRIDSIZE);
|
|
}
|
|
|
|
bool ProcStep(int x0, int y0, int x1, int y1, int x2, int y2, int color, bool check_only) {
|
|
if (!inMap(x0, y0) || !inMap(x1, y1) || !inMap(x2, y2))
|
|
return false;
|
|
if (gridInfo[x0][y0] != color || gridInfo[x1][y1] != 0)
|
|
return false;
|
|
if (gridInfo[x2][y2] != 0 && !(x2 == x0 && y2 == y0))
|
|
return false;
|
|
|
|
if (!check_only) {
|
|
gridInfo[x0][y0] = 0;
|
|
gridInfo[x1][y1] = color;
|
|
gridInfo[x2][y2] = OBSTACLE;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// 计算棋子的所有移动位置(优化版)
|
|
void calculateMovesFast(const int grid[GRIDSIZE][GRIDSIZE], int x, int y,
|
|
int moves[], int &count) {
|
|
count = 0;
|
|
int color = grid[x][y];
|
|
if (color == 0) return;
|
|
|
|
for (int d = 0; d < 8; ++d) {
|
|
for (int step = 1; step < GRIDSIZE; ++step) {
|
|
int xx = x + dx[d] * step;
|
|
int yy = y + dy[d] * step;
|
|
|
|
if (!inMap(xx, yy) || grid[xx][yy] != 0)
|
|
break;
|
|
|
|
moves[count++] = (xx << 3) | yy; // 使用位运算压缩坐标
|
|
}
|
|
}
|
|
}
|
|
|
|
// 预先计算所有棋子的移动
|
|
void precalculateMoves(const int grid[GRIDSIZE][GRIDSIZE], int color) {
|
|
int idx = (color == grid_black) ? 0 : 1;
|
|
moveCache[idx].clear();
|
|
|
|
for (int i = 0; i < GRIDSIZE; ++i) {
|
|
for (int j = 0; j < GRIDSIZE; ++j) {
|
|
if (grid[i][j] == color) {
|
|
MoveCache mc;
|
|
mc.pieceX = i;
|
|
mc.pieceY = j;
|
|
calculateMovesFast(grid, i, j, mc.moves, mc.moveCount);
|
|
if (mc.moveCount > 0) {
|
|
moveCache[idx].push_back(mc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取所有可能的走法(使用缓存)
|
|
vector<Move> getAllPossibleMovesFast(const int grid[GRIDSIZE][GRIDSIZE], int color) {
|
|
vector<Move> moves;
|
|
int idx = (color == grid_black) ? 0 : 1;
|
|
|
|
// 如果缓存未计算,先计算
|
|
if (moveCache[idx].empty()) {
|
|
precalculateMoves(grid, color);
|
|
}
|
|
|
|
// 临时棋盘用于计算箭的位置
|
|
int tempGrid[GRIDSIZE][GRIDSIZE];
|
|
|
|
for (const auto& piece : moveCache[idx]) {
|
|
for (int m = 0; m < piece.moveCount; ++m) {
|
|
int movePos = piece.moves[m];
|
|
int moveX = movePos >> 3;
|
|
int moveY = movePos & 7;
|
|
|
|
// 创建临时棋盘
|
|
copyBoard(grid, tempGrid);
|
|
tempGrid[moveX][moveY] = color;
|
|
tempGrid[piece.pieceX][piece.pieceY] = 0;
|
|
|
|
// 计算箭的位置
|
|
int arrowMoves[56];
|
|
int arrowCount = 0;
|
|
calculateMovesFast(tempGrid, moveX, moveY, arrowMoves, arrowCount);
|
|
|
|
for (int a = 0; a < arrowCount; ++a) {
|
|
int arrowPos = arrowMoves[a];
|
|
int arrowX = arrowPos >> 3;
|
|
int arrowY = arrowPos & 7;
|
|
moves.push_back(Move(piece.pieceX, piece.pieceY, moveX, moveY, arrowX, arrowY));
|
|
}
|
|
}
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
// 快速局面评估(简化版)
|
|
double evaluateBoardFast(const int grid[GRIDSIZE][GRIDSIZE], int originalColor) {
|
|
double score = 0.0;
|
|
|
|
// 快速评估:只计算移动能力和中心控制
|
|
for (int i = 0; i < GRIDSIZE; ++i) {
|
|
for (int j = 0; j < GRIDSIZE; ++j) {
|
|
int piece = grid[i][j];
|
|
if (piece != 0 && piece != OBSTACLE) {
|
|
// 中心控制
|
|
double centerValue = (10.0 - centerDistance[i][j]) * CENTER_FACTOR;
|
|
|
|
// 移动能力(简化计算)
|
|
int moves[56];
|
|
int moveCount = 0;
|
|
calculateMovesFast(grid, i, j, moves, moveCount);
|
|
double mobility = moveCount * CONTROL_FACTOR;
|
|
|
|
if (piece == originalColor) {
|
|
score += centerValue + mobility;
|
|
} else {
|
|
score -= centerValue + mobility;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 归一化
|
|
return tanh(score / 50.0);
|
|
}
|
|
|
|
// 优化的随机游戏模拟
|
|
double simulateRandomGameFast(Move move, const int originalGrid[GRIDSIZE][GRIDSIZE], int color) {
|
|
// 使用栈上数组,避免动态分配
|
|
int simGrid[GRIDSIZE][GRIDSIZE];
|
|
copyBoard(originalGrid, simGrid);
|
|
|
|
// 执行第一步
|
|
simGrid[move.x1][move.y1] = color;
|
|
simGrid[move.x0][move.y0] = 0;
|
|
simGrid[move.x2][move.y2] = OBSTACLE;
|
|
|
|
int currentColor = -color;
|
|
int steps = 0;
|
|
|
|
// 快速随机模拟
|
|
while (steps < MAX_SIMULATION_STEPS) {
|
|
// 获取当前玩家的移动
|
|
int moves[56];
|
|
int moveCount = 0;
|
|
bool hasMove = false;
|
|
|
|
// 找到一个可以移动的棋子
|
|
for (int i = 0; i < GRIDSIZE && !hasMove; ++i) {
|
|
for (int j = 0; j < GRIDSIZE && !hasMove; ++j) {
|
|
if (simGrid[i][j] == currentColor) {
|
|
calculateMovesFast(simGrid, i, j, moves, moveCount);
|
|
if (moveCount > 0) {
|
|
// 随机选择一个移动
|
|
int moveIdx = rng() % moveCount;
|
|
int movePos = moves[moveIdx];
|
|
int moveX = movePos >> 3;
|
|
int moveY = movePos & 7;
|
|
|
|
// 计算箭的位置
|
|
int arrowMoves[56];
|
|
int arrowCount = 0;
|
|
|
|
// 临时棋盘计算箭
|
|
int tempGrid[GRIDSIZE][GRIDSIZE];
|
|
copyBoard(simGrid, tempGrid);
|
|
tempGrid[moveX][moveY] = currentColor;
|
|
tempGrid[i][j] = 0;
|
|
calculateMovesFast(tempGrid, moveX, moveY, arrowMoves, arrowCount);
|
|
|
|
if (arrowCount > 0) {
|
|
int arrowIdx = rng() % arrowCount;
|
|
int arrowPos = arrowMoves[arrowIdx];
|
|
int arrowX = arrowPos >> 3;
|
|
int arrowY = arrowPos & 7;
|
|
|
|
// 执行移动
|
|
simGrid[moveX][moveY] = currentColor;
|
|
simGrid[i][j] = 0;
|
|
simGrid[arrowX][arrowY] = OBSTACLE;
|
|
hasMove = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasMove) break;
|
|
|
|
currentColor = -currentColor;
|
|
steps++;
|
|
}
|
|
|
|
return evaluateBoardFast(simGrid, color);
|
|
}
|
|
|
|
// 主决策函数
|
|
Move findBestMoveWithMonteCarlo() {
|
|
// 清空缓存
|
|
moveCache[0].clear();
|
|
moveCache[1].clear();
|
|
|
|
// 获取所有可能走法
|
|
vector<Move> moves = getAllPossibleMovesFast(gridInfo, currBotColor);
|
|
|
|
if (moves.empty()) {
|
|
return Move(255, 255, 255, 255, 255, 255);
|
|
}
|
|
|
|
// 如果走法很少,直接返回第一个
|
|
if (moves.size() == 1) {
|
|
return moves[0];
|
|
}
|
|
|
|
Move bestMove = moves[0];
|
|
double bestScore = -1e9;
|
|
|
|
// 限制检查的走法数量
|
|
int checkCount = min((int)moves.size(), 30);
|
|
|
|
// 均匀采样,而不是检查所有走法
|
|
vector<int> indices(moves.size());
|
|
for (int i = 0; i < moves.size(); ++i) indices[i] = i;
|
|
shuffle(indices.begin(), indices.end(), rng);
|
|
|
|
for (int i = 0; i < checkCount; ++i) {
|
|
int idx = indices[i];
|
|
double totalScore = 0.0;
|
|
|
|
// 减少模拟次数
|
|
int sims = (i < 10) ? SIMULATIONS_PER_MOVE : (SIMULATIONS_PER_MOVE / 2);
|
|
|
|
for (int sim = 0; sim < sims; ++sim) {
|
|
totalScore += simulateRandomGameFast(moves[idx], gridInfo, currBotColor);
|
|
}
|
|
|
|
double avgScore = totalScore / sims;
|
|
|
|
if (avgScore > bestScore) {
|
|
bestScore = avgScore;
|
|
bestMove = moves[idx];
|
|
}
|
|
}
|
|
|
|
return bestMove;
|
|
}
|
|
|
|
int main() {
|
|
ios::sync_with_stdio(false);
|
|
cin.tie(0);
|
|
|
|
// 快速初始化棋盘
|
|
memset(gridInfo, 0, sizeof(gridInfo));
|
|
gridInfo[0][2] = gridInfo[2][0] = gridInfo[5][0] = gridInfo[7][2] = grid_black;
|
|
gridInfo[0][5] = gridInfo[2][7] = gridInfo[5][7] = gridInfo[7][5] = grid_white;
|
|
|
|
int turnID;
|
|
cin >> turnID;
|
|
|
|
currBotColor = grid_white;
|
|
for (int i = 0; i < turnID; i++) {
|
|
int x0, y0, x1, y1, x2, y2;
|
|
cin >> x0 >> y0 >> x1 >> y1 >> x2 >> y2;
|
|
|
|
if (x0 == -1) {
|
|
currBotColor = grid_black;
|
|
} else if (x0 >= 0) {
|
|
ProcStep(x0, y0, x1, y1, x2, y2, -currBotColor, false);
|
|
}
|
|
|
|
if (i < turnID - 1) {
|
|
cin >> x0 >> y0 >> x1 >> y1 >> x2 >> y2;
|
|
if (x0 >= 0) {
|
|
ProcStep(x0, y0, x1, y1, x2, y2, currBotColor, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 决策
|
|
Move bestMove = findBestMoveWithMonteCarlo();
|
|
|
|
// 如果无效,使用简单策略
|
|
if (!bestMove.isValid()) {
|
|
// 简单策略:找到第一个合法走法
|
|
vector<Move> moves = getAllPossibleMovesFast(gridInfo, currBotColor);
|
|
if (!moves.empty()) {
|
|
bestMove = moves[0];
|
|
}
|
|
}
|
|
|
|
cout << (int)bestMove.x0 << ' ' << (int)bestMove.y0 << ' '
|
|
<< (int)bestMove.x1 << ' ' << (int)bestMove.y1 << ' '
|
|
<< (int)bestMove.x2 << ' ' << (int)bestMove.y2 << endl;
|
|
|
|
return 0;
|
|
} |