#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define B_SIZE 19
#define M_MOVE 400
#define S_COUNT 5000
#define H_SIZE 100000
//S_COUNTz
//H_SIZE=HAXI_SIZE哈希链表对棋局进行缓存,
char board[B_SIZE][B_SIZE];//棋盘暂时用字符串生成
int h[M_MOVE][2];//记录每一步
int count = 0;//记录步数
int cp = 1;//cp=current_player
int lx = -1;
int ly = -1;
int lc[B_SIZE][B_SIZE] = {0};
int end_flag = 0;//弃权次数,用于计算是否结束比赛
// 并查集初始化
int parent[B_SIZE * B_SIZE];
void u_find() {
for (int i = 0; i < B_SIZE * B_SIZE; i++)
{
parent[i] = i;
}
}
// 查找根节点
//路径压缩优化,提高查找效率
int find(int x)
{
if (parent[x] != x)
{
parent[x] = find(parent[x]);
}
return parent[x];
}
// 合并两个集合,处理围棋里面的连通块,即大龙**
void union_sets(int x, int y)
{
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY)
{
parent[rootX] = rootY;
}
}
//深度优先策略,搜索气
void dfs(int x, int y, char color, int visited[B_SIZE][B_SIZE], int *qi)
{
if (x < 0 || x >= B_SIZE || y < 0 || y >= B_SIZE)
{
return;
}
if (visited[x][y])
{
return;
}
if (board[x][y] == '.')
{
(*qi)++;
//更新气的数量
return;
}
if (board[x][y] != color)
{
return;
}
visited[x][y] = 1;
dfs(x + 1, y, color, visited, qi);
dfs(x - 1, y, color, visited, qi);
dfs(x, y - 1, color, visited, qi);
dfs(x, y + 1, color, visited, qi);
}
//记录气的数目
int qi[B_SIZE][B_SIZE];
//更新气的数目
void update_qi()
{
memset(qi, -1, sizeof(qi));
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (board[i][j] != '.')
{
int visited[B_SIZE][B_SIZE] = {0};
int qis = 0;
dfs(i, j, board[i][j], visited, &qis);
qi[i][j] = qis;
}
}
}
}
//初始化棋盘
void initialize()
{
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
board[i][j] = '.';
}
}
count = 0;
lx = -1;
ly = -1;
memset(lc, 0, sizeof(lc));
u_find();
update_qi();
end_flag = 0;
}
//显示棋盘
void show()
{
printf(" ");
for (int i = 0; i < B_SIZE; i++)
{
printf(" %c ", 'a' + i);
}
printf("\n");
for (int i = 0; i < B_SIZE; i++)
{
printf("%2d", i + 1);
for (int j = 0; j < B_SIZE; j++)
{
if (i == lx && j == ly)
{
printf("-%c-", board[i][j] == '*' ? '*' : board[i][j] == 'o' ? 'o' : '.');
} else
{
printf(" %c ", board[i][j]);
}
}
printf("\n");
}
}
//检测合法落子
int legal_move(int x, int y)
{
return x >= 0 && x < B_SIZE && y >= 0 && y < B_SIZE;
}
//提子
int capture_zi(int x, int y)
{
char opponent = (cp == 1)? 'o' : '*';
int captured = 0;
int visited[B_SIZE][B_SIZE] = {0};
int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
for (int i = 0; i < 4; i++)
{
int new_x = x + directions[i][0];
int new_y = y + directions[i][1];
if ( legal_move(new_x, new_y) && board[new_x][new_y] == opponent && !visited[new_x][new_y])
{
int liberties = 0;
dfs(new_x, new_y, opponent, visited, &liberties);
if (liberties == 0)
{
for (int j = 0; j < B_SIZE; j++)
{
for (int k = 0; k < B_SIZE; k++)
{
if (visited[j][k])
{
board[j][k] = '.';
captured++;
}
}
}
}
memset(visited, 0, sizeof(visited));
}
}
update_qi();
return captured;
}
//判断打劫
int is_ko(int x, int y)
{
if (count < 2)
{
return 0;
}
int captured = capture_zi(x, y);
if (captured!= 1) return 0;
int prev_x = h[count - 2][0];
int prev_y = h[count - 2][1];
int current[B_SIZE][B_SIZE] = {0};
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (board[i][j]!= lc[i][j])
{
current[i][j] = 1;
}
}
}
int single_capture = 0;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (current[i][j])
{
if (single_capture) return 0;
single_capture = 1;
}
}
}
if (single_capture && x == prev_x && y == prev_y) return 1;
return 0;
}
//落子
void move(int x, int y)
{
board[x][y] = cp == 1? '*' : 'o';
h[count][0] = x;
h[count][1] = y;
count++;
lx = x;
ly = y;
int captured = capture_zi(x, y);
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
lc[i][j] = board[i][j];
}
}
//检测落子的气
int self = 0;
int visited[B_SIZE][B_SIZE] = {0};
dfs(x, y, board[x][y], visited, &self);
if (self == 0)
{
board[x][y] = '.';
count--;
printf("wrong position,please change a correct position.\n");
return;
}
cp = 3 - cp;
update_qi();
end_flag = 0;
}
//保存棋局
void save(const char *filename)
{
FILE *file = fopen(filename, "w");
if (file == NULL)
{
printf("can't open file\n");
return;
}
for (int i = 0; i < count; i++)
{
fprintf(file, "%d %d\n", h[i][0], h[i][1]);
}
fclose(file);
}
//读取棋局
void load(const char *filename)
{
initialize();
FILE *file = fopen(filename, "r");
if (file == NULL)
{
printf("can't open file\n");
return;
}
int x, y;
while (fscanf(file, "%d %d", &x, &y) == 2) {
move(x, y);
}
fclose(file);
}
//复盘
void replay() {
initialize();
int a = 0;//记录当前步骤
char input;
while (1) {
show();//先展示棋盘
printf("N show the next situation, L show the next situation ,Q break.\n");
scanf(" %c", &input);
if (input == 'N' && a < count - 1)
{
a++;
move(h[a][0], h[a][1]);
} else if (input == 'L' && a > 0)
{
a--;
initialize();
for (int i = 0; i <= a; i++)
{
move(h[i][0], h[i][1]);
}
} else if (input == 'Q') {
break;
}
}
}
//数子
void m_count() {
int black = 0, white = 0;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (board[i][j] == '*')
{
black++;
} else if (board[i][j] == 'o')
{
white++;
}
}
}
printf("Black: %d, White: %d\n", black, white);
if (black > white)
{
printf("Black stones win!\n");
} else if (white > black)
{
printf("White stones win!\n");
} else
{
printf("It's a draw!\n");
}
}
// 检查是否结束比赛
int game_over()
{
if (end_flag >= 2)
{
printf("Both players have passed consecutively. Game over!\n");
m_count();
return 1;
}
return 0;
}
//节点定义,存储坐标
typedef struct wjt
{
int x, y;
int wins;
int visits;
struct wjt *next;
} wjt;
wjt *hash_table[H_SIZE];
// 简单的哈希函数,提高搜索决策效率
unsigned int hash(char board[B_SIZE][B_SIZE])
{
unsigned int hash_val = 0;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
hash_val = (hash_val * 31 + board[i][j]) % H_SIZE;
}
}
return hash_val;
}
// 在哈希表中查找节点
wjt *find_node(char board[B_SIZE][B_SIZE], int x, int y)
{
unsigned int hash_val = hash(board);
wjt *current = hash_table[hash_val];
while (current != NULL)
{
if (current->x == x && current->y == y)
{
return current;
}
current = current->next;
}
return NULL;
}
// 插入新节点到哈希表
void insert_node(char board[B_SIZE][B_SIZE], int x, int y)
{
unsigned int hash_val = hash(board);
wjt *new_node = (wjt *)malloc(sizeof(wjt));
new_node->x = x;
new_node->y = y;
new_node->wins = 0;
new_node->visits = 0;
new_node->next = hash_table[hash_val];
hash_table[hash_val] = new_node;
}
// 改进后的评估函数,考虑棋子的气和布局
int evaluate(char board[B_SIZE][B_SIZE], int cp)
{
int b_score = 0, w_score = 0;
int i, j;
for (i = 0; i < B_SIZE; i++)
{
for (j = 0; j < B_SIZE; j++)
{
if (board[i][j] == '*')
{
b_score += qi[i][j];
} else if (board[i][j] == 'o')
{
w_score += qi[i][j];
}
}
}
if (cp == 1)
{
return b_score - w_score;
} else {
return w_score - b_score;
}
}
// 蒙特卡罗模拟
int mct(char board[B_SIZE][B_SIZE], int cp)
{
char temp[B_SIZE][B_SIZE];
memcpy(temp, board, sizeof(temp));
int player = cp;
int end_flag = 0;
int local_count = 0;
int local_history[M_MOVE][2];
while (1)
{
int valid_flag = 0;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (legal_move(i, j))
{
local_history[local_count][0] = i;
local_history[local_count][1] = j;
local_count++;
temp[i][j] = player == 1? '*' : 'o';
int captured = 0;
// 模拟提子
char opponent = (player == 1)? 'o' : '*';
int visited[B_SIZE][B_SIZE] = {0};
int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
for (int k = 0; k < 4; k++)
{
int new_x = i + directions[k][0];
int new_y = j + directions[k][1];
if (new_x >= 0 && new_x < B_SIZE && new_y >= 0 && new_y < B_SIZE && temp[new_x][new_y] == opponent &&!visited[new_x][new_y])
{
int liberties = 0;
int temp_visited[B_SIZE][B_SIZE] = {0};
dfs(new_x, new_y, opponent, temp_visited, &liberties);
if (liberties == 0)
{
for (int m = 0; m < B_SIZE; m++)
{
for (int n = 0; n < B_SIZE; n++)
{
if (temp_visited[m][n])
{
temp[m][n] = '.';
captured++;
}
}
}
}
}
}
// 检测落子的气
int self = 0;
int self_visited[B_SIZE][B_SIZE] = {0};
dfs(i, j, temp[i][j], self_visited, &self);
if (self == 0)
{
temp[i][j] = '.';
local_count--;
} else
{
valid_flag = 1;
end_flag = 0;
break;
}
}
}
if (valid_flag) break;
}
if (!valid_flag)
{
end_flag++;
player = 3 - player;
if (end_flag >= 2)
{
break;
}
continue;
}
player = 3 - player;
}
int black = 0, white = 0;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (temp[i][j] == '*')
{
black++;
} else if (temp[i][j] == 'o')
{
white++;
}
}
}
if (cp == 1 && black > white)
{
return 1;
} else if (cp == 2 && white > black)
{
return 1;
}
return 0;
}
// 电脑落子函数
void computer_move(char board[B_SIZE][B_SIZE], int cp)
{
memset(hash_table, 0, sizeof(hash_table));
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
if (legal_move(i, j))
{
insert_node(board, i, j);
}
}
}
for (int k = 0; k < S_COUNT; k++)
{
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
wjt *node = find_node(board, i, j);
if (node != NULL)
{
char temp[B_SIZE][B_SIZE];
memcpy(temp, board, sizeof(temp));
temp[i][j] = cp == 1? '*' : 'o';
int result = mct(temp, cp);
node->visits++;
if (result == 1)
{
node->wins++;
}
}
}
}
}
int best_x = -1, best_y = -1;
double best_score = -1;
for (int i = 0; i < B_SIZE; i++)
{
for (int j = 0; j < B_SIZE; j++)
{
wjt *node = find_node(board, i, j);
if (node != NULL)
{
// 结合模拟结果和当前棋局评估来计算得分
double simulation_score = (double)node->wins / node->visits;
int evaluation_score = evaluate(board, cp);
double combined_score = simulation_score * 0.6 + evaluation_score * 0.4; // 可调整权重
if (combined_score > best_score)
{
best_score = combined_score;
best_x = i;
best_y = j;
}
}
}
}
if (best_x != -1 && best_y != -1)
{
move(best_x, best_y);
}
}
// 释放哈希表中所有节点的内存
void free_hash_table() {
for (int i = 0; i < H_SIZE; i++) {
wjt *current = hash_table[i];
wjt *next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
}
hash_table[i] = NULL;
}
}
int main(int argc, char *argv[])
{
int mode;
printf("-----------------------------------------------------------\n");
printf("-----------------------------------------------------------\n");
printf("-----------------------------------------------------------\n");
printf("------Game mode: 1. Two players 2. Human vs Computer------\n");
printf("-----------------------------------------------------------\n");
printf("-----------------------------------------------------------\n");
printf("-----------------------------------------------------------\n");
printf("Please select:");
scanf("%d", &mode);
initialize();
int x, y;
char col_str[2];
int row;
while (1)
{
show();
printf("Current player: %s\n", cp == 1 ? "Black" : "White");
if (mode == 2 && cp == 2)
{
//
computer_move(board, cp);
} else
{
char input[10];
printf("Please enter the move position (e.g., c12) or 'P' to pass: ");
scanf("%s", input);
if (strcmp(input, "P") == 0)
{
end_flag++;
cp = 3 - count;
if (game_over())
{
break;
}
continue;
}
sscanf(input, "%1s%d", col_str, &row);
x = row - 1;
y = col_str[0] - 'a';
if (legal_move(x, y))
{
if (is_ko(x, y))
{
printf("This move is a ko. It is prohibited. Please make a new move!\n");
continue;
}
move(x, y);
} else
{
printf("The move position is invalid. Please enter a new position!\n");
}
}
if (game_over())
{
break;
}
char c[10];
//存储指令
printf("Enter S to save the game, L to load the game, R to replay the game, other to continue: ");
scanf("%s", c);
if (strcmp(c, "S") == 0)
{
char file[100];
//文件名
printf("Please enter the file name to save: ");
scanf("%s", file);
save(file);
} else if (strcmp(c, "L") == 0)
{
char file[100];
printf("Please enter the file name to load: ");
scanf("%s", file);
load(file);
} else if (strcmp(c, "R") == 0)
{
replay();
}
}
free_hash_table();
return 0;
} 修改代码
最新发布