Files
Gobang-Game/ai.c
T
2025-06-30 22:27:15 +08:00

325 lines
10 KiB
C

#include "ai.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
extern int BOARD_SIZE;
extern int board[MAX_BOARD_SIZE][MAX_BOARD_SIZE];
extern int step_count;
extern const int direction[4][2];
extern Step steps[MAX_STEPS];
/**
* @brief ?????????????????????????
* ??????????????????????????????????????????????????
* ????????????????????????????????
* @param x ????????????? (0-based)??
* @param y ????????????? (0-based)??
* @param player ????? (PLAYER ?? AI)??????????????????????
* @return int ???????????????????????
* @note ??????????
* - ??????????????????????M???????????????????????????
* - ?????????????????\????????????????????\????????????????????\?????????
* ?????????????????????
* - ?????? (??????????????????AI???):
* - ????: 1,000,000 (???)
* - ????: 100,000 (????????)
* - ????: 10,000 (????????????)
* - ????: 5,000 (??????)
* - ????: 1,000
* - ???: 500
* - ???: 100
* - ????: ????????
* - ?????????????????????????????????????????????????????????AI????????
*/
int evaluate_pos(int x, int y, int player)
{
// ?????????????
int original = board[x][y];
// ??????????????
board[x][y] = player;
int total_score = 0; // ???
int line_scores[4] = {0}; // ???????????
// ??????????????????
for (int i = 0; i < 4; i++)
{
int dx = direction[i][0], dy = direction[i][1];
// ????????????????????
DirInfo info = count_specific_direction(x, y, dx, dy, player);
// ?????????????????
if (info.continuous_chess >= 5)
{
board[x][y] = original; // ???????
return 1000000; // ????????
}
// ??????????????????
switch (info.continuous_chess)
{
case 4: // ??????
if (info.check_start && info.check_end) // ????(???????)
line_scores[i] = 100000;
else if (info.check_start || info.check_end) // ????(??????)
line_scores[i] = 10000;
else // ????(??????)
line_scores[i] = 500;
break;
case 3: // ??????
if (info.check_start && info.check_end) // ????
line_scores[i] = 5000;
else if (info.check_start || info.check_end) // ????
line_scores[i] = 1000;
else // ????
line_scores[i] = 50;
break;
case 2: // ??????
if (info.check_start && info.check_end) // ???
line_scores[i] = 500;
else if (info.check_start || info.check_end) // ???
line_scores[i] = 100;
else // ????
line_scores[i] = 10;
break;
case 1: // ????
if (info.check_start && info.check_end) // ????????
line_scores[i] = 50;
else if (info.check_start || info.check_end) // ????????
line_scores[i] = 10;
else // ???????
line_scores[i] = 1;
break;
}
}
// ???????????????+?????????????
int max_score = 0;
int sum_score = 0;
for (int i = 0; i < 4; i++)
{
if (line_scores[i] > max_score)
max_score = line_scores[i];
sum_score += line_scores[i];
}
total_score = max_score * 10 + sum_score; // ????????????
// ????????????????????????
int center_x = BOARD_SIZE / 2;
int center_y = BOARD_SIZE / 2;
int distance = abs(x - center_x) + abs(y - center_y); // ?????????
int position_bonus = 50 * (BOARD_SIZE - distance); // ??????????????????
board[x][y] = original; // ?????????
return total_score + position_bonus; // ????????????
}
/**
* @brief ??????-???????????????????Minimax?????????????????
* ??????????????????????????????????????????????????????
* @param x ????????????????
* @param y ????????????????
* @param player ??????????? (PLAYER ?? AI)??
* @param depth ??????????????????AI????????????????????
* @param alpha ?????????????AI?????????????????????????
* @param beta ???????????????????????????????????????????
* @param is_maximizing ???????true???????????????AI???????false????????????????????????
* @return int ???????????????????????????
* @note ?????????:
* 1. **??????????**: ?????????????????????????????????????????????????????????????????
* 2. **??????? (AI)**: ??????????????????????????????????????????????????????????alpha???
* 3. **????????? (????)**: ????????????????????????????AI???????????????????????????????????beta???
* 4. **??-????**: ?????Minimax???????????
* - **?????**: ????????????????????????????????????????alpha?????????????????????????
* ??????????????????????????????????????????(if beta <= alpha)
* - **????**: ??????????ah?????????????????????????????beta??????????????????????????
* ???????????????????????????????????????????????????????(if beta <= alpha)
* ????????????????????????????????????????????AI??????????
*/
int dfs(int x, int y, int player, int depth, int alpha, int beta, bool is_maximizing)
{
// ???n??????????
if (check_win(x, y, player))
{
return (player == AI) ? 1000000 + depth : -1000000 - depth;
}
// ?????????????
if (depth == 0 || step_count >= BOARD_SIZE * BOARD_SIZE)
{
return evaluate_pos(x, y, AI) - evaluate_pos(x, y, PLAYER);
}
int best_score = is_maximizing ? -1000000 : 1000000;
// ????????????????????
for (int i = 0; i < BOARD_SIZE; i++)
{
for (int j = 0; j < BOARD_SIZE; j++)
{
if (board[i][j] != EMPTY)
continue;
// ???????????
board[i][j] = player;
step_count++;
// ???????(???????????????)
int current_score = dfs(i, j, (player == AI) ? PLAYER : AI, depth - 1, alpha, beta, !is_maximizing);
// ????????
board[i][j] = EMPTY;
step_count--;
// ????????(AI)???
if (is_maximizing)
{
best_score = (current_score > best_score) ? current_score : best_score;
alpha = (best_score > alpha) ? best_score : alpha;
// ?????
if (beta <= alpha)
{
break;
}
}
// ????????(????)???
else
{
best_score = (current_score < best_score) ? current_score : best_score;
beta = (best_score < beta) ? best_score : beta;
// ????
if (beta <= alpha)
{
break;
}
}
}
if ((is_maximizing && best_score >= beta) || (!is_maximizing && best_score <= alpha))
{
break; // ????????????
}
}
return best_score;
}
/**
* @brief AI?????????????????????????????????????????????
* @note ??????????????????
* 1. ????????????????????????????????????????????????
* 2. ???????????????????????????DFS?????????????????
* @note ???????
* - ??????????????????????????
* - ????>10??????????????????????????2??
* - ??????????????????
*/
void ai_move(int depth)
{
// 1. ???????????????????????????????????
for (int i = 0; i < BOARD_SIZE; i++)
{
for (int j = 0; j < BOARD_SIZE; j++)
{
if (board[i][j] != EMPTY)
continue;
// ?????????????????
board[i][j] = PLAYER;
bool need_block = false;
// ??????????
for (int k = 0; k < 4; k++)
{
DirInfo info = count_specific_direction(i, j, direction[k][0], direction[k][1], PLAYER);
// ????????????????????????????????
if (info.continuous_chess >= 4 && (info.check_start || info.check_end))
{
need_block = true;
break;
}
// ????????????????????????????
if (info.continuous_chess == 3 && info.check_start && info.check_end)
{
need_block = true;
break;
}
}
board[i][j] = EMPTY; // ???????
if (need_block)
{
// ??????????????????
board[i][j] = AI;
steps[step_count++] = (Step){AI, i, j};
printf("AI????(%d, %d)\n", i + 1, j + 1);
return;
}
}
}
// 2. ?????????????????????????????????
int best_score = -1000000;
int best_x = -1, best_y = -1;
// ????????????????
for (int i = 0; i < BOARD_SIZE; i++)
{
for (int j = 0; j < BOARD_SIZE; j++)
{
if (board[i][j] != EMPTY)
continue;
// ????????????????(2??????)
bool has_nearby_stone = false;
for (int di = -2; di <= 2; di++)
{
for (int dj = -2; dj <= 2; dj++)
{
int ni = i + di;
int nj = j + dj;
if (ni >= 0 && ni < BOARD_SIZE &&
nj >= 0 && nj < BOARD_SIZE)
{
if (board[ni][nj] != EMPTY)
{
has_nearby_stone = true;
break;
}
}
}
if (has_nearby_stone)
break;
}
if (!has_nearby_stone && step_count > 10)
continue;
// ???AI????
board[i][j] = AI;
int current_score = dfs(i, j, PLAYER, depth, -1000000, 1000000, false);
board[i][j] = EMPTY;
// ???????????
if (current_score > best_score)
{
best_score = current_score;
best_x = i;
best_y = j;
}
}
}
// ??????????
if (best_x != -1 && best_y != -1)
{
board[best_x][best_y] = AI;
steps[step_count++] = (Step){AI, best_x, best_y};
printf("AI????(%d, %d)\n", best_x + 1, best_y + 1);
}
}