Files
Home-of-CS/content/post/DEV_2025_12_16_16/oasa25.cpp
T

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;
}