Оценочная функция (Evaluation)
Факторы оценки:
Победа/поражение:
+100000 за победу ИИ, -100000 за победу игрока.
Контроль клеток:
+3 за каждую фишку ИИ, -3 за фишку игрока.
Центральные клетки:
Бонус +15 за фишки в центре (чем ближе к центру, тем выше бонус).
Цепочки фишек:
+8 за каждую соседнюю фишку того же игрока.
Мобильность:
Бонус за количество возможных ходов (+5 за разницу в мобильности).
Угрозы:
Штраф -10 за фишки под угрозой захвата.
Формула: Оценка = Базовые_фишки + Центральные_бонусы + Цепочки + Мобильность - Угрозы
int Evaluation(TPlaying_Field* field) {
if (CheckWin(field, PLAYER2)) return 100000;
if (CheckWin(field, PLAYER1)) return -100000;
int score = 0;
const int CENTRAL_BONUS = 15;
const int CHAIN_BONUS = 8;
const int EDGE_BONUS = 12;
const int MOBILITY_BONUS = 5;
const int THREAT_BONUS = 10;
// Оценка мобильности (количество возможных ходов)
int playerMoves = GenerateMoves(field, PLAYER2).size();
int opponentMoves = GenerateMoves(field, PLAYER1).size();
score += (playerMoves - opponentMoves) * MOBILITY_BONUS;
// Оценка позиций и угроз
for (int i = 0; i < NUM_ROWS; ++i) {
for (int j = 0; j < NUM_COLS; ++j) {
if (field->board[i][j] == PLAYER2) {
score += 3; // Базовое значение фишки
// Бонус за центр (чем ближе к центру, тем больше бонус)
int centerDist = std::abs(i - NUM_ROWS / 2) + std::abs(j - NUM_COLS / 2);
score += (NUM_ROWS - centerDist) * CENTRAL_BONUS / NUM_ROWS;
// Бонус за приближение к правому краю (цель AI)
score += j * EDGE_BONUS / NUM_COLS;
// Бонус за соединения
int connections = 0;
for (const auto& dir : DIRECTIONS) {
int ni = i + dir[0];
int nj = j + dir[1];
if (IsInBounds(ni, nj) && field->board[ni][nj] == PLAYER2) {
connections++;
}
}
score += connections * CHAIN_BONUS;
// Бонус за потенциальные угрозы (фишки рядом с пустыми клетками)
for (const auto& dir : DIRECTIONS) {
int ni = i + dir[0];
int nj = j + dir[1];
if (IsInBounds(ni, nj)) {
if (field->board[ni][nj] == EMPTY) {
score += THREAT_BONUS / 2;
}
else if (field->board[ni][nj] == PLAYER1) {
score += THREAT_BONUS;
}
}
}
}
else if (field->board[i][j] == PLAYER1) {
score -= 3; // Базовое значение фишки противника
// Штраф за центр
int centerDist = std::abs(i - NUM_ROWS / 2) + std::abs(j - NUM_COLS / 2);
score -= (NUM_ROWS - centerDist) * CENTRAL_BONUS / NUM_ROWS;
// Штраф за приближение к нижнему краю (цель игрока)
score -= (NUM_ROWS - 1 - i) * EDGE_BONUS / NUM_ROWS;
// Штраф за соединения противника
int connections = 0;
for (const auto& dir : DIRECTIONS) {
int ni = i + dir[0];
int nj = j + dir[1];
if (IsInBounds(ni, nj) && field->board[ni][nj] == PLAYER1) {
connections++;
}
}
score -= connections * CHAIN_BONUS;
}
}
}
return score;
}
void CaptureOpponentPieces(int x, int y, CellState player, TPlaying_Field* field) {
for (const auto& dir : DIRECTIONS) {
int ni = x + dir[0];
int nj = y + dir[1];
if (IsInBounds(ni, nj) && field->board[ni][nj] != EMPTY &&
field->board[ni][nj] != player) {
field->board[ni][nj] = player;
}
}
}
bool CheckWin(TPlaying_Field* field, CellState player) {
bool visited[NUM_ROWS][NUM_COLS] = { false };
std::vector<std::pair<int, int>> stack;
if (player == PLAYER1) {
for (int j = 0; j < NUM_COLS; ++j) {
if (field->board[0][j] == PLAYER1) {
stack.push_back({ 0, j });
visited[0][j] = true;
}
}
}
else {
for (int i = 0; i < NUM_ROWS; ++i) {
if (field->board[i][0] == PLAYER2) {
stack.push_back({ i, 0 });
visited[i][0] = true;
}
}
}
while (!stack.empty()) {
auto current = stack.back();
stack.pop_back();
int i = current.first;
int j = current.second;
if ((player == PLAYER1 && i == NUM_ROWS - 1) ||
(player == PLAYER2 && j == NUM_COLS - 1)) {
return true;
}
for (const auto& dir : DIRECTIONS) {
int ni = i + dir[0];
int nj = j + dir[1];
if (IsInBounds(ni, nj) && field->board[ni][nj] == player && !visited[ni][nj]) {
visited[ni][nj] = true;
stack.push_back({ ni, nj });
}
}
}
return false;
}
